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)
1240 case InventoryLocation::UNDEFINED:
1242 case InventoryLocation::PLAYER:
1245 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1250 player->setModified(true);
1251 // Updates are sent in ServerEnvironment::step()
1254 case InventoryLocation::NODEMETA:
1257 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1259 m_env->getMap().dispatchEvent(&event);
1262 case InventoryLocation::DETACHED:
1264 // Updates are sent in ServerEnvironment::step()
1268 sanity_check(false); // abort
1273 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1275 std::vector<session_t> clients = m_clients.getClientIDs();
1277 // Set the modified blocks unsent for all the clients
1278 for (const session_t client_id : clients) {
1279 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1280 client->SetBlocksNotSent(block);
1285 void Server::peerAdded(con::Peer *peer)
1287 verbosestream<<"Server::peerAdded(): peer->id="
1288 <<peer->id<<std::endl;
1290 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1293 void Server::deletingPeer(con::Peer *peer, bool timeout)
1295 verbosestream<<"Server::deletingPeer(): peer->id="
1296 <<peer->id<<", timeout="<<timeout<<std::endl;
1298 m_clients.event(peer->id, CSE_Disconnect);
1299 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1302 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1304 *retval = m_con->getPeerStat(peer_id,type);
1305 return *retval != -1;
1308 bool Server::getClientInfo(
1317 std::string* vers_string
1320 *state = m_clients.getClientState(peer_id);
1322 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1329 *uptime = client->uptime();
1330 *ser_vers = client->serialization_version;
1331 *prot_vers = client->net_proto_version;
1333 *major = client->getMajor();
1334 *minor = client->getMinor();
1335 *patch = client->getPatch();
1336 *vers_string = client->getPatch();
1343 void Server::handlePeerChanges()
1345 while(!m_peer_change_queue.empty())
1347 con::PeerChange c = m_peer_change_queue.front();
1348 m_peer_change_queue.pop();
1350 verbosestream<<"Server: Handling peer change: "
1351 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1356 case con::PEER_ADDED:
1357 m_clients.CreateClient(c.peer_id);
1360 case con::PEER_REMOVED:
1361 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1365 FATAL_ERROR("Invalid peer change event received!");
1371 void Server::printToConsoleOnly(const std::string &text)
1374 m_admin_chat->outgoing_queue.push_back(
1375 new ChatEventChat("", utf8_to_wide(text)));
1377 std::cout << text << std::endl;
1381 void Server::Send(NetworkPacket *pkt)
1383 Send(pkt->getPeerId(), pkt);
1386 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1388 m_clients.send(peer_id,
1389 clientCommandFactoryTable[pkt->getCommand()].channel,
1391 clientCommandFactoryTable[pkt->getCommand()].reliable);
1394 void Server::SendMovement(session_t peer_id)
1396 std::ostringstream os(std::ios_base::binary);
1398 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1400 pkt << g_settings->getFloat("movement_acceleration_default");
1401 pkt << g_settings->getFloat("movement_acceleration_air");
1402 pkt << g_settings->getFloat("movement_acceleration_fast");
1403 pkt << g_settings->getFloat("movement_speed_walk");
1404 pkt << g_settings->getFloat("movement_speed_crouch");
1405 pkt << g_settings->getFloat("movement_speed_fast");
1406 pkt << g_settings->getFloat("movement_speed_climb");
1407 pkt << g_settings->getFloat("movement_speed_jump");
1408 pkt << g_settings->getFloat("movement_liquid_fluidity");
1409 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1410 pkt << g_settings->getFloat("movement_liquid_sink");
1411 pkt << g_settings->getFloat("movement_gravity");
1416 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1418 if (playersao->isImmortal())
1421 session_t peer_id = playersao->getPeerID();
1422 bool is_alive = playersao->getHP() > 0;
1425 SendPlayerHP(peer_id);
1427 DiePlayer(peer_id, reason);
1430 void Server::SendHP(session_t peer_id, u16 hp)
1432 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1437 void Server::SendBreath(session_t peer_id, u16 breath)
1439 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1440 pkt << (u16) breath;
1444 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1445 const std::string &custom_reason, bool reconnect)
1447 assert(reason < SERVER_ACCESSDENIED_MAX);
1449 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1451 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1452 pkt << custom_reason;
1453 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1454 reason == SERVER_ACCESSDENIED_CRASH)
1455 pkt << custom_reason << (u8)reconnect;
1459 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1461 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1466 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1467 v3f camera_point_target)
1469 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1470 pkt << set_camera_point_target << camera_point_target;
1474 void Server::SendItemDef(session_t peer_id,
1475 IItemDefManager *itemdef, u16 protocol_version)
1477 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1481 u32 length of the next item
1482 zlib-compressed serialized ItemDefManager
1484 std::ostringstream tmp_os(std::ios::binary);
1485 itemdef->serialize(tmp_os, protocol_version);
1486 std::ostringstream tmp_os2(std::ios::binary);
1487 compressZlib(tmp_os.str(), tmp_os2);
1488 pkt.putLongString(tmp_os2.str());
1491 verbosestream << "Server: Sending item definitions to id(" << peer_id
1492 << "): size=" << pkt.getSize() << std::endl;
1497 void Server::SendNodeDef(session_t peer_id,
1498 const NodeDefManager *nodedef, u16 protocol_version)
1500 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1504 u32 length of the next item
1505 zlib-compressed serialized NodeDefManager
1507 std::ostringstream tmp_os(std::ios::binary);
1508 nodedef->serialize(tmp_os, protocol_version);
1509 std::ostringstream tmp_os2(std::ios::binary);
1510 compressZlib(tmp_os.str(), tmp_os2);
1512 pkt.putLongString(tmp_os2.str());
1515 verbosestream << "Server: Sending node definitions to id(" << peer_id
1516 << "): size=" << pkt.getSize() << std::endl;
1522 Non-static send methods
1525 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1527 RemotePlayer *player = sao->getPlayer();
1529 // Do not send new format to old clients
1530 incremental &= player->protocol_version >= 38;
1532 UpdateCrafting(player);
1538 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1540 std::ostringstream os(std::ios::binary);
1541 sao->getInventory()->serialize(os, incremental);
1542 sao->getInventory()->setModified(false);
1543 player->setModified(true);
1545 const std::string &s = os.str();
1546 pkt.putRawString(s.c_str(), s.size());
1550 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1552 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1554 u8 type = message.type;
1555 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1557 if (peer_id != PEER_ID_INEXISTENT) {
1558 RemotePlayer *player = m_env->getPlayer(peer_id);
1564 m_clients.sendToAll(&pkt);
1568 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1569 const std::string &formname)
1571 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1572 if (formspec.empty()){
1573 //the client should close the formspec
1574 //but make sure there wasn't another one open in meantime
1575 const auto it = m_formspec_state_data.find(peer_id);
1576 if (it != m_formspec_state_data.end() && it->second == formname) {
1577 m_formspec_state_data.erase(peer_id);
1579 pkt.putLongString("");
1581 m_formspec_state_data[peer_id] = formname;
1582 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1589 // Spawns a particle on peer with peer_id
1590 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1591 v3f pos, v3f velocity, v3f acceleration,
1592 float expirationtime, float size, bool collisiondetection,
1593 bool collision_removal, bool object_collision,
1594 bool vertical, const std::string &texture,
1595 const struct TileAnimationParams &animation, u8 glow)
1597 static thread_local const float radius =
1598 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1600 if (peer_id == PEER_ID_INEXISTENT) {
1601 std::vector<session_t> clients = m_clients.getClientIDs();
1603 for (const session_t client_id : clients) {
1604 RemotePlayer *player = m_env->getPlayer(client_id);
1608 PlayerSAO *sao = player->getPlayerSAO();
1612 // Do not send to distant clients
1613 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1616 SendSpawnParticle(client_id, player->protocol_version,
1617 pos, velocity, acceleration,
1618 expirationtime, size, collisiondetection, collision_removal,
1619 object_collision, vertical, texture, animation, glow);
1624 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1626 pkt << pos << velocity << acceleration << expirationtime
1627 << size << collisiondetection;
1628 pkt.putLongString(texture);
1630 pkt << collision_removal;
1631 // This is horrible but required (why are there two ways to serialize pkts?)
1632 std::ostringstream os(std::ios_base::binary);
1633 animation.serialize(os, protocol_version);
1634 pkt.putRawString(os.str());
1636 pkt << object_collision;
1641 // Adds a ParticleSpawner on peer with peer_id
1642 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1643 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1644 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1645 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1646 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1647 const struct TileAnimationParams &animation, u8 glow)
1649 if (peer_id == PEER_ID_INEXISTENT) {
1650 // This sucks and should be replaced:
1651 std::vector<session_t> clients = m_clients.getClientIDs();
1652 for (const session_t client_id : clients) {
1653 RemotePlayer *player = m_env->getPlayer(client_id);
1656 SendAddParticleSpawner(client_id, player->protocol_version,
1657 amount, spawntime, minpos, maxpos,
1658 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1659 minsize, maxsize, collisiondetection, collision_removal,
1660 object_collision, attached_id, vertical, texture, id,
1666 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1668 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1669 << minacc << maxacc << minexptime << maxexptime << minsize
1670 << maxsize << collisiondetection;
1672 pkt.putLongString(texture);
1674 pkt << id << vertical;
1675 pkt << collision_removal;
1677 // This is horrible but required
1678 std::ostringstream os(std::ios_base::binary);
1679 animation.serialize(os, protocol_version);
1680 pkt.putRawString(os.str());
1682 pkt << object_collision;
1687 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1689 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1691 // Ugly error in this packet
1694 if (peer_id != PEER_ID_INEXISTENT)
1697 m_clients.sendToAll(&pkt);
1701 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1703 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1705 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1706 << form->text << form->number << form->item << form->dir
1707 << form->align << form->offset << form->world_pos << form->size;
1712 void Server::SendHUDRemove(session_t peer_id, u32 id)
1714 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1719 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1721 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1722 pkt << id << (u8) stat;
1726 case HUD_STAT_SCALE:
1727 case HUD_STAT_ALIGN:
1728 case HUD_STAT_OFFSET:
1729 pkt << *(v2f *) value;
1733 pkt << *(std::string *) value;
1735 case HUD_STAT_WORLD_POS:
1736 pkt << *(v3f *) value;
1739 pkt << *(v2s32 *) value;
1741 case HUD_STAT_NUMBER:
1745 pkt << *(u32 *) value;
1752 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1754 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1756 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1758 pkt << flags << mask;
1763 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1765 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1766 pkt << param << value;
1770 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1771 const std::string &type, const std::vector<std::string> ¶ms,
1774 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1775 pkt << bgcolor << type << (u16) params.size();
1777 for (const std::string ¶m : params)
1785 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1787 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1788 pkt << params.density << params.color_bright << params.color_ambient
1789 << params.height << params.thickness << params.speed;
1793 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1796 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1799 pkt << do_override << (u16) (ratio * 65535);
1804 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1806 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1807 pkt << time << time_speed;
1809 if (peer_id == PEER_ID_INEXISTENT) {
1810 m_clients.sendToAll(&pkt);
1817 void Server::SendPlayerHP(session_t peer_id)
1819 PlayerSAO *playersao = getPlayerSAO(peer_id);
1820 // In some rare case if the player is disconnected
1821 // while Lua call l_punch, for example, this can be NULL
1825 SendHP(peer_id, playersao->getHP());
1826 m_script->player_event(playersao,"health_changed");
1828 // Send to other clients
1829 std::string str = gob_cmd_punched(playersao->getHP());
1830 ActiveObjectMessage aom(playersao->getId(), true, str);
1831 playersao->m_messages_out.push(aom);
1834 void Server::SendPlayerBreath(PlayerSAO *sao)
1838 m_script->player_event(sao, "breath_changed");
1839 SendBreath(sao->getPeerID(), sao->getBreath());
1842 void Server::SendMovePlayer(session_t peer_id)
1844 RemotePlayer *player = m_env->getPlayer(peer_id);
1846 PlayerSAO *sao = player->getPlayerSAO();
1849 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1850 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1853 v3f pos = sao->getBasePosition();
1854 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1855 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1856 << " pitch=" << sao->getLookPitch()
1857 << " yaw=" << sao->getRotation().Y
1864 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1865 f32 animation_speed)
1867 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1870 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1871 << animation_frames[3] << animation_speed;
1876 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1878 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1879 pkt << first << third;
1883 void Server::SendPlayerPrivileges(session_t peer_id)
1885 RemotePlayer *player = m_env->getPlayer(peer_id);
1887 if(player->getPeerId() == PEER_ID_INEXISTENT)
1890 std::set<std::string> privs;
1891 m_script->getAuth(player->getName(), NULL, &privs);
1893 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1894 pkt << (u16) privs.size();
1896 for (const std::string &priv : privs) {
1903 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1905 RemotePlayer *player = m_env->getPlayer(peer_id);
1907 if (player->getPeerId() == PEER_ID_INEXISTENT)
1910 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1911 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1915 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1917 RemotePlayer *player = m_env->getPlayer(peer_id);
1919 if (player->getPeerId() == PEER_ID_INEXISTENT)
1922 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1923 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1927 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1929 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1930 pkt.putRawString(datas.c_str(), datas.size());
1932 return pkt.getSize();
1935 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1938 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1939 datas.size(), peer_id);
1941 pkt.putRawString(datas.c_str(), datas.size());
1943 m_clients.send(pkt.getPeerId(),
1944 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1948 void Server::SendCSMRestrictionFlags(session_t peer_id)
1950 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1951 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1952 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1956 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1958 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1963 s32 Server::playSound(const SimpleSoundSpec &spec,
1964 const ServerSoundParams ¶ms)
1966 // Find out initial position of sound
1967 bool pos_exists = false;
1968 v3f pos = params.getPos(m_env, &pos_exists);
1969 // If position is not found while it should be, cancel sound
1970 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1973 // Filter destination clients
1974 std::vector<session_t> dst_clients;
1975 if(!params.to_player.empty()) {
1976 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1978 infostream<<"Server::playSound: Player \""<<params.to_player
1979 <<"\" not found"<<std::endl;
1982 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1983 infostream<<"Server::playSound: Player \""<<params.to_player
1984 <<"\" not connected"<<std::endl;
1987 dst_clients.push_back(player->getPeerId());
1989 std::vector<session_t> clients = m_clients.getClientIDs();
1991 for (const session_t client_id : clients) {
1992 RemotePlayer *player = m_env->getPlayer(client_id);
1996 PlayerSAO *sao = player->getPlayerSAO();
2001 if(sao->getBasePosition().getDistanceFrom(pos) >
2002 params.max_hear_distance)
2005 dst_clients.push_back(client_id);
2009 if(dst_clients.empty())
2013 s32 id = m_next_sound_id++;
2014 // The sound will exist as a reference in m_playing_sounds
2015 m_playing_sounds[id] = ServerPlayingSound();
2016 ServerPlayingSound &psound = m_playing_sounds[id];
2017 psound.params = params;
2020 float gain = params.gain * spec.gain;
2021 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2022 pkt << id << spec.name << gain
2023 << (u8) params.type << pos << params.object
2024 << params.loop << params.fade << params.pitch;
2026 // Backwards compability
2027 bool play_sound = gain > 0;
2029 for (const u16 dst_client : dst_clients) {
2030 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2031 psound.clients.insert(dst_client);
2032 m_clients.send(dst_client, 0, &pkt, true);
2037 void Server::stopSound(s32 handle)
2039 // Get sound reference
2040 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2041 m_playing_sounds.find(handle);
2042 if (i == m_playing_sounds.end())
2044 ServerPlayingSound &psound = i->second;
2046 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2049 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2050 si != psound.clients.end(); ++si) {
2052 m_clients.send(*si, 0, &pkt, true);
2054 // Remove sound reference
2055 m_playing_sounds.erase(i);
2058 void Server::fadeSound(s32 handle, float step, float gain)
2060 // Get sound reference
2061 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2062 m_playing_sounds.find(handle);
2063 if (i == m_playing_sounds.end())
2066 ServerPlayingSound &psound = i->second;
2067 psound.params.gain = gain;
2069 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2070 pkt << handle << step << gain;
2072 // Backwards compability
2073 bool play_sound = gain > 0;
2074 ServerPlayingSound compat_psound = psound;
2075 compat_psound.clients.clear();
2077 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2078 compat_pkt << handle;
2080 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2081 it != psound.clients.end();) {
2082 if (m_clients.getProtocolVersion(*it) >= 32) {
2084 m_clients.send(*it, 0, &pkt, true);
2087 compat_psound.clients.insert(*it);
2089 m_clients.send(*it, 0, &compat_pkt, true);
2090 psound.clients.erase(it++);
2094 // Remove sound reference
2095 if (!play_sound || psound.clients.empty())
2096 m_playing_sounds.erase(i);
2098 if (play_sound && !compat_psound.clients.empty()) {
2099 // Play new sound volume on older clients
2100 playSound(compat_psound.spec, compat_psound.params);
2104 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2107 float maxd = far_d_nodes * BS;
2108 v3f p_f = intToFloat(p, BS);
2109 v3s16 block_pos = getNodeBlockPos(p);
2111 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2114 std::vector<session_t> clients = m_clients.getClientIDs();
2117 for (session_t client_id : clients) {
2118 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2122 RemotePlayer *player = m_env->getPlayer(client_id);
2123 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2125 // If player is far away, only set modified blocks not sent
2126 if (!client->isBlockSent(block_pos) || (sao &&
2127 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2129 far_players->emplace(client_id);
2131 client->SetBlockNotSent(block_pos);
2136 m_clients.send(client_id, 0, &pkt, true);
2142 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2143 float far_d_nodes, bool remove_metadata)
2145 float maxd = far_d_nodes * BS;
2146 v3f p_f = intToFloat(p, BS);
2147 v3s16 block_pos = getNodeBlockPos(p);
2149 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2150 pkt << p << n.param0 << n.param1 << n.param2
2151 << (u8) (remove_metadata ? 0 : 1);
2153 std::vector<session_t> clients = m_clients.getClientIDs();
2156 for (session_t client_id : clients) {
2157 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2161 RemotePlayer *player = m_env->getPlayer(client_id);
2162 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2164 // If player is far away, only set modified blocks not sent
2165 if (!client->isBlockSent(block_pos) || (sao &&
2166 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2168 far_players->emplace(client_id);
2170 client->SetBlockNotSent(block_pos);
2175 m_clients.send(client_id, 0, &pkt, true);
2181 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2183 float maxd = far_d_nodes * BS;
2184 NodeMetadataList meta_updates_list(false);
2185 std::vector<session_t> clients = m_clients.getClientIDs();
2189 for (session_t i : clients) {
2190 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2194 ServerActiveObject *player = m_env->getActiveObject(i);
2195 v3f player_pos = player ? player->getBasePosition() : v3f();
2197 for (const v3s16 &pos : meta_updates) {
2198 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2203 v3s16 block_pos = getNodeBlockPos(pos);
2204 if (!client->isBlockSent(block_pos) || (player &&
2205 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2206 client->SetBlockNotSent(block_pos);
2210 // Add the change to send list
2211 meta_updates_list.set(pos, meta);
2213 if (meta_updates_list.size() == 0)
2216 // Send the meta changes
2217 std::ostringstream os(std::ios::binary);
2218 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2219 std::ostringstream oss(std::ios::binary);
2220 compressZlib(os.str(), oss);
2222 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2223 pkt.putLongString(oss.str());
2224 m_clients.send(i, 0, &pkt, true);
2226 meta_updates_list.clear();
2232 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2233 u16 net_proto_version)
2236 Create a packet with the block in the right format
2239 std::ostringstream os(std::ios_base::binary);
2240 block->serialize(os, ver, false);
2241 block->serializeNetworkSpecific(os);
2242 std::string s = os.str();
2244 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2246 pkt << block->getPos();
2247 pkt.putRawString(s.c_str(), s.size());
2251 void Server::SendBlocks(float dtime)
2253 MutexAutoLock envlock(m_env_mutex);
2254 //TODO check if one big lock could be faster then multiple small ones
2256 std::vector<PrioritySortedBlockTransfer> queue;
2258 u32 total_sending = 0;
2261 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (const session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2272 total_sending += client->getSendingCount();
2273 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2279 // Lowest priority number comes first.
2280 // Lowest is most important.
2281 std::sort(queue.begin(), queue.end());
2285 // Maximal total count calculation
2286 // The per-client block sends is halved with the maximal online users
2287 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2288 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2290 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2291 Map &map = m_env->getMap();
2293 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2294 if (total_sending >= max_blocks_to_send)
2297 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2301 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2306 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2307 client->net_proto_version);
2309 client->SentBlock(block_to_send.pos);
2315 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2317 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2322 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2323 if (!client || client->isBlockSent(blockpos)) {
2327 SendBlockNoLock(peer_id, block, client->serialization_version,
2328 client->net_proto_version);
2334 void Server::fillMediaCache()
2336 infostream<<"Server: Calculating media file checksums"<<std::endl;
2338 // Collect all media file paths
2339 std::vector<std::string> paths;
2340 m_modmgr->getModsMediaPaths(paths);
2341 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2342 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2344 // Collect media file information from paths into cache
2345 for (const std::string &mediapath : paths) {
2346 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2347 for (const fs::DirListNode &dln : dirlist) {
2348 if (dln.dir) // Ignode dirs
2350 std::string filename = dln.name;
2351 // If name contains illegal characters, ignore the file
2352 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2353 infostream<<"Server: ignoring illegal file name: \""
2354 << filename << "\"" << std::endl;
2357 // If name is not in a supported format, ignore it
2358 const char *supported_ext[] = {
2359 ".png", ".jpg", ".bmp", ".tga",
2360 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2362 ".x", ".b3d", ".md2", ".obj",
2363 // Custom translation file format
2367 if (removeStringEnd(filename, supported_ext).empty()){
2368 infostream << "Server: ignoring unsupported file extension: \""
2369 << filename << "\"" << std::endl;
2372 // Ok, attempt to load the file and add to cache
2373 std::string filepath;
2374 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2377 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2379 errorstream << "Server::fillMediaCache(): Could not open \""
2380 << filename << "\" for reading" << std::endl;
2383 std::ostringstream tmp_os(std::ios_base::binary);
2387 fis.read(buf, 1024);
2388 std::streamsize len = fis.gcount();
2389 tmp_os.write(buf, len);
2398 errorstream<<"Server::fillMediaCache(): Failed to read \""
2399 << filename << "\"" << std::endl;
2402 if(tmp_os.str().length() == 0) {
2403 errorstream << "Server::fillMediaCache(): Empty file \""
2404 << filepath << "\"" << std::endl;
2409 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2411 unsigned char *digest = sha1.getDigest();
2412 std::string sha1_base64 = base64_encode(digest, 20);
2413 std::string sha1_hex = hex_encode((char*)digest, 20);
2417 m_media[filename] = MediaInfo(filepath, sha1_base64);
2418 verbosestream << "Server: " << sha1_hex << " is " << filename
2424 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2426 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2430 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2433 std::string lang_suffix;
2434 lang_suffix.append(".").append(lang_code).append(".tr");
2435 for (const auto &i : m_media) {
2436 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2443 for (const auto &i : m_media) {
2444 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2446 pkt << i.first << i.second.sha1_digest;
2449 pkt << g_settings->get("remote_media");
2453 struct SendableMedia
2459 SendableMedia(const std::string &name_="", const std::string &path_="",
2460 const std::string &data_=""):
2467 void Server::sendRequestedMedia(session_t peer_id,
2468 const std::vector<std::string> &tosend)
2470 verbosestream<<"Server::sendRequestedMedia(): "
2471 <<"Sending files to client"<<std::endl;
2475 // Put 5kB in one bunch (this is not accurate)
2476 u32 bytes_per_bunch = 5000;
2478 std::vector< std::vector<SendableMedia> > file_bunches;
2479 file_bunches.emplace_back();
2481 u32 file_size_bunch_total = 0;
2483 for (const std::string &name : tosend) {
2484 if (m_media.find(name) == m_media.end()) {
2485 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2486 <<"unknown file \""<<(name)<<"\""<<std::endl;
2490 //TODO get path + name
2491 std::string tpath = m_media[name].path;
2494 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2496 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2497 <<tpath<<"\" for reading"<<std::endl;
2500 std::ostringstream tmp_os(std::ios_base::binary);
2504 fis.read(buf, 1024);
2505 std::streamsize len = fis.gcount();
2506 tmp_os.write(buf, len);
2507 file_size_bunch_total += len;
2516 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2517 <<name<<"\""<<std::endl;
2520 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2521 <<tname<<"\""<<std::endl;*/
2523 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2525 // Start next bunch if got enough data
2526 if(file_size_bunch_total >= bytes_per_bunch) {
2527 file_bunches.emplace_back();
2528 file_size_bunch_total = 0;
2533 /* Create and send packets */
2535 u16 num_bunches = file_bunches.size();
2536 for (u16 i = 0; i < num_bunches; i++) {
2539 u16 total number of texture bunches
2540 u16 index of this bunch
2541 u32 number of files in this bunch
2550 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2551 pkt << num_bunches << i << (u32) file_bunches[i].size();
2553 for (const SendableMedia &j : file_bunches[i]) {
2555 pkt.putLongString(j.data);
2558 verbosestream << "Server::sendRequestedMedia(): bunch "
2559 << i << "/" << num_bunches
2560 << " files=" << file_bunches[i].size()
2561 << " size=" << pkt.getSize() << std::endl;
2566 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2568 const auto &inv_it = m_detached_inventories.find(name);
2569 const auto &player_it = m_detached_inventories_player.find(name);
2571 if (player_it == m_detached_inventories_player.end() ||
2572 player_it->second.empty()) {
2573 // OK. Send to everyone
2576 return; // Mods are not done loading
2578 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2580 return; // Player is offline
2582 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2583 return; // Caller requested send to a different player, so don't send.
2585 peer_id = p->getPeerId();
2588 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2591 if (inv_it == m_detached_inventories.end()) {
2592 pkt << false; // Remove inventory
2594 pkt << true; // Update inventory
2596 // Serialization & NetworkPacket isn't a love story
2597 std::ostringstream os(std::ios_base::binary);
2598 inv_it->second->serialize(os);
2599 inv_it->second->setModified(false);
2601 const std::string &os_str = os.str();
2602 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2603 pkt.putRawString(os_str);
2606 if (peer_id == PEER_ID_INEXISTENT)
2607 m_clients.sendToAll(&pkt);
2612 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2614 for (const auto &detached_inventory : m_detached_inventories) {
2615 const std::string &name = detached_inventory.first;
2617 Inventory *inv = detached_inventory.second;
2618 if (!inv || !inv->checkModified())
2622 sendDetachedInventory(name, peer_id);
2630 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2632 PlayerSAO *playersao = getPlayerSAO(peer_id);
2633 // In some rare cases this can be NULL -- if the player is disconnected
2634 // when a Lua function modifies l_punch, for example
2638 infostream << "Server::DiePlayer(): Player "
2639 << playersao->getPlayer()->getName()
2640 << " dies" << std::endl;
2642 playersao->setHP(0, reason);
2643 playersao->clearParentAttachment();
2645 // Trigger scripted stuff
2646 m_script->on_dieplayer(playersao, reason);
2648 SendPlayerHP(peer_id);
2649 SendDeathscreen(peer_id, false, v3f(0,0,0));
2652 void Server::RespawnPlayer(session_t peer_id)
2654 PlayerSAO *playersao = getPlayerSAO(peer_id);
2657 infostream << "Server::RespawnPlayer(): Player "
2658 << playersao->getPlayer()->getName()
2659 << " respawns" << std::endl;
2661 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2662 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2663 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2665 bool repositioned = m_script->on_respawnplayer(playersao);
2666 if (!repositioned) {
2667 // setPos will send the new position to client
2668 playersao->setPos(findSpawnPos());
2671 SendPlayerHP(peer_id);
2675 void Server::DenySudoAccess(session_t peer_id)
2677 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2682 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2683 const std::string &str_reason, bool reconnect)
2685 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2687 m_clients.event(peer_id, CSE_SetDenied);
2688 DisconnectPeer(peer_id);
2692 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2693 const std::string &custom_reason)
2695 SendAccessDenied(peer_id, reason, custom_reason);
2696 m_clients.event(peer_id, CSE_SetDenied);
2697 DisconnectPeer(peer_id);
2700 // 13/03/15: remove this function when protocol version 25 will become
2701 // the minimum version for MT users, maybe in 1 year
2702 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2704 SendAccessDenied_Legacy(peer_id, reason);
2705 m_clients.event(peer_id, CSE_SetDenied);
2706 DisconnectPeer(peer_id);
2709 void Server::DisconnectPeer(session_t peer_id)
2711 m_modchannel_mgr->leaveAllChannels(peer_id);
2712 m_con->DisconnectPeer(peer_id);
2715 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2718 RemoteClient* client = getClient(peer_id, CS_Invalid);
2720 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2722 // Right now, the auth mechs don't change between login and sudo mode.
2723 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2724 client->allowed_sudo_mechs = sudo_auth_mechs;
2726 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2727 << g_settings->getFloat("dedicated_server_step")
2731 m_clients.event(peer_id, CSE_AuthAccept);
2733 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2735 // We only support SRP right now
2736 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2738 resp_pkt << sudo_auth_mechs;
2740 m_clients.event(peer_id, CSE_SudoSuccess);
2744 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2746 std::wstring message;
2749 Clear references to playing sounds
2751 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2752 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2753 ServerPlayingSound &psound = i->second;
2754 psound.clients.erase(peer_id);
2755 if (psound.clients.empty())
2756 m_playing_sounds.erase(i++);
2761 // clear formspec info so the next client can't abuse the current state
2762 m_formspec_state_data.erase(peer_id);
2764 RemotePlayer *player = m_env->getPlayer(peer_id);
2766 /* Run scripts and remove from environment */
2768 PlayerSAO *playersao = player->getPlayerSAO();
2771 playersao->clearChildAttachments();
2772 playersao->clearParentAttachment();
2774 // inform connected clients
2775 const std::string &player_name = player->getName();
2776 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2777 // (u16) 1 + std::string represents a vector serialization representation
2778 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2779 m_clients.sendToAll(¬ice);
2781 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2783 playersao->disconnected();
2790 if (player && reason != CDR_DENY) {
2791 std::ostringstream os(std::ios_base::binary);
2792 std::vector<session_t> clients = m_clients.getClientIDs();
2794 for (const session_t client_id : clients) {
2796 RemotePlayer *player = m_env->getPlayer(client_id);
2800 // Get name of player
2801 os << player->getName() << " ";
2804 std::string name = player->getName();
2805 actionstream << name << " "
2806 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2807 << " List of players: " << os.str() << std::endl;
2809 m_admin_chat->outgoing_queue.push_back(
2810 new ChatEventNick(CET_NICK_REMOVE, name));
2814 MutexAutoLock env_lock(m_env_mutex);
2815 m_clients.DeleteClient(peer_id);
2819 // Send leave chat message to all remaining clients
2820 if (!message.empty()) {
2821 SendChatMessage(PEER_ID_INEXISTENT,
2822 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2826 void Server::UpdateCrafting(RemotePlayer *player)
2828 InventoryList *clist = player->inventory.getList("craft");
2829 if (!clist || clist->getSize() == 0)
2832 if (!clist->checkModified()) {
2833 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2837 // Get a preview for crafting
2839 InventoryLocation loc;
2840 loc.setPlayer(player->getName());
2841 std::vector<ItemStack> output_replacements;
2842 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2843 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2846 InventoryList *plist = player->inventory.getList("craftpreview");
2847 if (plist && plist->getSize() >= 1) {
2848 // Put the new preview in
2849 plist->changeItem(0, preview);
2853 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2855 if (evt->type == CET_NICK_ADD) {
2856 // The terminal informed us of its nick choice
2857 m_admin_nick = ((ChatEventNick *)evt)->nick;
2858 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2859 errorstream << "You haven't set up an account." << std::endl
2860 << "Please log in using the client as '"
2861 << m_admin_nick << "' with a secure password." << std::endl
2862 << "Until then, you can't execute admin tasks via the console," << std::endl
2863 << "and everybody can claim the user account instead of you," << std::endl
2864 << "giving them full control over this server." << std::endl;
2867 assert(evt->type == CET_CHAT);
2868 handleAdminChat((ChatEventChat *)evt);
2872 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2873 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2875 // If something goes wrong, this player is to blame
2876 RollbackScopeActor rollback_scope(m_rollback,
2877 std::string("player:") + name);
2879 if (g_settings->getBool("strip_color_codes"))
2880 wmessage = unescape_enriched(wmessage);
2883 switch (player->canSendChatMessage()) {
2884 case RPLAYER_CHATRESULT_FLOODING: {
2885 std::wstringstream ws;
2886 ws << L"You cannot send more messages. You are limited to "
2887 << g_settings->getFloat("chat_message_limit_per_10sec")
2888 << L" messages per 10 seconds.";
2891 case RPLAYER_CHATRESULT_KICK:
2892 DenyAccess_Legacy(player->getPeerId(),
2893 L"You have been kicked due to message flooding.");
2895 case RPLAYER_CHATRESULT_OK:
2898 FATAL_ERROR("Unhandled chat filtering result found.");
2902 if (m_max_chatmessage_length > 0
2903 && wmessage.length() > m_max_chatmessage_length) {
2904 return L"Your message exceed the maximum chat message limit set on the server. "
2905 L"It was refused. Send a shorter message";
2908 auto message = trim(wide_to_utf8(wmessage));
2909 if (message.find_first_of("\n\r") != std::wstring::npos) {
2910 return L"New lines are not permitted in chat messages";
2913 // Run script hook, exit if script ate the chat message
2914 if (m_script->on_chat_message(name, message))
2919 // Whether to send line to the player that sent the message, or to all players
2920 bool broadcast_line = true;
2922 if (check_shout_priv && !checkPriv(name, "shout")) {
2923 line += L"-!- You don't have permission to shout.";
2924 broadcast_line = false;
2926 line += narrow_to_wide(m_script->formatChatMessage(name,
2927 wide_to_narrow(wmessage)));
2931 Tell calling method to send the message to sender
2933 if (!broadcast_line)
2937 Send the message to others
2939 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2941 std::vector<session_t> clients = m_clients.getClientIDs();
2944 Send the message back to the inital sender
2945 if they are using protocol version >= 29
2948 session_t peer_id_to_avoid_sending =
2949 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2951 if (player && player->protocol_version >= 29)
2952 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2954 for (u16 cid : clients) {
2955 if (cid != peer_id_to_avoid_sending)
2956 SendChatMessage(cid, ChatMessage(line));
2961 void Server::handleAdminChat(const ChatEventChat *evt)
2963 std::string name = evt->nick;
2964 std::wstring wname = utf8_to_wide(name);
2965 std::wstring wmessage = evt->evt_msg;
2967 std::wstring answer = handleChat(name, wname, wmessage);
2969 // If asked to send answer to sender
2970 if (!answer.empty()) {
2971 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2975 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2977 RemoteClient *client = getClientNoEx(peer_id,state_min);
2979 throw ClientNotFoundException("Client not found");
2983 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2985 return m_clients.getClientNoEx(peer_id, state_min);
2988 std::string Server::getPlayerName(session_t peer_id)
2990 RemotePlayer *player = m_env->getPlayer(peer_id);
2992 return "[id="+itos(peer_id)+"]";
2993 return player->getName();
2996 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2998 RemotePlayer *player = m_env->getPlayer(peer_id);
3001 return player->getPlayerSAO();
3004 std::wstring Server::getStatusString()
3006 std::wostringstream os(std::ios_base::binary);
3007 os << L"# Server: ";
3009 os << L"version=" << narrow_to_wide(g_version_string);
3011 os << L", uptime=" << m_uptime.get();
3013 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3015 // Information about clients
3017 os << L", clients={";
3019 std::vector<session_t> clients = m_clients.getClientIDs();
3020 for (session_t client_id : clients) {
3021 RemotePlayer *player = m_env->getPlayer(client_id);
3023 // Get name of player
3024 std::wstring name = L"unknown";
3026 name = narrow_to_wide(player->getName());
3028 // Add name to information string
3039 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3040 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3042 if (!g_settings->get("motd").empty())
3043 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3048 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3050 std::set<std::string> privs;
3051 m_script->getAuth(name, NULL, &privs);
3055 bool Server::checkPriv(const std::string &name, const std::string &priv)
3057 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3058 return (privs.count(priv) != 0);
3061 void Server::reportPrivsModified(const std::string &name)
3064 std::vector<session_t> clients = m_clients.getClientIDs();
3065 for (const session_t client_id : clients) {
3066 RemotePlayer *player = m_env->getPlayer(client_id);
3067 reportPrivsModified(player->getName());
3070 RemotePlayer *player = m_env->getPlayer(name.c_str());
3073 SendPlayerPrivileges(player->getPeerId());
3074 PlayerSAO *sao = player->getPlayerSAO();
3077 sao->updatePrivileges(
3078 getPlayerEffectivePrivs(name),
3083 void Server::reportInventoryFormspecModified(const std::string &name)
3085 RemotePlayer *player = m_env->getPlayer(name.c_str());
3088 SendPlayerInventoryFormspec(player->getPeerId());
3091 void Server::reportFormspecPrependModified(const std::string &name)
3093 RemotePlayer *player = m_env->getPlayer(name.c_str());
3096 SendPlayerFormspecPrepend(player->getPeerId());
3099 void Server::setIpBanned(const std::string &ip, const std::string &name)
3101 m_banmanager->add(ip, name);
3104 void Server::unsetIpBanned(const std::string &ip_or_name)
3106 m_banmanager->remove(ip_or_name);
3109 std::string Server::getBanDescription(const std::string &ip_or_name)
3111 return m_banmanager->getBanDescription(ip_or_name);
3114 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3116 // m_env will be NULL if the server is initializing
3120 if (m_admin_nick == name && !m_admin_nick.empty()) {
3121 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3124 RemotePlayer *player = m_env->getPlayer(name);
3129 if (player->getPeerId() == PEER_ID_INEXISTENT)
3132 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3135 bool Server::showFormspec(const char *playername, const std::string &formspec,
3136 const std::string &formname)
3138 // m_env will be NULL if the server is initializing
3142 RemotePlayer *player = m_env->getPlayer(playername);
3146 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3150 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3155 u32 id = player->addHud(form);
3157 SendHUDAdd(player->getPeerId(), id, form);
3162 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3166 HudElement* todel = player->removeHud(id);
3173 SendHUDRemove(player->getPeerId(), id);
3177 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3182 SendHUDChange(player->getPeerId(), id, stat, data);
3186 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3191 SendHUDSetFlags(player->getPeerId(), flags, mask);
3192 player->hud_flags &= ~mask;
3193 player->hud_flags |= flags;
3195 PlayerSAO* playersao = player->getPlayerSAO();
3200 m_script->player_event(playersao, "hud_changed");
3204 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3209 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3212 player->setHotbarItemcount(hotbar_itemcount);
3213 std::ostringstream os(std::ios::binary);
3214 writeS32(os, hotbar_itemcount);
3215 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3219 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3224 player->setHotbarImage(name);
3225 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3228 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3233 player->setHotbarSelectedImage(name);
3234 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3237 Address Server::getPeerAddress(session_t peer_id)
3239 return m_con->GetPeerAddress(peer_id);
3242 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3243 v2s32 animation_frames[4], f32 frame_speed)
3245 sanity_check(player);
3246 player->setLocalAnimations(animation_frames, frame_speed);
3247 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3250 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3252 sanity_check(player);
3253 player->eye_offset_first = first;
3254 player->eye_offset_third = third;
3255 SendEyeOffset(player->getPeerId(), first, third);
3258 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3259 const std::string &type, const std::vector<std::string> ¶ms,
3262 sanity_check(player);
3263 player->setSky(bgcolor, type, params, clouds);
3264 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3267 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3269 sanity_check(player);
3270 player->setCloudParams(params);
3271 SendCloudParams(player->getPeerId(), params);
3274 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3280 player->overrideDayNightRatio(do_override, ratio);
3281 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3285 void Server::notifyPlayers(const std::wstring &msg)
3287 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3290 void Server::spawnParticle(const std::string &playername, v3f pos,
3291 v3f velocity, v3f acceleration,
3292 float expirationtime, float size, bool
3293 collisiondetection, bool collision_removal, bool object_collision,
3294 bool vertical, const std::string &texture,
3295 const struct TileAnimationParams &animation, u8 glow)
3297 // m_env will be NULL if the server is initializing
3301 session_t peer_id = PEER_ID_INEXISTENT;
3303 if (!playername.empty()) {
3304 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3307 peer_id = player->getPeerId();
3308 proto_ver = player->protocol_version;
3311 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3312 expirationtime, size, collisiondetection, collision_removal,
3313 object_collision, vertical, texture, animation, glow);
3316 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3317 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3318 float minexptime, float maxexptime, float minsize, float maxsize,
3319 bool collisiondetection, bool collision_removal, bool object_collision,
3320 ServerActiveObject *attached, bool vertical, const std::string &texture,
3321 const std::string &playername, const struct TileAnimationParams &animation,
3324 // m_env will be NULL if the server is initializing
3328 session_t peer_id = PEER_ID_INEXISTENT;
3330 if (!playername.empty()) {
3331 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3334 peer_id = player->getPeerId();
3335 proto_ver = player->protocol_version;
3338 u16 attached_id = attached ? attached->getId() : 0;
3341 if (attached_id == 0)
3342 id = m_env->addParticleSpawner(spawntime);
3344 id = m_env->addParticleSpawner(spawntime, attached_id);
3346 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3347 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3348 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3349 collision_removal, object_collision, attached_id, vertical,
3350 texture, id, animation, glow);
3355 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3357 // m_env will be NULL if the server is initializing
3359 throw ServerError("Can't delete particle spawners during initialisation!");
3361 session_t peer_id = PEER_ID_INEXISTENT;
3362 if (!playername.empty()) {
3363 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3366 peer_id = player->getPeerId();
3369 m_env->deleteParticleSpawner(id);
3370 SendDeleteParticleSpawner(peer_id, id);
3373 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3375 if(m_detached_inventories.count(name) > 0){
3376 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3377 delete m_detached_inventories[name];
3379 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3381 Inventory *inv = new Inventory(m_itemdef);
3383 m_detached_inventories[name] = inv;
3384 if (!player.empty())
3385 m_detached_inventories_player[name] = player;
3387 //TODO find a better way to do this
3388 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3392 bool Server::removeDetachedInventory(const std::string &name)
3394 const auto &inv_it = m_detached_inventories.find(name);
3395 if (inv_it == m_detached_inventories.end())
3398 delete inv_it->second;
3399 m_detached_inventories.erase(inv_it);
3401 if (!m_env) // Mods are not done loading
3404 const auto &player_it = m_detached_inventories_player.find(name);
3405 if (player_it != m_detached_inventories_player.end()) {
3406 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3408 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3409 sendDetachedInventory(name, player->getPeerId());
3411 m_detached_inventories_player.erase(player_it);
3413 // Notify all players about the change
3414 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3419 // actions: time-reversed list
3420 // Return value: success/failure
3421 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3422 std::list<std::string> *log)
3424 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3425 ServerMap *map = (ServerMap*)(&m_env->getMap());
3427 // Fail if no actions to handle
3428 if (actions.empty()) {
3430 log->push_back("Nothing to do.");
3437 for (const RollbackAction &action : actions) {
3439 bool success = action.applyRevert(map, this, this);
3442 std::ostringstream os;
3443 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3444 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3446 log->push_back(os.str());
3448 std::ostringstream os;
3449 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3450 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3452 log->push_back(os.str());
3456 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3457 <<" failed"<<std::endl;
3459 // Call it done if less than half failed
3460 return num_failed <= num_tried/2;
3463 // IGameDef interface
3465 IItemDefManager *Server::getItemDefManager()
3470 const NodeDefManager *Server::getNodeDefManager()
3475 ICraftDefManager *Server::getCraftDefManager()
3480 u16 Server::allocateUnknownNodeId(const std::string &name)
3482 return m_nodedef->allocateDummy(name);
3485 IWritableItemDefManager *Server::getWritableItemDefManager()
3490 NodeDefManager *Server::getWritableNodeDefManager()
3495 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3500 const std::vector<ModSpec> & Server::getMods() const
3502 return m_modmgr->getMods();
3505 const ModSpec *Server::getModSpec(const std::string &modname) const
3507 return m_modmgr->getModSpec(modname);
3510 void Server::getModNames(std::vector<std::string> &modlist)
3512 m_modmgr->getModNames(modlist);
3515 std::string Server::getBuiltinLuaPath()
3517 return porting::path_share + DIR_DELIM + "builtin";
3520 std::string Server::getModStoragePath() const
3522 return m_path_world + DIR_DELIM + "mod_storage";
3525 v3f Server::findSpawnPos()
3527 ServerMap &map = m_env->getServerMap();
3529 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3530 return nodeposf * BS;
3532 bool is_good = false;
3533 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3534 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3536 // Try to find a good place a few times
3537 for (s32 i = 0; i < 4000 && !is_good; i++) {
3538 s32 range = MYMIN(1 + i, range_max);
3539 // We're going to try to throw the player to this position
3540 v2s16 nodepos2d = v2s16(
3541 -range + (myrand() % (range * 2)),
3542 -range + (myrand() % (range * 2)));
3543 // Get spawn level at point
3544 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3545 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3546 // signify an unsuitable spawn position, or if outside limits.
3547 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3548 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3551 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3552 // Consecutive empty nodes
3555 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3556 // avoid obstructions in already-generated mapblocks.
3557 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3558 // no obstructions, but mapgen decorations are generated after spawn so
3559 // the player may end up inside one.
3560 for (s32 i = 0; i < 8; i++) {
3561 v3s16 blockpos = getNodeBlockPos(nodepos);
3562 map.emergeBlock(blockpos, true);
3563 content_t c = map.getNode(nodepos).getContent();
3565 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3566 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3567 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3569 if (air_count >= 2) {
3570 // Spawn in lower empty node
3572 nodeposf = intToFloat(nodepos, BS);
3573 // Don't spawn the player outside map boundaries
3574 if (objectpos_over_limit(nodeposf))
3575 // Exit this loop, positions above are probably over limit
3578 // Good position found, cause an exit from main loop
3592 // No suitable spawn point found, return fallback 0,0,0
3593 return v3f(0.0f, 0.0f, 0.0f);
3596 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3598 if (delay == 0.0f) {
3599 // No delay, shutdown immediately
3600 m_shutdown_state.is_requested = true;
3601 // only print to the infostream, a chat message saying
3602 // "Server Shutting Down" is sent when the server destructs.
3603 infostream << "*** Immediate Server shutdown requested." << std::endl;
3604 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3605 // Negative delay, cancel shutdown if requested
3606 m_shutdown_state.reset();
3607 std::wstringstream ws;
3609 ws << L"*** Server shutdown canceled.";
3611 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3612 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3613 // m_shutdown_* are already handled, skip.
3615 } else if (delay > 0.0f) {
3616 // Positive delay, tell the clients when the server will shut down
3617 std::wstringstream ws;
3619 ws << L"*** Server shutting down in "
3620 << duration_to_string(myround(delay)).c_str()
3623 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3624 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3627 m_shutdown_state.trigger(delay, msg, reconnect);
3630 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3633 Try to get an existing player
3635 RemotePlayer *player = m_env->getPlayer(name);
3637 // If player is already connected, cancel
3638 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3639 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3644 If player with the wanted peer_id already exists, cancel.
3646 if (m_env->getPlayer(peer_id)) {
3647 infostream<<"emergePlayer(): Player with wrong name but same"
3648 " peer_id already exists"<<std::endl;
3653 player = new RemotePlayer(name, idef());
3656 bool newplayer = false;
3659 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3661 // Complete init with server parts
3662 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3663 player->protocol_version = proto_version;
3667 m_script->on_newplayer(playersao);
3673 bool Server::registerModStorage(ModMetadata *storage)
3675 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3676 errorstream << "Unable to register same mod storage twice. Storage name: "
3677 << storage->getModName() << std::endl;
3681 m_mod_storages[storage->getModName()] = storage;
3685 void Server::unregisterModStorage(const std::string &name)
3687 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3688 if (it != m_mod_storages.end()) {
3689 // Save unconditionaly on unregistration
3690 it->second->save(getModStoragePath());
3691 m_mod_storages.erase(name);
3695 void dedicated_server_loop(Server &server, bool &kill)
3697 verbosestream<<"dedicated_server_loop()"<<std::endl;
3699 IntervalLimiter m_profiler_interval;
3701 static thread_local const float steplen =
3702 g_settings->getFloat("dedicated_server_step");
3703 static thread_local const float profiler_print_interval =
3704 g_settings->getFloat("profiler_print_interval");
3707 // This is kind of a hack but can be done like this
3708 // because server.step() is very light
3709 sleep_ms((int)(steplen*1000.0));
3710 server.step(steplen);
3712 if (server.isShutdownRequested() || kill)
3718 if (profiler_print_interval != 0) {
3719 if(m_profiler_interval.step(steplen, profiler_print_interval))
3721 infostream<<"Profiler:"<<std::endl;
3722 g_profiler->print(infostream);
3723 g_profiler->clear();
3728 infostream << "Dedicated server quitting" << std::endl;
3730 if (g_settings->getBool("server_announce"))
3731 ServerList::sendAnnounce(ServerList::AA_DELETE,
3732 server.m_bind_addr.getPort());
3741 bool Server::joinModChannel(const std::string &channel)
3743 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3744 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3747 bool Server::leaveModChannel(const std::string &channel)
3749 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3752 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3754 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3757 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3761 ModChannel* Server::getModChannel(const std::string &channel)
3763 return m_modchannel_mgr->getModChannel(channel);
3766 void Server::broadcastModChannelMessage(const std::string &channel,
3767 const std::string &message, session_t from_peer)
3769 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3773 if (message.size() > STRING_MAX_LEN) {
3774 warningstream << "ModChannel message too long, dropping before sending "
3775 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3776 << channel << ")" << std::endl;
3781 if (from_peer != PEER_ID_SERVER) {
3782 sender = getPlayerName(from_peer);
3785 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3786 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3787 resp_pkt << channel << sender << message;
3788 for (session_t peer_id : peers) {
3790 if (peer_id == from_peer)
3793 Send(peer_id, &resp_pkt);
3796 if (from_peer != PEER_ID_SERVER) {
3797 m_script->on_modchannel_message(channel, sender, message);