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, false);
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:
1245 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1250 player->setModified(true);
1255 PlayerSAO *playersao = player->getPlayerSAO();
1259 SendInventory(playersao, true);
1262 case InventoryLocation::NODEMETA:
1265 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1267 m_env->getMap().dispatchEvent(&event);
1270 case InventoryLocation::DETACHED:
1272 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1276 sanity_check(false); // abort
1281 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1283 std::vector<session_t> clients = m_clients.getClientIDs();
1285 // Set the modified blocks unsent for all the clients
1286 for (const session_t client_id : clients) {
1287 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1288 client->SetBlocksNotSent(block);
1293 void Server::peerAdded(con::Peer *peer)
1295 verbosestream<<"Server::peerAdded(): peer->id="
1296 <<peer->id<<std::endl;
1298 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1301 void Server::deletingPeer(con::Peer *peer, bool timeout)
1303 verbosestream<<"Server::deletingPeer(): peer->id="
1304 <<peer->id<<", timeout="<<timeout<<std::endl;
1306 m_clients.event(peer->id, CSE_Disconnect);
1307 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1310 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1312 *retval = m_con->getPeerStat(peer_id,type);
1313 return *retval != -1;
1316 bool Server::getClientInfo(
1325 std::string* vers_string
1328 *state = m_clients.getClientState(peer_id);
1330 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1337 *uptime = client->uptime();
1338 *ser_vers = client->serialization_version;
1339 *prot_vers = client->net_proto_version;
1341 *major = client->getMajor();
1342 *minor = client->getMinor();
1343 *patch = client->getPatch();
1344 *vers_string = client->getPatch();
1351 void Server::handlePeerChanges()
1353 while(!m_peer_change_queue.empty())
1355 con::PeerChange c = m_peer_change_queue.front();
1356 m_peer_change_queue.pop();
1358 verbosestream<<"Server: Handling peer change: "
1359 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1364 case con::PEER_ADDED:
1365 m_clients.CreateClient(c.peer_id);
1368 case con::PEER_REMOVED:
1369 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1373 FATAL_ERROR("Invalid peer change event received!");
1379 void Server::printToConsoleOnly(const std::string &text)
1382 m_admin_chat->outgoing_queue.push_back(
1383 new ChatEventChat("", utf8_to_wide(text)));
1385 std::cout << text << std::endl;
1389 void Server::Send(NetworkPacket *pkt)
1391 Send(pkt->getPeerId(), pkt);
1394 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1396 m_clients.send(peer_id,
1397 clientCommandFactoryTable[pkt->getCommand()].channel,
1399 clientCommandFactoryTable[pkt->getCommand()].reliable);
1402 void Server::SendMovement(session_t peer_id)
1404 std::ostringstream os(std::ios_base::binary);
1406 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1408 pkt << g_settings->getFloat("movement_acceleration_default");
1409 pkt << g_settings->getFloat("movement_acceleration_air");
1410 pkt << g_settings->getFloat("movement_acceleration_fast");
1411 pkt << g_settings->getFloat("movement_speed_walk");
1412 pkt << g_settings->getFloat("movement_speed_crouch");
1413 pkt << g_settings->getFloat("movement_speed_fast");
1414 pkt << g_settings->getFloat("movement_speed_climb");
1415 pkt << g_settings->getFloat("movement_speed_jump");
1416 pkt << g_settings->getFloat("movement_liquid_fluidity");
1417 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1418 pkt << g_settings->getFloat("movement_liquid_sink");
1419 pkt << g_settings->getFloat("movement_gravity");
1424 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1426 if (playersao->isImmortal())
1429 session_t peer_id = playersao->getPeerID();
1430 bool is_alive = playersao->getHP() > 0;
1433 SendPlayerHP(peer_id);
1435 DiePlayer(peer_id, reason);
1438 void Server::SendHP(session_t peer_id, u16 hp)
1440 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1445 void Server::SendBreath(session_t peer_id, u16 breath)
1447 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1448 pkt << (u16) breath;
1452 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1453 const std::string &custom_reason, bool reconnect)
1455 assert(reason < SERVER_ACCESSDENIED_MAX);
1457 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1459 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1460 pkt << custom_reason;
1461 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1462 reason == SERVER_ACCESSDENIED_CRASH)
1463 pkt << custom_reason << (u8)reconnect;
1467 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1469 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1474 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1475 v3f camera_point_target)
1477 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1478 pkt << set_camera_point_target << camera_point_target;
1482 void Server::SendItemDef(session_t peer_id,
1483 IItemDefManager *itemdef, u16 protocol_version)
1485 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1489 u32 length of the next item
1490 zlib-compressed serialized ItemDefManager
1492 std::ostringstream tmp_os(std::ios::binary);
1493 itemdef->serialize(tmp_os, protocol_version);
1494 std::ostringstream tmp_os2(std::ios::binary);
1495 compressZlib(tmp_os.str(), tmp_os2);
1496 pkt.putLongString(tmp_os2.str());
1499 verbosestream << "Server: Sending item definitions to id(" << peer_id
1500 << "): size=" << pkt.getSize() << std::endl;
1505 void Server::SendNodeDef(session_t peer_id,
1506 const NodeDefManager *nodedef, u16 protocol_version)
1508 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1512 u32 length of the next item
1513 zlib-compressed serialized NodeDefManager
1515 std::ostringstream tmp_os(std::ios::binary);
1516 nodedef->serialize(tmp_os, protocol_version);
1517 std::ostringstream tmp_os2(std::ios::binary);
1518 compressZlib(tmp_os.str(), tmp_os2);
1520 pkt.putLongString(tmp_os2.str());
1523 verbosestream << "Server: Sending node definitions to id(" << peer_id
1524 << "): size=" << pkt.getSize() << std::endl;
1530 Non-static send methods
1533 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1535 RemotePlayer *player = sao->getPlayer();
1537 // Do not send new format to old clients
1538 incremental &= player->protocol_version >= 38;
1540 UpdateCrafting(player);
1546 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1548 std::ostringstream os(std::ios::binary);
1549 sao->getInventory()->serialize(os, incremental);
1550 sao->getInventory()->setModified(false);
1551 player->setModified(true);
1553 const std::string &s = os.str();
1554 pkt.putRawString(s.c_str(), s.size());
1558 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1560 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1562 u8 type = message.type;
1563 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1565 if (peer_id != PEER_ID_INEXISTENT) {
1566 RemotePlayer *player = m_env->getPlayer(peer_id);
1572 m_clients.sendToAll(&pkt);
1576 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1577 const std::string &formname)
1579 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1580 if (formspec.empty()){
1581 //the client should close the formspec
1582 //but make sure there wasn't another one open in meantime
1583 const auto it = m_formspec_state_data.find(peer_id);
1584 if (it != m_formspec_state_data.end() && it->second == formname) {
1585 m_formspec_state_data.erase(peer_id);
1587 pkt.putLongString("");
1589 m_formspec_state_data[peer_id] = formname;
1590 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1597 // Spawns a particle on peer with peer_id
1598 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1599 v3f pos, v3f velocity, v3f acceleration,
1600 float expirationtime, float size, bool collisiondetection,
1601 bool collision_removal, bool object_collision,
1602 bool vertical, const std::string &texture,
1603 const struct TileAnimationParams &animation, u8 glow)
1605 static thread_local const float radius =
1606 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1608 if (peer_id == PEER_ID_INEXISTENT) {
1609 std::vector<session_t> clients = m_clients.getClientIDs();
1611 for (const session_t client_id : clients) {
1612 RemotePlayer *player = m_env->getPlayer(client_id);
1616 PlayerSAO *sao = player->getPlayerSAO();
1620 // Do not send to distant clients
1621 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1624 SendSpawnParticle(client_id, player->protocol_version,
1625 pos, velocity, acceleration,
1626 expirationtime, size, collisiondetection, collision_removal,
1627 object_collision, vertical, texture, animation, glow);
1632 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1634 pkt << pos << velocity << acceleration << expirationtime
1635 << size << collisiondetection;
1636 pkt.putLongString(texture);
1638 pkt << collision_removal;
1639 // This is horrible but required (why are there two ways to serialize pkts?)
1640 std::ostringstream os(std::ios_base::binary);
1641 animation.serialize(os, protocol_version);
1642 pkt.putRawString(os.str());
1644 pkt << object_collision;
1649 // Adds a ParticleSpawner on peer with peer_id
1650 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1651 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1652 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1653 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1654 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1655 const struct TileAnimationParams &animation, u8 glow)
1657 if (peer_id == PEER_ID_INEXISTENT) {
1658 // This sucks and should be replaced:
1659 std::vector<session_t> clients = m_clients.getClientIDs();
1660 for (const session_t client_id : clients) {
1661 RemotePlayer *player = m_env->getPlayer(client_id);
1664 SendAddParticleSpawner(client_id, player->protocol_version,
1665 amount, spawntime, minpos, maxpos,
1666 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1667 minsize, maxsize, collisiondetection, collision_removal,
1668 object_collision, attached_id, vertical, texture, id,
1674 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1676 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1677 << minacc << maxacc << minexptime << maxexptime << minsize
1678 << maxsize << collisiondetection;
1680 pkt.putLongString(texture);
1682 pkt << id << vertical;
1683 pkt << collision_removal;
1685 // This is horrible but required
1686 std::ostringstream os(std::ios_base::binary);
1687 animation.serialize(os, protocol_version);
1688 pkt.putRawString(os.str());
1690 pkt << object_collision;
1695 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1697 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1699 // Ugly error in this packet
1702 if (peer_id != PEER_ID_INEXISTENT)
1705 m_clients.sendToAll(&pkt);
1709 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1711 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1713 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1714 << form->text << form->number << form->item << form->dir
1715 << form->align << form->offset << form->world_pos << form->size;
1720 void Server::SendHUDRemove(session_t peer_id, u32 id)
1722 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1727 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1729 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1730 pkt << id << (u8) stat;
1734 case HUD_STAT_SCALE:
1735 case HUD_STAT_ALIGN:
1736 case HUD_STAT_OFFSET:
1737 pkt << *(v2f *) value;
1741 pkt << *(std::string *) value;
1743 case HUD_STAT_WORLD_POS:
1744 pkt << *(v3f *) value;
1747 pkt << *(v2s32 *) value;
1749 case HUD_STAT_NUMBER:
1753 pkt << *(u32 *) value;
1760 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1762 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1764 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1766 pkt << flags << mask;
1771 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1773 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1774 pkt << param << value;
1778 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1779 const std::string &type, const std::vector<std::string> ¶ms,
1782 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1783 pkt << bgcolor << type << (u16) params.size();
1785 for (const std::string ¶m : params)
1793 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1795 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1796 pkt << params.density << params.color_bright << params.color_ambient
1797 << params.height << params.thickness << params.speed;
1801 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1804 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1807 pkt << do_override << (u16) (ratio * 65535);
1812 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1814 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1815 pkt << time << time_speed;
1817 if (peer_id == PEER_ID_INEXISTENT) {
1818 m_clients.sendToAll(&pkt);
1825 void Server::SendPlayerHP(session_t peer_id)
1827 PlayerSAO *playersao = getPlayerSAO(peer_id);
1828 // In some rare case if the player is disconnected
1829 // while Lua call l_punch, for example, this can be NULL
1833 SendHP(peer_id, playersao->getHP());
1834 m_script->player_event(playersao,"health_changed");
1836 // Send to other clients
1837 std::string str = gob_cmd_punched(playersao->getHP());
1838 ActiveObjectMessage aom(playersao->getId(), true, str);
1839 playersao->m_messages_out.push(aom);
1842 void Server::SendPlayerBreath(PlayerSAO *sao)
1846 m_script->player_event(sao, "breath_changed");
1847 SendBreath(sao->getPeerID(), sao->getBreath());
1850 void Server::SendMovePlayer(session_t peer_id)
1852 RemotePlayer *player = m_env->getPlayer(peer_id);
1854 PlayerSAO *sao = player->getPlayerSAO();
1857 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1858 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1861 v3f pos = sao->getBasePosition();
1862 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1863 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1864 << " pitch=" << sao->getLookPitch()
1865 << " yaw=" << sao->getRotation().Y
1872 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1873 f32 animation_speed)
1875 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1878 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1879 << animation_frames[3] << animation_speed;
1884 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1886 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1887 pkt << first << third;
1891 void Server::SendPlayerPrivileges(session_t peer_id)
1893 RemotePlayer *player = m_env->getPlayer(peer_id);
1895 if(player->getPeerId() == PEER_ID_INEXISTENT)
1898 std::set<std::string> privs;
1899 m_script->getAuth(player->getName(), NULL, &privs);
1901 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1902 pkt << (u16) privs.size();
1904 for (const std::string &priv : privs) {
1911 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1913 RemotePlayer *player = m_env->getPlayer(peer_id);
1915 if (player->getPeerId() == PEER_ID_INEXISTENT)
1918 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1919 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1923 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1925 RemotePlayer *player = m_env->getPlayer(peer_id);
1927 if (player->getPeerId() == PEER_ID_INEXISTENT)
1930 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1931 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1935 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1937 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1938 pkt.putRawString(datas.c_str(), datas.size());
1940 return pkt.getSize();
1943 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1946 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1947 datas.size(), peer_id);
1949 pkt.putRawString(datas.c_str(), datas.size());
1951 m_clients.send(pkt.getPeerId(),
1952 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1956 void Server::SendCSMRestrictionFlags(session_t peer_id)
1958 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1959 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1960 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1964 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1966 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1971 s32 Server::playSound(const SimpleSoundSpec &spec,
1972 const ServerSoundParams ¶ms)
1974 // Find out initial position of sound
1975 bool pos_exists = false;
1976 v3f pos = params.getPos(m_env, &pos_exists);
1977 // If position is not found while it should be, cancel sound
1978 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1981 // Filter destination clients
1982 std::vector<session_t> dst_clients;
1983 if(!params.to_player.empty()) {
1984 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1986 infostream<<"Server::playSound: Player \""<<params.to_player
1987 <<"\" not found"<<std::endl;
1990 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1991 infostream<<"Server::playSound: Player \""<<params.to_player
1992 <<"\" not connected"<<std::endl;
1995 dst_clients.push_back(player->getPeerId());
1997 std::vector<session_t> clients = m_clients.getClientIDs();
1999 for (const session_t client_id : clients) {
2000 RemotePlayer *player = m_env->getPlayer(client_id);
2004 PlayerSAO *sao = player->getPlayerSAO();
2009 if(sao->getBasePosition().getDistanceFrom(pos) >
2010 params.max_hear_distance)
2013 dst_clients.push_back(client_id);
2017 if(dst_clients.empty())
2021 s32 id = m_next_sound_id++;
2022 // The sound will exist as a reference in m_playing_sounds
2023 m_playing_sounds[id] = ServerPlayingSound();
2024 ServerPlayingSound &psound = m_playing_sounds[id];
2025 psound.params = params;
2028 float gain = params.gain * spec.gain;
2029 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2030 pkt << id << spec.name << gain
2031 << (u8) params.type << pos << params.object
2032 << params.loop << params.fade << params.pitch;
2034 // Backwards compability
2035 bool play_sound = gain > 0;
2037 for (const u16 dst_client : dst_clients) {
2038 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2039 psound.clients.insert(dst_client);
2040 m_clients.send(dst_client, 0, &pkt, true);
2045 void Server::stopSound(s32 handle)
2047 // Get sound reference
2048 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2049 m_playing_sounds.find(handle);
2050 if (i == m_playing_sounds.end())
2052 ServerPlayingSound &psound = i->second;
2054 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2057 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2058 si != psound.clients.end(); ++si) {
2060 m_clients.send(*si, 0, &pkt, true);
2062 // Remove sound reference
2063 m_playing_sounds.erase(i);
2066 void Server::fadeSound(s32 handle, float step, float gain)
2068 // Get sound reference
2069 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2070 m_playing_sounds.find(handle);
2071 if (i == m_playing_sounds.end())
2074 ServerPlayingSound &psound = i->second;
2075 psound.params.gain = gain;
2077 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2078 pkt << handle << step << gain;
2080 // Backwards compability
2081 bool play_sound = gain > 0;
2082 ServerPlayingSound compat_psound = psound;
2083 compat_psound.clients.clear();
2085 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2086 compat_pkt << handle;
2088 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2089 it != psound.clients.end();) {
2090 if (m_clients.getProtocolVersion(*it) >= 32) {
2092 m_clients.send(*it, 0, &pkt, true);
2095 compat_psound.clients.insert(*it);
2097 m_clients.send(*it, 0, &compat_pkt, true);
2098 psound.clients.erase(it++);
2102 // Remove sound reference
2103 if (!play_sound || psound.clients.empty())
2104 m_playing_sounds.erase(i);
2106 if (play_sound && !compat_psound.clients.empty()) {
2107 // Play new sound volume on older clients
2108 playSound(compat_psound.spec, compat_psound.params);
2112 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2115 float maxd = far_d_nodes * BS;
2116 v3f p_f = intToFloat(p, BS);
2117 v3s16 block_pos = getNodeBlockPos(p);
2119 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2122 std::vector<session_t> clients = m_clients.getClientIDs();
2125 for (session_t client_id : clients) {
2126 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2130 RemotePlayer *player = m_env->getPlayer(client_id);
2131 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2133 // If player is far away, only set modified blocks not sent
2134 if (!client->isBlockSent(block_pos) || (sao &&
2135 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2137 far_players->emplace(client_id);
2139 client->SetBlockNotSent(block_pos);
2144 m_clients.send(client_id, 0, &pkt, true);
2150 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2151 float far_d_nodes, bool remove_metadata)
2153 float maxd = far_d_nodes * BS;
2154 v3f p_f = intToFloat(p, BS);
2155 v3s16 block_pos = getNodeBlockPos(p);
2157 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2158 pkt << p << n.param0 << n.param1 << n.param2
2159 << (u8) (remove_metadata ? 0 : 1);
2161 std::vector<session_t> clients = m_clients.getClientIDs();
2164 for (session_t client_id : clients) {
2165 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2169 RemotePlayer *player = m_env->getPlayer(client_id);
2170 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2172 // If player is far away, only set modified blocks not sent
2173 if (!client->isBlockSent(block_pos) || (sao &&
2174 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2176 far_players->emplace(client_id);
2178 client->SetBlockNotSent(block_pos);
2183 m_clients.send(client_id, 0, &pkt, true);
2189 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2191 float maxd = far_d_nodes * BS;
2192 NodeMetadataList meta_updates_list(false);
2193 std::vector<session_t> clients = m_clients.getClientIDs();
2197 for (session_t i : clients) {
2198 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2202 ServerActiveObject *player = m_env->getActiveObject(i);
2203 v3f player_pos = player ? player->getBasePosition() : v3f();
2205 for (const v3s16 &pos : meta_updates) {
2206 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2211 v3s16 block_pos = getNodeBlockPos(pos);
2212 if (!client->isBlockSent(block_pos) || (player &&
2213 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2214 client->SetBlockNotSent(block_pos);
2218 // Add the change to send list
2219 meta_updates_list.set(pos, meta);
2221 if (meta_updates_list.size() == 0)
2224 // Send the meta changes
2225 std::ostringstream os(std::ios::binary);
2226 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2227 std::ostringstream oss(std::ios::binary);
2228 compressZlib(os.str(), oss);
2230 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2231 pkt.putLongString(oss.str());
2232 m_clients.send(i, 0, &pkt, true);
2234 meta_updates_list.clear();
2240 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2241 u16 net_proto_version)
2244 Create a packet with the block in the right format
2247 std::ostringstream os(std::ios_base::binary);
2248 block->serialize(os, ver, false);
2249 block->serializeNetworkSpecific(os);
2250 std::string s = os.str();
2252 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2254 pkt << block->getPos();
2255 pkt.putRawString(s.c_str(), s.size());
2259 void Server::SendBlocks(float dtime)
2261 MutexAutoLock envlock(m_env_mutex);
2262 //TODO check if one big lock could be faster then multiple small ones
2264 std::vector<PrioritySortedBlockTransfer> queue;
2266 u32 total_sending = 0;
2269 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2271 std::vector<session_t> clients = m_clients.getClientIDs();
2274 for (const session_t client_id : clients) {
2275 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2280 total_sending += client->getSendingCount();
2281 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2287 // Lowest priority number comes first.
2288 // Lowest is most important.
2289 std::sort(queue.begin(), queue.end());
2293 // Maximal total count calculation
2294 // The per-client block sends is halved with the maximal online users
2295 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2296 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2298 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2299 Map &map = m_env->getMap();
2301 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2302 if (total_sending >= max_blocks_to_send)
2305 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2309 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2314 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2315 client->net_proto_version);
2317 client->SentBlock(block_to_send.pos);
2323 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2325 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2330 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2331 if (!client || client->isBlockSent(blockpos)) {
2335 SendBlockNoLock(peer_id, block, client->serialization_version,
2336 client->net_proto_version);
2342 void Server::fillMediaCache()
2344 infostream<<"Server: Calculating media file checksums"<<std::endl;
2346 // Collect all media file paths
2347 std::vector<std::string> paths;
2348 m_modmgr->getModsMediaPaths(paths);
2349 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2350 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2352 // Collect media file information from paths into cache
2353 for (const std::string &mediapath : paths) {
2354 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2355 for (const fs::DirListNode &dln : dirlist) {
2356 if (dln.dir) // Ignode dirs
2358 std::string filename = dln.name;
2359 // If name contains illegal characters, ignore the file
2360 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2361 infostream<<"Server: ignoring illegal file name: \""
2362 << filename << "\"" << std::endl;
2365 // If name is not in a supported format, ignore it
2366 const char *supported_ext[] = {
2367 ".png", ".jpg", ".bmp", ".tga",
2368 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2370 ".x", ".b3d", ".md2", ".obj",
2371 // Custom translation file format
2375 if (removeStringEnd(filename, supported_ext).empty()){
2376 infostream << "Server: ignoring unsupported file extension: \""
2377 << filename << "\"" << std::endl;
2380 // Ok, attempt to load the file and add to cache
2381 std::string filepath;
2382 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2385 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2387 errorstream << "Server::fillMediaCache(): Could not open \""
2388 << filename << "\" for reading" << std::endl;
2391 std::ostringstream tmp_os(std::ios_base::binary);
2395 fis.read(buf, 1024);
2396 std::streamsize len = fis.gcount();
2397 tmp_os.write(buf, len);
2406 errorstream<<"Server::fillMediaCache(): Failed to read \""
2407 << filename << "\"" << std::endl;
2410 if(tmp_os.str().length() == 0) {
2411 errorstream << "Server::fillMediaCache(): Empty file \""
2412 << filepath << "\"" << std::endl;
2417 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2419 unsigned char *digest = sha1.getDigest();
2420 std::string sha1_base64 = base64_encode(digest, 20);
2421 std::string sha1_hex = hex_encode((char*)digest, 20);
2425 m_media[filename] = MediaInfo(filepath, sha1_base64);
2426 verbosestream << "Server: " << sha1_hex << " is " << filename
2432 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2434 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2438 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2441 std::string lang_suffix;
2442 lang_suffix.append(".").append(lang_code).append(".tr");
2443 for (const auto &i : m_media) {
2444 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2451 for (const auto &i : m_media) {
2452 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2454 pkt << i.first << i.second.sha1_digest;
2457 pkt << g_settings->get("remote_media");
2461 struct SendableMedia
2467 SendableMedia(const std::string &name_="", const std::string &path_="",
2468 const std::string &data_=""):
2475 void Server::sendRequestedMedia(session_t peer_id,
2476 const std::vector<std::string> &tosend)
2478 verbosestream<<"Server::sendRequestedMedia(): "
2479 <<"Sending files to client"<<std::endl;
2483 // Put 5kB in one bunch (this is not accurate)
2484 u32 bytes_per_bunch = 5000;
2486 std::vector< std::vector<SendableMedia> > file_bunches;
2487 file_bunches.emplace_back();
2489 u32 file_size_bunch_total = 0;
2491 for (const std::string &name : tosend) {
2492 if (m_media.find(name) == m_media.end()) {
2493 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2494 <<"unknown file \""<<(name)<<"\""<<std::endl;
2498 //TODO get path + name
2499 std::string tpath = m_media[name].path;
2502 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2504 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2505 <<tpath<<"\" for reading"<<std::endl;
2508 std::ostringstream tmp_os(std::ios_base::binary);
2512 fis.read(buf, 1024);
2513 std::streamsize len = fis.gcount();
2514 tmp_os.write(buf, len);
2515 file_size_bunch_total += len;
2524 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2525 <<name<<"\""<<std::endl;
2528 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2529 <<tname<<"\""<<std::endl;*/
2531 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2533 // Start next bunch if got enough data
2534 if(file_size_bunch_total >= bytes_per_bunch) {
2535 file_bunches.emplace_back();
2536 file_size_bunch_total = 0;
2541 /* Create and send packets */
2543 u16 num_bunches = file_bunches.size();
2544 for (u16 i = 0; i < num_bunches; i++) {
2547 u16 total number of texture bunches
2548 u16 index of this bunch
2549 u32 number of files in this bunch
2558 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2559 pkt << num_bunches << i << (u32) file_bunches[i].size();
2561 for (const SendableMedia &j : file_bunches[i]) {
2563 pkt.putLongString(j.data);
2566 verbosestream << "Server::sendRequestedMedia(): bunch "
2567 << i << "/" << num_bunches
2568 << " files=" << file_bunches[i].size()
2569 << " size=" << pkt.getSize() << std::endl;
2574 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2576 const auto &inv_it = m_detached_inventories.find(name);
2577 const auto &player_it = m_detached_inventories_player.find(name);
2579 if (player_it == m_detached_inventories_player.end() ||
2580 player_it->second.empty()) {
2581 // OK. Send to everyone
2584 return; // Mods are not done loading
2586 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2588 return; // Player is offline
2590 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2591 return; // Caller requested send to a different player, so don't send.
2593 peer_id = p->getPeerId();
2596 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2599 if (inv_it == m_detached_inventories.end()) {
2600 pkt << false; // Remove inventory
2602 pkt << true; // Update inventory
2604 // Serialization & NetworkPacket isn't a love story
2605 std::ostringstream os(std::ios_base::binary);
2606 inv_it->second->serialize(os);
2607 inv_it->second->setModified(false);
2609 const std::string &os_str = os.str();
2610 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2611 pkt.putRawString(os_str);
2614 if (peer_id == PEER_ID_INEXISTENT)
2615 m_clients.sendToAll(&pkt);
2620 void Server::sendDetachedInventories(session_t peer_id)
2622 for (const auto &detached_inventory : m_detached_inventories) {
2623 const std::string &name = detached_inventory.first;
2624 //Inventory *inv = i->second;
2625 sendDetachedInventory(name, peer_id);
2633 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2635 PlayerSAO *playersao = getPlayerSAO(peer_id);
2636 // In some rare cases this can be NULL -- if the player is disconnected
2637 // when a Lua function modifies l_punch, for example
2641 infostream << "Server::DiePlayer(): Player "
2642 << playersao->getPlayer()->getName()
2643 << " dies" << std::endl;
2645 playersao->setHP(0, reason);
2646 playersao->clearParentAttachment();
2648 // Trigger scripted stuff
2649 m_script->on_dieplayer(playersao, reason);
2651 SendPlayerHP(peer_id);
2652 SendDeathscreen(peer_id, false, v3f(0,0,0));
2655 void Server::RespawnPlayer(session_t peer_id)
2657 PlayerSAO *playersao = getPlayerSAO(peer_id);
2660 infostream << "Server::RespawnPlayer(): Player "
2661 << playersao->getPlayer()->getName()
2662 << " respawns" << std::endl;
2664 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2665 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2666 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2668 bool repositioned = m_script->on_respawnplayer(playersao);
2669 if (!repositioned) {
2670 // setPos will send the new position to client
2671 playersao->setPos(findSpawnPos());
2674 SendPlayerHP(peer_id);
2678 void Server::DenySudoAccess(session_t peer_id)
2680 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2685 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2686 const std::string &str_reason, bool reconnect)
2688 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2690 m_clients.event(peer_id, CSE_SetDenied);
2691 DisconnectPeer(peer_id);
2695 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2696 const std::string &custom_reason)
2698 SendAccessDenied(peer_id, reason, custom_reason);
2699 m_clients.event(peer_id, CSE_SetDenied);
2700 DisconnectPeer(peer_id);
2703 // 13/03/15: remove this function when protocol version 25 will become
2704 // the minimum version for MT users, maybe in 1 year
2705 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2707 SendAccessDenied_Legacy(peer_id, reason);
2708 m_clients.event(peer_id, CSE_SetDenied);
2709 DisconnectPeer(peer_id);
2712 void Server::DisconnectPeer(session_t peer_id)
2714 m_modchannel_mgr->leaveAllChannels(peer_id);
2715 m_con->DisconnectPeer(peer_id);
2718 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2721 RemoteClient* client = getClient(peer_id, CS_Invalid);
2723 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2725 // Right now, the auth mechs don't change between login and sudo mode.
2726 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2727 client->allowed_sudo_mechs = sudo_auth_mechs;
2729 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2730 << g_settings->getFloat("dedicated_server_step")
2734 m_clients.event(peer_id, CSE_AuthAccept);
2736 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2738 // We only support SRP right now
2739 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2741 resp_pkt << sudo_auth_mechs;
2743 m_clients.event(peer_id, CSE_SudoSuccess);
2747 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2749 std::wstring message;
2752 Clear references to playing sounds
2754 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2755 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2756 ServerPlayingSound &psound = i->second;
2757 psound.clients.erase(peer_id);
2758 if (psound.clients.empty())
2759 m_playing_sounds.erase(i++);
2764 // clear formspec info so the next client can't abuse the current state
2765 m_formspec_state_data.erase(peer_id);
2767 RemotePlayer *player = m_env->getPlayer(peer_id);
2769 /* Run scripts and remove from environment */
2771 PlayerSAO *playersao = player->getPlayerSAO();
2774 playersao->clearChildAttachments();
2775 playersao->clearParentAttachment();
2777 // inform connected clients
2778 const std::string &player_name = player->getName();
2779 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2780 // (u16) 1 + std::string represents a vector serialization representation
2781 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2782 m_clients.sendToAll(¬ice);
2784 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2786 playersao->disconnected();
2793 if (player && reason != CDR_DENY) {
2794 std::ostringstream os(std::ios_base::binary);
2795 std::vector<session_t> clients = m_clients.getClientIDs();
2797 for (const session_t client_id : clients) {
2799 RemotePlayer *player = m_env->getPlayer(client_id);
2803 // Get name of player
2804 os << player->getName() << " ";
2807 std::string name = player->getName();
2808 actionstream << name << " "
2809 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2810 << " List of players: " << os.str() << std::endl;
2812 m_admin_chat->outgoing_queue.push_back(
2813 new ChatEventNick(CET_NICK_REMOVE, name));
2817 MutexAutoLock env_lock(m_env_mutex);
2818 m_clients.DeleteClient(peer_id);
2822 // Send leave chat message to all remaining clients
2823 if (!message.empty()) {
2824 SendChatMessage(PEER_ID_INEXISTENT,
2825 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2829 void Server::UpdateCrafting(RemotePlayer *player)
2831 InventoryList *clist = player->inventory.getList("craft");
2832 if (!clist || clist->getSize() == 0)
2835 if (!clist->checkModified()) {
2836 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2840 // Get a preview for crafting
2842 InventoryLocation loc;
2843 loc.setPlayer(player->getName());
2844 std::vector<ItemStack> output_replacements;
2845 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2846 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2849 InventoryList *plist = player->inventory.getList("craftpreview");
2850 if (plist && plist->getSize() >= 1) {
2851 // Put the new preview in
2852 plist->changeItem(0, preview);
2856 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2858 if (evt->type == CET_NICK_ADD) {
2859 // The terminal informed us of its nick choice
2860 m_admin_nick = ((ChatEventNick *)evt)->nick;
2861 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2862 errorstream << "You haven't set up an account." << std::endl
2863 << "Please log in using the client as '"
2864 << m_admin_nick << "' with a secure password." << std::endl
2865 << "Until then, you can't execute admin tasks via the console," << std::endl
2866 << "and everybody can claim the user account instead of you," << std::endl
2867 << "giving them full control over this server." << std::endl;
2870 assert(evt->type == CET_CHAT);
2871 handleAdminChat((ChatEventChat *)evt);
2875 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2876 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2878 // If something goes wrong, this player is to blame
2879 RollbackScopeActor rollback_scope(m_rollback,
2880 std::string("player:") + name);
2882 if (g_settings->getBool("strip_color_codes"))
2883 wmessage = unescape_enriched(wmessage);
2886 switch (player->canSendChatMessage()) {
2887 case RPLAYER_CHATRESULT_FLOODING: {
2888 std::wstringstream ws;
2889 ws << L"You cannot send more messages. You are limited to "
2890 << g_settings->getFloat("chat_message_limit_per_10sec")
2891 << L" messages per 10 seconds.";
2894 case RPLAYER_CHATRESULT_KICK:
2895 DenyAccess_Legacy(player->getPeerId(),
2896 L"You have been kicked due to message flooding.");
2898 case RPLAYER_CHATRESULT_OK:
2901 FATAL_ERROR("Unhandled chat filtering result found.");
2905 if (m_max_chatmessage_length > 0
2906 && wmessage.length() > m_max_chatmessage_length) {
2907 return L"Your message exceed the maximum chat message limit set on the server. "
2908 L"It was refused. Send a shorter message";
2911 auto message = trim(wide_to_utf8(wmessage));
2912 if (message.find_first_of("\n\r") != std::wstring::npos) {
2913 return L"New lines are not permitted in chat messages";
2916 // Run script hook, exit if script ate the chat message
2917 if (m_script->on_chat_message(name, message))
2922 // Whether to send line to the player that sent the message, or to all players
2923 bool broadcast_line = true;
2925 if (check_shout_priv && !checkPriv(name, "shout")) {
2926 line += L"-!- You don't have permission to shout.";
2927 broadcast_line = false;
2929 line += narrow_to_wide(m_script->formatChatMessage(name,
2930 wide_to_narrow(wmessage)));
2934 Tell calling method to send the message to sender
2936 if (!broadcast_line)
2940 Send the message to others
2942 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2944 std::vector<session_t> clients = m_clients.getClientIDs();
2947 Send the message back to the inital sender
2948 if they are using protocol version >= 29
2951 session_t peer_id_to_avoid_sending =
2952 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2954 if (player && player->protocol_version >= 29)
2955 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2957 for (u16 cid : clients) {
2958 if (cid != peer_id_to_avoid_sending)
2959 SendChatMessage(cid, ChatMessage(line));
2964 void Server::handleAdminChat(const ChatEventChat *evt)
2966 std::string name = evt->nick;
2967 std::wstring wname = utf8_to_wide(name);
2968 std::wstring wmessage = evt->evt_msg;
2970 std::wstring answer = handleChat(name, wname, wmessage);
2972 // If asked to send answer to sender
2973 if (!answer.empty()) {
2974 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2978 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2980 RemoteClient *client = getClientNoEx(peer_id,state_min);
2982 throw ClientNotFoundException("Client not found");
2986 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2988 return m_clients.getClientNoEx(peer_id, state_min);
2991 std::string Server::getPlayerName(session_t peer_id)
2993 RemotePlayer *player = m_env->getPlayer(peer_id);
2995 return "[id="+itos(peer_id)+"]";
2996 return player->getName();
2999 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3001 RemotePlayer *player = m_env->getPlayer(peer_id);
3004 return player->getPlayerSAO();
3007 std::wstring Server::getStatusString()
3009 std::wostringstream os(std::ios_base::binary);
3010 os << L"# Server: ";
3012 os << L"version=" << narrow_to_wide(g_version_string);
3014 os << L", uptime=" << m_uptime.get();
3016 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3018 // Information about clients
3020 os << L", clients={";
3022 std::vector<session_t> clients = m_clients.getClientIDs();
3023 for (session_t client_id : clients) {
3024 RemotePlayer *player = m_env->getPlayer(client_id);
3026 // Get name of player
3027 std::wstring name = L"unknown";
3029 name = narrow_to_wide(player->getName());
3031 // Add name to information string
3042 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3043 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3045 if (!g_settings->get("motd").empty())
3046 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3051 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3053 std::set<std::string> privs;
3054 m_script->getAuth(name, NULL, &privs);
3058 bool Server::checkPriv(const std::string &name, const std::string &priv)
3060 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3061 return (privs.count(priv) != 0);
3064 void Server::reportPrivsModified(const std::string &name)
3067 std::vector<session_t> clients = m_clients.getClientIDs();
3068 for (const session_t client_id : clients) {
3069 RemotePlayer *player = m_env->getPlayer(client_id);
3070 reportPrivsModified(player->getName());
3073 RemotePlayer *player = m_env->getPlayer(name.c_str());
3076 SendPlayerPrivileges(player->getPeerId());
3077 PlayerSAO *sao = player->getPlayerSAO();
3080 sao->updatePrivileges(
3081 getPlayerEffectivePrivs(name),
3086 void Server::reportInventoryFormspecModified(const std::string &name)
3088 RemotePlayer *player = m_env->getPlayer(name.c_str());
3091 SendPlayerInventoryFormspec(player->getPeerId());
3094 void Server::reportFormspecPrependModified(const std::string &name)
3096 RemotePlayer *player = m_env->getPlayer(name.c_str());
3099 SendPlayerFormspecPrepend(player->getPeerId());
3102 void Server::setIpBanned(const std::string &ip, const std::string &name)
3104 m_banmanager->add(ip, name);
3107 void Server::unsetIpBanned(const std::string &ip_or_name)
3109 m_banmanager->remove(ip_or_name);
3112 std::string Server::getBanDescription(const std::string &ip_or_name)
3114 return m_banmanager->getBanDescription(ip_or_name);
3117 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3119 // m_env will be NULL if the server is initializing
3123 if (m_admin_nick == name && !m_admin_nick.empty()) {
3124 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3127 RemotePlayer *player = m_env->getPlayer(name);
3132 if (player->getPeerId() == PEER_ID_INEXISTENT)
3135 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3138 bool Server::showFormspec(const char *playername, const std::string &formspec,
3139 const std::string &formname)
3141 // m_env will be NULL if the server is initializing
3145 RemotePlayer *player = m_env->getPlayer(playername);
3149 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3153 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3158 u32 id = player->addHud(form);
3160 SendHUDAdd(player->getPeerId(), id, form);
3165 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3169 HudElement* todel = player->removeHud(id);
3176 SendHUDRemove(player->getPeerId(), id);
3180 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3185 SendHUDChange(player->getPeerId(), id, stat, data);
3189 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3194 SendHUDSetFlags(player->getPeerId(), flags, mask);
3195 player->hud_flags &= ~mask;
3196 player->hud_flags |= flags;
3198 PlayerSAO* playersao = player->getPlayerSAO();
3203 m_script->player_event(playersao, "hud_changed");
3207 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3212 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3215 player->setHotbarItemcount(hotbar_itemcount);
3216 std::ostringstream os(std::ios::binary);
3217 writeS32(os, hotbar_itemcount);
3218 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3222 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3227 player->setHotbarImage(name);
3228 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3231 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3236 player->setHotbarSelectedImage(name);
3237 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3240 Address Server::getPeerAddress(session_t peer_id)
3242 return m_con->GetPeerAddress(peer_id);
3245 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3246 v2s32 animation_frames[4], f32 frame_speed)
3248 sanity_check(player);
3249 player->setLocalAnimations(animation_frames, frame_speed);
3250 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3253 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3255 sanity_check(player);
3256 player->eye_offset_first = first;
3257 player->eye_offset_third = third;
3258 SendEyeOffset(player->getPeerId(), first, third);
3261 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3262 const std::string &type, const std::vector<std::string> ¶ms,
3265 sanity_check(player);
3266 player->setSky(bgcolor, type, params, clouds);
3267 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3270 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3272 sanity_check(player);
3273 player->setCloudParams(params);
3274 SendCloudParams(player->getPeerId(), params);
3277 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3283 player->overrideDayNightRatio(do_override, ratio);
3284 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3288 void Server::notifyPlayers(const std::wstring &msg)
3290 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3293 void Server::spawnParticle(const std::string &playername, v3f pos,
3294 v3f velocity, v3f acceleration,
3295 float expirationtime, float size, bool
3296 collisiondetection, bool collision_removal, bool object_collision,
3297 bool vertical, const std::string &texture,
3298 const struct TileAnimationParams &animation, u8 glow)
3300 // m_env will be NULL if the server is initializing
3304 session_t peer_id = PEER_ID_INEXISTENT;
3306 if (!playername.empty()) {
3307 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3310 peer_id = player->getPeerId();
3311 proto_ver = player->protocol_version;
3314 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3315 expirationtime, size, collisiondetection, collision_removal,
3316 object_collision, vertical, texture, animation, glow);
3319 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3320 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3321 float minexptime, float maxexptime, float minsize, float maxsize,
3322 bool collisiondetection, bool collision_removal, bool object_collision,
3323 ServerActiveObject *attached, bool vertical, const std::string &texture,
3324 const std::string &playername, const struct TileAnimationParams &animation,
3327 // m_env will be NULL if the server is initializing
3331 session_t peer_id = PEER_ID_INEXISTENT;
3333 if (!playername.empty()) {
3334 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3337 peer_id = player->getPeerId();
3338 proto_ver = player->protocol_version;
3341 u16 attached_id = attached ? attached->getId() : 0;
3344 if (attached_id == 0)
3345 id = m_env->addParticleSpawner(spawntime);
3347 id = m_env->addParticleSpawner(spawntime, attached_id);
3349 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3350 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3351 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3352 collision_removal, object_collision, attached_id, vertical,
3353 texture, id, animation, glow);
3358 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3360 // m_env will be NULL if the server is initializing
3362 throw ServerError("Can't delete particle spawners during initialisation!");
3364 session_t peer_id = PEER_ID_INEXISTENT;
3365 if (!playername.empty()) {
3366 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3369 peer_id = player->getPeerId();
3372 m_env->deleteParticleSpawner(id);
3373 SendDeleteParticleSpawner(peer_id, id);
3376 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3378 if(m_detached_inventories.count(name) > 0){
3379 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3380 delete m_detached_inventories[name];
3382 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3384 Inventory *inv = new Inventory(m_itemdef);
3386 m_detached_inventories[name] = inv;
3387 if (!player.empty())
3388 m_detached_inventories_player[name] = player;
3390 //TODO find a better way to do this
3391 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3395 bool Server::removeDetachedInventory(const std::string &name)
3397 const auto &inv_it = m_detached_inventories.find(name);
3398 if (inv_it == m_detached_inventories.end())
3401 delete inv_it->second;
3402 m_detached_inventories.erase(inv_it);
3404 if (!m_env) // Mods are not done loading
3407 const auto &player_it = m_detached_inventories_player.find(name);
3408 if (player_it != m_detached_inventories_player.end()) {
3409 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3411 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3412 sendDetachedInventory(name, player->getPeerId());
3414 m_detached_inventories_player.erase(player_it);
3416 // Notify all players about the change
3417 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3422 // actions: time-reversed list
3423 // Return value: success/failure
3424 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3425 std::list<std::string> *log)
3427 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3428 ServerMap *map = (ServerMap*)(&m_env->getMap());
3430 // Fail if no actions to handle
3431 if (actions.empty()) {
3433 log->push_back("Nothing to do.");
3440 for (const RollbackAction &action : actions) {
3442 bool success = action.applyRevert(map, this, this);
3445 std::ostringstream os;
3446 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3447 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3449 log->push_back(os.str());
3451 std::ostringstream os;
3452 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3453 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3455 log->push_back(os.str());
3459 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3460 <<" failed"<<std::endl;
3462 // Call it done if less than half failed
3463 return num_failed <= num_tried/2;
3466 // IGameDef interface
3468 IItemDefManager *Server::getItemDefManager()
3473 const NodeDefManager *Server::getNodeDefManager()
3478 ICraftDefManager *Server::getCraftDefManager()
3483 u16 Server::allocateUnknownNodeId(const std::string &name)
3485 return m_nodedef->allocateDummy(name);
3488 IWritableItemDefManager *Server::getWritableItemDefManager()
3493 NodeDefManager *Server::getWritableNodeDefManager()
3498 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3503 const std::vector<ModSpec> & Server::getMods() const
3505 return m_modmgr->getMods();
3508 const ModSpec *Server::getModSpec(const std::string &modname) const
3510 return m_modmgr->getModSpec(modname);
3513 void Server::getModNames(std::vector<std::string> &modlist)
3515 m_modmgr->getModNames(modlist);
3518 std::string Server::getBuiltinLuaPath()
3520 return porting::path_share + DIR_DELIM + "builtin";
3523 std::string Server::getModStoragePath() const
3525 return m_path_world + DIR_DELIM + "mod_storage";
3528 v3f Server::findSpawnPos()
3530 ServerMap &map = m_env->getServerMap();
3532 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3533 return nodeposf * BS;
3535 bool is_good = false;
3536 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3537 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3539 // Try to find a good place a few times
3540 for (s32 i = 0; i < 4000 && !is_good; i++) {
3541 s32 range = MYMIN(1 + i, range_max);
3542 // We're going to try to throw the player to this position
3543 v2s16 nodepos2d = v2s16(
3544 -range + (myrand() % (range * 2)),
3545 -range + (myrand() % (range * 2)));
3546 // Get spawn level at point
3547 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3548 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3549 // signify an unsuitable spawn position, or if outside limits.
3550 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3551 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3554 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3555 // Consecutive empty nodes
3558 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3559 // avoid obstructions in already-generated mapblocks.
3560 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3561 // no obstructions, but mapgen decorations are generated after spawn so
3562 // the player may end up inside one.
3563 for (s32 i = 0; i < 8; i++) {
3564 v3s16 blockpos = getNodeBlockPos(nodepos);
3565 map.emergeBlock(blockpos, true);
3566 content_t c = map.getNode(nodepos).getContent();
3568 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3569 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3570 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3572 if (air_count >= 2) {
3573 // Spawn in lower empty node
3575 nodeposf = intToFloat(nodepos, BS);
3576 // Don't spawn the player outside map boundaries
3577 if (objectpos_over_limit(nodeposf))
3578 // Exit this loop, positions above are probably over limit
3581 // Good position found, cause an exit from main loop
3595 // No suitable spawn point found, return fallback 0,0,0
3596 return v3f(0.0f, 0.0f, 0.0f);
3599 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3601 if (delay == 0.0f) {
3602 // No delay, shutdown immediately
3603 m_shutdown_state.is_requested = true;
3604 // only print to the infostream, a chat message saying
3605 // "Server Shutting Down" is sent when the server destructs.
3606 infostream << "*** Immediate Server shutdown requested." << std::endl;
3607 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3608 // Negative delay, cancel shutdown if requested
3609 m_shutdown_state.reset();
3610 std::wstringstream ws;
3612 ws << L"*** Server shutdown canceled.";
3614 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3615 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3616 // m_shutdown_* are already handled, skip.
3618 } else if (delay > 0.0f) {
3619 // Positive delay, tell the clients when the server will shut down
3620 std::wstringstream ws;
3622 ws << L"*** Server shutting down in "
3623 << duration_to_string(myround(delay)).c_str()
3626 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3627 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3630 m_shutdown_state.trigger(delay, msg, reconnect);
3633 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3636 Try to get an existing player
3638 RemotePlayer *player = m_env->getPlayer(name);
3640 // If player is already connected, cancel
3641 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3642 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3647 If player with the wanted peer_id already exists, cancel.
3649 if (m_env->getPlayer(peer_id)) {
3650 infostream<<"emergePlayer(): Player with wrong name but same"
3651 " peer_id already exists"<<std::endl;
3656 player = new RemotePlayer(name, idef());
3659 bool newplayer = false;
3662 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3664 // Complete init with server parts
3665 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3666 player->protocol_version = proto_version;
3670 m_script->on_newplayer(playersao);
3676 bool Server::registerModStorage(ModMetadata *storage)
3678 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3679 errorstream << "Unable to register same mod storage twice. Storage name: "
3680 << storage->getModName() << std::endl;
3684 m_mod_storages[storage->getModName()] = storage;
3688 void Server::unregisterModStorage(const std::string &name)
3690 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3691 if (it != m_mod_storages.end()) {
3692 // Save unconditionaly on unregistration
3693 it->second->save(getModStoragePath());
3694 m_mod_storages.erase(name);
3698 void dedicated_server_loop(Server &server, bool &kill)
3700 verbosestream<<"dedicated_server_loop()"<<std::endl;
3702 IntervalLimiter m_profiler_interval;
3704 static thread_local const float steplen =
3705 g_settings->getFloat("dedicated_server_step");
3706 static thread_local const float profiler_print_interval =
3707 g_settings->getFloat("profiler_print_interval");
3710 // This is kind of a hack but can be done like this
3711 // because server.step() is very light
3712 sleep_ms((int)(steplen*1000.0));
3713 server.step(steplen);
3715 if (server.isShutdownRequested() || kill)
3721 if (profiler_print_interval != 0) {
3722 if(m_profiler_interval.step(steplen, profiler_print_interval))
3724 infostream<<"Profiler:"<<std::endl;
3725 g_profiler->print(infostream);
3726 g_profiler->clear();
3731 infostream << "Dedicated server quitting" << std::endl;
3733 if (g_settings->getBool("server_announce"))
3734 ServerList::sendAnnounce(ServerList::AA_DELETE,
3735 server.m_bind_addr.getPort());
3744 bool Server::joinModChannel(const std::string &channel)
3746 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3747 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3750 bool Server::leaveModChannel(const std::string &channel)
3752 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3755 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3757 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3760 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3764 ModChannel* Server::getModChannel(const std::string &channel)
3766 return m_modchannel_mgr->getModChannel(channel);
3769 void Server::broadcastModChannelMessage(const std::string &channel,
3770 const std::string &message, session_t from_peer)
3772 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3776 if (message.size() > STRING_MAX_LEN) {
3777 warningstream << "ModChannel message too long, dropping before sending "
3778 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3779 << channel << ")" << std::endl;
3784 if (from_peer != PEER_ID_SERVER) {
3785 sender = getPlayerName(from_peer);
3788 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3789 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3790 resp_pkt << channel << sender << message;
3791 for (session_t peer_id : peers) {
3793 if (peer_id == from_peer)
3796 Send(peer_id, &resp_pkt);
3799 if (from_peer != PEER_ID_SERVER) {
3800 m_script->on_modchannel_message(channel, sender, message);