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)
473 g_profiler->add("Server::AsyncRunStep (num)", 1);
477 MutexAutoLock lock1(m_step_dtime_mutex);
478 dtime = m_step_dtime;
482 // Send blocks to clients
486 if((dtime < 0.001) && !initial_step)
489 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
491 //infostream<<"Server steps "<<dtime<<std::endl;
492 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
495 MutexAutoLock lock1(m_step_dtime_mutex);
496 m_step_dtime -= dtime;
503 m_uptime.set(m_uptime.get() + dtime);
509 Update time of day and overall game time
511 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
514 Send to clients at constant intervals
517 m_time_of_day_send_timer -= dtime;
518 if(m_time_of_day_send_timer < 0.0) {
519 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
520 u16 time = m_env->getTimeOfDay();
521 float time_speed = g_settings->getFloat("time_speed");
522 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
526 MutexAutoLock lock(m_env_mutex);
527 // Figure out and report maximum lag to environment
528 float max_lag = m_env->getMaxLagEstimate();
529 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
531 if(dtime > 0.1 && dtime > max_lag * 2.0)
532 infostream<<"Server: Maximum lag peaked to "<<dtime
536 m_env->reportMaxLagEstimate(max_lag);
538 ScopeProfiler sp(g_profiler, "SEnv step");
539 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
543 static const float map_timer_and_unload_dtime = 2.92;
544 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
546 MutexAutoLock lock(m_env_mutex);
547 // Run Map's timers and unload unused data
548 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
549 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
550 g_settings->getFloat("server_unload_unused_data_timeout"),
555 Listen to the admin chat, if available
558 if (!m_admin_chat->command_queue.empty()) {
559 MutexAutoLock lock(m_env_mutex);
560 while (!m_admin_chat->command_queue.empty()) {
561 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
562 handleChatInterfaceEvent(evt);
566 m_admin_chat->outgoing_queue.push_back(
567 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
574 /* Transform liquids */
575 m_liquid_transform_timer += dtime;
576 if(m_liquid_transform_timer >= m_liquid_transform_every)
578 m_liquid_transform_timer -= m_liquid_transform_every;
580 MutexAutoLock lock(m_env_mutex);
582 ScopeProfiler sp(g_profiler, "Server: liquid transform");
584 std::map<v3s16, MapBlock*> modified_blocks;
585 m_env->getMap().transformLiquids(modified_blocks, m_env);
588 Set the modified blocks unsent for all the clients
590 if (!modified_blocks.empty()) {
591 SetBlocksNotSent(modified_blocks);
594 m_clients.step(dtime);
596 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
598 // send masterserver announce
600 float &counter = m_masterserver_timer;
601 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
602 g_settings->getBool("server_announce")) {
603 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
604 ServerList::AA_START,
605 m_bind_addr.getPort(),
606 m_clients.getPlayerNames(),
608 m_env->getGameTime(),
611 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
621 Check added and deleted active objects
624 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
625 MutexAutoLock envlock(m_env_mutex);
628 const RemoteClientMap &clients = m_clients.getClientList();
629 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
631 // Radius inside which objects are active
632 static thread_local const s16 radius =
633 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
635 // Radius inside which players are active
636 static thread_local const bool is_transfer_limited =
637 g_settings->exists("unlimited_player_transfer_distance") &&
638 !g_settings->getBool("unlimited_player_transfer_distance");
639 static thread_local const s16 player_transfer_dist =
640 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
641 s16 player_radius = player_transfer_dist;
642 if (player_radius == 0 && is_transfer_limited)
643 player_radius = radius;
645 for (const auto &client_it : clients) {
646 RemoteClient *client = client_it.second;
648 // If definitions and textures have not been sent, don't
649 // send objects either
650 if (client->getState() < CS_DefinitionsSent)
653 RemotePlayer *player = m_env->getPlayer(client->peer_id);
655 // This can happen if the client timeouts somehow
659 PlayerSAO *playersao = player->getPlayerSAO();
663 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
664 if (my_radius <= 0) my_radius = radius;
665 //infostream << "Server: Active Radius " << my_radius << std::endl;
667 std::queue<u16> removed_objects;
668 std::queue<u16> added_objects;
669 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
670 client->m_known_objects, removed_objects);
671 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
672 client->m_known_objects, added_objects);
674 // Ignore if nothing happened
675 if (removed_objects.empty() && added_objects.empty()) {
679 std::string data_buffer;
683 // Handle removed objects
684 writeU16((u8*)buf, removed_objects.size());
685 data_buffer.append(buf, 2);
686 while (!removed_objects.empty()) {
688 u16 id = removed_objects.front();
689 ServerActiveObject* obj = m_env->getActiveObject(id);
691 // Add to data buffer for sending
692 writeU16((u8*)buf, id);
693 data_buffer.append(buf, 2);
695 // Remove from known objects
696 client->m_known_objects.erase(id);
698 if(obj && obj->m_known_by_count > 0)
699 obj->m_known_by_count--;
700 removed_objects.pop();
703 // Handle added objects
704 writeU16((u8*)buf, added_objects.size());
705 data_buffer.append(buf, 2);
706 while (!added_objects.empty()) {
708 u16 id = added_objects.front();
709 ServerActiveObject* obj = m_env->getActiveObject(id);
712 u8 type = ACTIVEOBJECT_TYPE_INVALID;
714 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
716 type = obj->getSendType();
718 // Add to data buffer for sending
719 writeU16((u8*)buf, id);
720 data_buffer.append(buf, 2);
721 writeU8((u8*)buf, type);
722 data_buffer.append(buf, 1);
725 data_buffer.append(serializeLongString(
726 obj->getClientInitializationData(client->net_proto_version)));
728 data_buffer.append(serializeLongString(""));
730 // Add to known objects
731 client->m_known_objects.insert(id);
734 obj->m_known_by_count++;
739 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
740 verbosestream << "Server: Sent object remove/add: "
741 << removed_objects.size() << " removed, "
742 << added_objects.size() << " added, "
743 << "packet size is " << pktSize << std::endl;
747 m_mod_storage_save_timer -= dtime;
748 if (m_mod_storage_save_timer <= 0.0f) {
749 infostream << "Saving registered mod storages." << std::endl;
750 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
751 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
752 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
753 if (it->second->isModified()) {
754 it->second->save(getModStoragePath());
764 MutexAutoLock envlock(m_env_mutex);
765 ScopeProfiler sp(g_profiler, "Server: sending object messages");
768 // Value = data sent by object
769 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
771 // Get active object messages from environment
773 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
777 std::vector<ActiveObjectMessage>* message_list = nullptr;
778 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
779 n = buffered_messages.find(aom.id);
780 if (n == buffered_messages.end()) {
781 message_list = new std::vector<ActiveObjectMessage>;
782 buffered_messages[aom.id] = message_list;
785 message_list = n->second;
787 message_list->push_back(aom);
791 const RemoteClientMap &clients = m_clients.getClientList();
792 // Route data to every client
793 for (const auto &client_it : clients) {
794 RemoteClient *client = client_it.second;
795 std::string reliable_data;
796 std::string unreliable_data;
797 // Go through all objects in message buffer
798 for (const auto &buffered_message : buffered_messages) {
799 // If object is not known by client, skip it
800 u16 id = buffered_message.first;
801 if (client->m_known_objects.find(id) == client->m_known_objects.end())
804 // Get message list of object
805 std::vector<ActiveObjectMessage>* list = buffered_message.second;
806 // Go through every message
807 for (const ActiveObjectMessage &aom : *list) {
808 // Compose the full new data with header
809 std::string new_data;
812 writeU16((u8*)&buf[0], aom.id);
813 new_data.append(buf, 2);
815 new_data += serializeString(aom.datastring);
816 // Add data to buffer
818 reliable_data += new_data;
820 unreliable_data += new_data;
824 reliable_data and unreliable_data are now ready.
827 if (!reliable_data.empty()) {
828 SendActiveObjectMessages(client->peer_id, reliable_data);
831 if (!unreliable_data.empty()) {
832 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
837 // Clear buffered_messages
838 for (auto &buffered_message : buffered_messages) {
839 delete buffered_message.second;
844 Send queued-for-sending map edit events.
847 // We will be accessing the environment
848 MutexAutoLock lock(m_env_mutex);
850 // Don't send too many at a time
853 // Single change sending is disabled if queue size is not small
854 bool disable_single_change_sending = false;
855 if(m_unsent_map_edit_queue.size() >= 4)
856 disable_single_change_sending = true;
858 int event_count = m_unsent_map_edit_queue.size();
860 // We'll log the amount of each
863 std::list<v3s16> node_meta_updates;
865 while (!m_unsent_map_edit_queue.empty()) {
866 MapEditEvent* event = m_unsent_map_edit_queue.front();
867 m_unsent_map_edit_queue.pop();
869 // Players far away from the change are stored here.
870 // Instead of sending the changes, MapBlocks are set not sent
872 std::unordered_set<u16> far_players;
874 switch (event->type) {
877 prof.add("MEET_ADDNODE", 1);
878 sendAddNode(event->p, event->n, &far_players,
879 disable_single_change_sending ? 5 : 30,
880 event->type == MEET_ADDNODE);
882 case MEET_REMOVENODE:
883 prof.add("MEET_REMOVENODE", 1);
884 sendRemoveNode(event->p, &far_players,
885 disable_single_change_sending ? 5 : 30);
887 case MEET_BLOCK_NODE_METADATA_CHANGED: {
888 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
889 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
890 if (!event->is_private_change) {
891 // Don't send the change yet. Collect them to eliminate dupes.
892 node_meta_updates.remove(event->p);
893 node_meta_updates.push_back(event->p);
896 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
897 getNodeBlockPos(event->p))) {
898 block->raiseModified(MOD_STATE_WRITE_NEEDED,
899 MOD_REASON_REPORT_META_CHANGE);
904 infostream << "Server: MEET_OTHER" << std::endl;
905 prof.add("MEET_OTHER", 1);
906 for (const v3s16 &modified_block : event->modified_blocks) {
907 m_clients.markBlockposAsNotSent(modified_block);
911 prof.add("unknown", 1);
912 warningstream << "Server: Unknown MapEditEvent "
913 << ((u32)event->type) << std::endl;
918 Set blocks not sent to far players
920 if (!far_players.empty()) {
921 // Convert list format to that wanted by SetBlocksNotSent
922 std::map<v3s16, MapBlock*> modified_blocks2;
923 for (const v3s16 &modified_block : event->modified_blocks) {
924 modified_blocks2[modified_block] =
925 m_env->getMap().getBlockNoCreateNoEx(modified_block);
928 // Set blocks not sent
929 for (const u16 far_player : far_players) {
930 if (RemoteClient *client = getClient(far_player))
931 client->SetBlocksNotSent(modified_blocks2);
938 if (event_count >= 5) {
939 infostream << "Server: MapEditEvents:" << std::endl;
940 prof.print(infostream);
941 } else if (event_count != 0) {
942 verbosestream << "Server: MapEditEvents:" << std::endl;
943 prof.print(verbosestream);
946 // Send all metadata updates
947 if (node_meta_updates.size())
948 sendMetadataChanged(node_meta_updates);
952 Trigger emergethread (it somehow gets to a non-triggered but
953 bysy state sometimes)
956 float &counter = m_emergethread_trigger_timer;
958 if (counter >= 2.0) {
961 m_emerge->startThreads();
965 // Save map, players and auth stuff
967 float &counter = m_savemap_timer;
969 static thread_local const float save_interval =
970 g_settings->getFloat("server_map_save_interval");
971 if (counter >= save_interval) {
973 MutexAutoLock lock(m_env_mutex);
975 ScopeProfiler sp(g_profiler, "Server: saving stuff");
978 if (m_banmanager->isModified()) {
979 m_banmanager->save();
982 // Save changed parts of map
983 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
986 m_env->saveLoadedPlayers();
988 // Save environment metadata
993 m_shutdown_state.tick(dtime, this);
996 void Server::Receive()
998 session_t peer_id = 0;
1001 m_con->Receive(&pkt);
1002 peer_id = pkt.getPeerId();
1004 } catch (const con::InvalidIncomingDataException &e) {
1005 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1006 << e.what() << std::endl;
1007 } catch (const SerializationError &e) {
1008 infostream << "Server::Receive(): SerializationError: what()="
1009 << e.what() << std::endl;
1010 } catch (const ClientStateError &e) {
1011 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1012 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1013 L"Try reconnecting or updating your client");
1014 } catch (const con::PeerNotFoundException &e) {
1019 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1021 std::string playername;
1022 PlayerSAO *playersao = NULL;
1025 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1027 playername = client->getName();
1028 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1030 } catch (std::exception &e) {
1036 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1038 // If failed, cancel
1039 if (!playersao || !player) {
1040 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1041 actionstream << "Server: Failed to emerge player \"" << playername
1042 << "\" (player allocated to an another client)" << std::endl;
1043 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1044 L"name. If your client closed unexpectedly, try again in "
1047 errorstream << "Server: " << playername << ": Failed to emerge player"
1049 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1055 Send complete position information
1057 SendMovePlayer(peer_id);
1060 SendPlayerPrivileges(peer_id);
1062 // Send inventory formspec
1063 SendPlayerInventoryFormspec(peer_id);
1066 SendInventory(playersao);
1068 // Send HP or death screen
1069 if (playersao->isDead())
1070 SendDeathscreen(peer_id, false, v3f(0,0,0));
1072 SendPlayerHPOrDie(playersao,
1073 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1076 SendPlayerBreath(playersao);
1078 Address addr = getPeerAddress(player->getPeerId());
1079 std::string ip_str = addr.serializeString();
1080 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1085 const std::vector<std::string> &names = m_clients.getPlayerNames();
1087 actionstream << player->getName() << " joins game. List of players: ";
1089 for (const std::string &name : names) {
1090 actionstream << name << " ";
1093 actionstream << player->getName() <<std::endl;
1098 inline void Server::handleCommand(NetworkPacket* pkt)
1100 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1101 (this->*opHandle.handler)(pkt);
1104 void Server::ProcessData(NetworkPacket *pkt)
1106 // Environment is locked first.
1107 MutexAutoLock envlock(m_env_mutex);
1109 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1110 u32 peer_id = pkt->getPeerId();
1113 Address address = getPeerAddress(peer_id);
1114 std::string addr_s = address.serializeString();
1116 if(m_banmanager->isIpBanned(addr_s)) {
1117 std::string ban_name = m_banmanager->getBanName(addr_s);
1118 infostream << "Server: A banned client tried to connect from "
1119 << addr_s << "; banned name was "
1120 << ban_name << std::endl;
1121 // This actually doesn't seem to transfer to the client
1122 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1123 + utf8_to_wide(ban_name));
1127 catch(con::PeerNotFoundException &e) {
1129 * no peer for this packet found
1130 * most common reason is peer timeout, e.g. peer didn't
1131 * respond for some time, your server was overloaded or
1134 infostream << "Server::ProcessData(): Canceling: peer "
1135 << peer_id << " not found" << std::endl;
1140 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1142 // Command must be handled into ToServerCommandHandler
1143 if (command >= TOSERVER_NUM_MSG_TYPES) {
1144 infostream << "Server: Ignoring unknown command "
1145 << command << std::endl;
1149 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1154 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1156 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1157 errorstream << "Server::ProcessData(): Cancelling: Peer"
1158 " serialization format invalid or not initialized."
1159 " Skipping incoming command=" << command << std::endl;
1163 /* Handle commands related to client startup */
1164 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1169 if (m_clients.getClientState(peer_id) < CS_Active) {
1170 if (command == TOSERVER_PLAYERPOS) return;
1172 errorstream << "Got packet command: " << command << " for peer id "
1173 << peer_id << " but client isn't active yet. Dropping packet "
1179 } catch (SendFailedException &e) {
1180 errorstream << "Server::ProcessData(): SendFailedException: "
1181 << "what=" << e.what()
1183 } catch (PacketError &e) {
1184 actionstream << "Server::ProcessData(): PacketError: "
1185 << "what=" << e.what()
1190 void Server::setTimeOfDay(u32 time)
1192 m_env->setTimeOfDay(time);
1193 m_time_of_day_send_timer = 0;
1196 void Server::onMapEditEvent(MapEditEvent *event)
1198 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1200 MapEditEvent *e = event->clone();
1201 m_unsent_map_edit_queue.push(e);
1204 Inventory* Server::getInventory(const InventoryLocation &loc)
1207 case InventoryLocation::UNDEFINED:
1208 case InventoryLocation::CURRENT_PLAYER:
1210 case InventoryLocation::PLAYER:
1212 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1215 PlayerSAO *playersao = player->getPlayerSAO();
1218 return playersao->getInventory();
1221 case InventoryLocation::NODEMETA:
1223 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1226 return meta->getInventory();
1229 case InventoryLocation::DETACHED:
1231 if(m_detached_inventories.count(loc.name) == 0)
1233 return m_detached_inventories[loc.name];
1237 sanity_check(false); // abort
1243 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1246 case InventoryLocation::UNDEFINED:
1248 case InventoryLocation::PLAYER:
1253 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1258 PlayerSAO *playersao = player->getPlayerSAO();
1262 SendInventory(playersao);
1265 case InventoryLocation::NODEMETA:
1268 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1270 m_env->getMap().dispatchEvent(&event);
1273 case InventoryLocation::DETACHED:
1275 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1279 sanity_check(false); // abort
1284 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1286 std::vector<session_t> clients = m_clients.getClientIDs();
1288 // Set the modified blocks unsent for all the clients
1289 for (const session_t client_id : clients) {
1290 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1291 client->SetBlocksNotSent(block);
1296 void Server::peerAdded(con::Peer *peer)
1298 verbosestream<<"Server::peerAdded(): peer->id="
1299 <<peer->id<<std::endl;
1301 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1304 void Server::deletingPeer(con::Peer *peer, bool timeout)
1306 verbosestream<<"Server::deletingPeer(): peer->id="
1307 <<peer->id<<", timeout="<<timeout<<std::endl;
1309 m_clients.event(peer->id, CSE_Disconnect);
1310 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1313 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1315 *retval = m_con->getPeerStat(peer_id,type);
1316 return *retval != -1;
1319 bool Server::getClientInfo(
1328 std::string* vers_string
1331 *state = m_clients.getClientState(peer_id);
1333 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1340 *uptime = client->uptime();
1341 *ser_vers = client->serialization_version;
1342 *prot_vers = client->net_proto_version;
1344 *major = client->getMajor();
1345 *minor = client->getMinor();
1346 *patch = client->getPatch();
1347 *vers_string = client->getPatch();
1354 void Server::handlePeerChanges()
1356 while(!m_peer_change_queue.empty())
1358 con::PeerChange c = m_peer_change_queue.front();
1359 m_peer_change_queue.pop();
1361 verbosestream<<"Server: Handling peer change: "
1362 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1367 case con::PEER_ADDED:
1368 m_clients.CreateClient(c.peer_id);
1371 case con::PEER_REMOVED:
1372 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1376 FATAL_ERROR("Invalid peer change event received!");
1382 void Server::printToConsoleOnly(const std::string &text)
1385 m_admin_chat->outgoing_queue.push_back(
1386 new ChatEventChat("", utf8_to_wide(text)));
1388 std::cout << text << std::endl;
1392 void Server::Send(NetworkPacket *pkt)
1394 Send(pkt->getPeerId(), pkt);
1397 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1399 m_clients.send(peer_id,
1400 clientCommandFactoryTable[pkt->getCommand()].channel,
1402 clientCommandFactoryTable[pkt->getCommand()].reliable);
1405 void Server::SendMovement(session_t peer_id)
1407 std::ostringstream os(std::ios_base::binary);
1409 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1411 pkt << g_settings->getFloat("movement_acceleration_default");
1412 pkt << g_settings->getFloat("movement_acceleration_air");
1413 pkt << g_settings->getFloat("movement_acceleration_fast");
1414 pkt << g_settings->getFloat("movement_speed_walk");
1415 pkt << g_settings->getFloat("movement_speed_crouch");
1416 pkt << g_settings->getFloat("movement_speed_fast");
1417 pkt << g_settings->getFloat("movement_speed_climb");
1418 pkt << g_settings->getFloat("movement_speed_jump");
1419 pkt << g_settings->getFloat("movement_liquid_fluidity");
1420 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1421 pkt << g_settings->getFloat("movement_liquid_sink");
1422 pkt << g_settings->getFloat("movement_gravity");
1427 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1429 if (playersao->isImmortal())
1432 session_t peer_id = playersao->getPeerID();
1433 bool is_alive = playersao->getHP() > 0;
1436 SendPlayerHP(peer_id);
1438 DiePlayer(peer_id, reason);
1441 void Server::SendHP(session_t peer_id, u16 hp)
1443 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1448 void Server::SendBreath(session_t peer_id, u16 breath)
1450 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1451 pkt << (u16) breath;
1455 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1456 const std::string &custom_reason, bool reconnect)
1458 assert(reason < SERVER_ACCESSDENIED_MAX);
1460 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1462 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1463 pkt << custom_reason;
1464 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1465 reason == SERVER_ACCESSDENIED_CRASH)
1466 pkt << custom_reason << (u8)reconnect;
1470 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1472 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1477 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1478 v3f camera_point_target)
1480 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1481 pkt << set_camera_point_target << camera_point_target;
1485 void Server::SendItemDef(session_t peer_id,
1486 IItemDefManager *itemdef, u16 protocol_version)
1488 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1492 u32 length of the next item
1493 zlib-compressed serialized ItemDefManager
1495 std::ostringstream tmp_os(std::ios::binary);
1496 itemdef->serialize(tmp_os, protocol_version);
1497 std::ostringstream tmp_os2(std::ios::binary);
1498 compressZlib(tmp_os.str(), tmp_os2);
1499 pkt.putLongString(tmp_os2.str());
1502 verbosestream << "Server: Sending item definitions to id(" << peer_id
1503 << "): size=" << pkt.getSize() << std::endl;
1508 void Server::SendNodeDef(session_t peer_id,
1509 const NodeDefManager *nodedef, u16 protocol_version)
1511 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1515 u32 length of the next item
1516 zlib-compressed serialized NodeDefManager
1518 std::ostringstream tmp_os(std::ios::binary);
1519 nodedef->serialize(tmp_os, protocol_version);
1520 std::ostringstream tmp_os2(std::ios::binary);
1521 compressZlib(tmp_os.str(), tmp_os2);
1523 pkt.putLongString(tmp_os2.str());
1526 verbosestream << "Server: Sending node definitions to id(" << peer_id
1527 << "): size=" << pkt.getSize() << std::endl;
1533 Non-static send methods
1536 void Server::SendInventory(PlayerSAO* playerSAO)
1538 UpdateCrafting(playerSAO->getPlayer());
1544 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1546 std::ostringstream os;
1547 playerSAO->getInventory()->serialize(os);
1549 std::string s = os.str();
1551 pkt.putRawString(s.c_str(), s.size());
1555 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1557 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1559 u8 type = message.type;
1560 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1562 if (peer_id != PEER_ID_INEXISTENT) {
1563 RemotePlayer *player = m_env->getPlayer(peer_id);
1569 m_clients.sendToAll(&pkt);
1573 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1574 const std::string &formname)
1576 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1577 if (formspec.empty()){
1578 //the client should close the formspec
1579 //but make sure there wasn't another one open in meantime
1580 const auto it = m_formspec_state_data.find(peer_id);
1581 if (it != m_formspec_state_data.end() && it->second == formname) {
1582 m_formspec_state_data.erase(peer_id);
1584 pkt.putLongString("");
1586 m_formspec_state_data[peer_id] = formname;
1587 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1594 // Spawns a particle on peer with peer_id
1595 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1596 v3f pos, v3f velocity, v3f acceleration,
1597 float expirationtime, float size, bool collisiondetection,
1598 bool collision_removal, bool object_collision,
1599 bool vertical, const std::string &texture,
1600 const struct TileAnimationParams &animation, u8 glow)
1602 static thread_local const float radius =
1603 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1605 if (peer_id == PEER_ID_INEXISTENT) {
1606 std::vector<session_t> clients = m_clients.getClientIDs();
1608 for (const session_t client_id : clients) {
1609 RemotePlayer *player = m_env->getPlayer(client_id);
1613 PlayerSAO *sao = player->getPlayerSAO();
1617 // Do not send to distant clients
1618 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1621 SendSpawnParticle(client_id, player->protocol_version,
1622 pos, velocity, acceleration,
1623 expirationtime, size, collisiondetection, collision_removal,
1624 object_collision, vertical, texture, animation, glow);
1629 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1631 pkt << pos << velocity << acceleration << expirationtime
1632 << size << collisiondetection;
1633 pkt.putLongString(texture);
1635 pkt << collision_removal;
1636 // This is horrible but required (why are there two ways to serialize pkts?)
1637 std::ostringstream os(std::ios_base::binary);
1638 animation.serialize(os, protocol_version);
1639 pkt.putRawString(os.str());
1641 pkt << object_collision;
1646 // Adds a ParticleSpawner on peer with peer_id
1647 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1648 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1649 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1650 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1651 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1652 const struct TileAnimationParams &animation, u8 glow)
1654 if (peer_id == PEER_ID_INEXISTENT) {
1655 // This sucks and should be replaced:
1656 std::vector<session_t> clients = m_clients.getClientIDs();
1657 for (const session_t client_id : clients) {
1658 RemotePlayer *player = m_env->getPlayer(client_id);
1661 SendAddParticleSpawner(client_id, player->protocol_version,
1662 amount, spawntime, minpos, maxpos,
1663 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1664 minsize, maxsize, collisiondetection, collision_removal,
1665 object_collision, attached_id, vertical, texture, id,
1671 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1673 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1674 << minacc << maxacc << minexptime << maxexptime << minsize
1675 << maxsize << collisiondetection;
1677 pkt.putLongString(texture);
1679 pkt << id << vertical;
1680 pkt << collision_removal;
1682 // This is horrible but required
1683 std::ostringstream os(std::ios_base::binary);
1684 animation.serialize(os, protocol_version);
1685 pkt.putRawString(os.str());
1687 pkt << object_collision;
1692 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1694 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1696 // Ugly error in this packet
1699 if (peer_id != PEER_ID_INEXISTENT)
1702 m_clients.sendToAll(&pkt);
1706 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1708 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1710 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1711 << form->text << form->number << form->item << form->dir
1712 << form->align << form->offset << form->world_pos << form->size;
1717 void Server::SendHUDRemove(session_t peer_id, u32 id)
1719 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1724 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1726 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1727 pkt << id << (u8) stat;
1731 case HUD_STAT_SCALE:
1732 case HUD_STAT_ALIGN:
1733 case HUD_STAT_OFFSET:
1734 pkt << *(v2f *) value;
1738 pkt << *(std::string *) value;
1740 case HUD_STAT_WORLD_POS:
1741 pkt << *(v3f *) value;
1744 pkt << *(v2s32 *) value;
1746 case HUD_STAT_NUMBER:
1750 pkt << *(u32 *) value;
1757 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1759 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1761 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1763 pkt << flags << mask;
1768 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1770 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1771 pkt << param << value;
1775 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1776 const std::string &type, const std::vector<std::string> ¶ms,
1779 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1780 pkt << bgcolor << type << (u16) params.size();
1782 for (const std::string ¶m : params)
1790 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1792 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1793 pkt << params.density << params.color_bright << params.color_ambient
1794 << params.height << params.thickness << params.speed;
1798 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1801 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1804 pkt << do_override << (u16) (ratio * 65535);
1809 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1811 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1812 pkt << time << time_speed;
1814 if (peer_id == PEER_ID_INEXISTENT) {
1815 m_clients.sendToAll(&pkt);
1822 void Server::SendPlayerHP(session_t peer_id)
1824 PlayerSAO *playersao = getPlayerSAO(peer_id);
1825 // In some rare case if the player is disconnected
1826 // while Lua call l_punch, for example, this can be NULL
1830 SendHP(peer_id, playersao->getHP());
1831 m_script->player_event(playersao,"health_changed");
1833 // Send to other clients
1834 std::string str = gob_cmd_punched(playersao->getHP());
1835 ActiveObjectMessage aom(playersao->getId(), true, str);
1836 playersao->m_messages_out.push(aom);
1839 void Server::SendPlayerBreath(PlayerSAO *sao)
1843 m_script->player_event(sao, "breath_changed");
1844 SendBreath(sao->getPeerID(), sao->getBreath());
1847 void Server::SendMovePlayer(session_t peer_id)
1849 RemotePlayer *player = m_env->getPlayer(peer_id);
1851 PlayerSAO *sao = player->getPlayerSAO();
1854 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1855 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1858 v3f pos = sao->getBasePosition();
1859 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1860 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1861 << " pitch=" << sao->getLookPitch()
1862 << " yaw=" << sao->getRotation().Y
1869 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1870 f32 animation_speed)
1872 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1875 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1876 << animation_frames[3] << animation_speed;
1881 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1883 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1884 pkt << first << third;
1888 void Server::SendPlayerPrivileges(session_t peer_id)
1890 RemotePlayer *player = m_env->getPlayer(peer_id);
1892 if(player->getPeerId() == PEER_ID_INEXISTENT)
1895 std::set<std::string> privs;
1896 m_script->getAuth(player->getName(), NULL, &privs);
1898 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1899 pkt << (u16) privs.size();
1901 for (const std::string &priv : privs) {
1908 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1910 RemotePlayer *player = m_env->getPlayer(peer_id);
1912 if (player->getPeerId() == PEER_ID_INEXISTENT)
1915 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1916 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1920 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1922 RemotePlayer *player = m_env->getPlayer(peer_id);
1924 if (player->getPeerId() == PEER_ID_INEXISTENT)
1927 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1928 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1932 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1934 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1935 pkt.putRawString(datas.c_str(), datas.size());
1937 return pkt.getSize();
1940 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1943 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1944 datas.size(), peer_id);
1946 pkt.putRawString(datas.c_str(), datas.size());
1948 m_clients.send(pkt.getPeerId(),
1949 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1953 void Server::SendCSMRestrictionFlags(session_t peer_id)
1955 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1956 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1957 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1961 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1963 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1968 s32 Server::playSound(const SimpleSoundSpec &spec,
1969 const ServerSoundParams ¶ms)
1971 // Find out initial position of sound
1972 bool pos_exists = false;
1973 v3f pos = params.getPos(m_env, &pos_exists);
1974 // If position is not found while it should be, cancel sound
1975 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1978 // Filter destination clients
1979 std::vector<session_t> dst_clients;
1980 if(!params.to_player.empty()) {
1981 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1983 infostream<<"Server::playSound: Player \""<<params.to_player
1984 <<"\" not found"<<std::endl;
1987 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1988 infostream<<"Server::playSound: Player \""<<params.to_player
1989 <<"\" not connected"<<std::endl;
1992 dst_clients.push_back(player->getPeerId());
1994 std::vector<session_t> clients = m_clients.getClientIDs();
1996 for (const session_t client_id : clients) {
1997 RemotePlayer *player = m_env->getPlayer(client_id);
2001 PlayerSAO *sao = player->getPlayerSAO();
2006 if(sao->getBasePosition().getDistanceFrom(pos) >
2007 params.max_hear_distance)
2010 dst_clients.push_back(client_id);
2014 if(dst_clients.empty())
2018 s32 id = m_next_sound_id++;
2019 // The sound will exist as a reference in m_playing_sounds
2020 m_playing_sounds[id] = ServerPlayingSound();
2021 ServerPlayingSound &psound = m_playing_sounds[id];
2022 psound.params = params;
2025 float gain = params.gain * spec.gain;
2026 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2027 pkt << id << spec.name << gain
2028 << (u8) params.type << pos << params.object
2029 << params.loop << params.fade << params.pitch;
2031 // Backwards compability
2032 bool play_sound = gain > 0;
2034 for (const u16 dst_client : dst_clients) {
2035 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2036 psound.clients.insert(dst_client);
2037 m_clients.send(dst_client, 0, &pkt, true);
2042 void Server::stopSound(s32 handle)
2044 // Get sound reference
2045 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2046 m_playing_sounds.find(handle);
2047 if (i == m_playing_sounds.end())
2049 ServerPlayingSound &psound = i->second;
2051 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2054 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2055 si != psound.clients.end(); ++si) {
2057 m_clients.send(*si, 0, &pkt, true);
2059 // Remove sound reference
2060 m_playing_sounds.erase(i);
2063 void Server::fadeSound(s32 handle, float step, float gain)
2065 // Get sound reference
2066 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2067 m_playing_sounds.find(handle);
2068 if (i == m_playing_sounds.end())
2071 ServerPlayingSound &psound = i->second;
2072 psound.params.gain = gain;
2074 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2075 pkt << handle << step << gain;
2077 // Backwards compability
2078 bool play_sound = gain > 0;
2079 ServerPlayingSound compat_psound = psound;
2080 compat_psound.clients.clear();
2082 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2083 compat_pkt << handle;
2085 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2086 it != psound.clients.end();) {
2087 if (m_clients.getProtocolVersion(*it) >= 32) {
2089 m_clients.send(*it, 0, &pkt, true);
2092 compat_psound.clients.insert(*it);
2094 m_clients.send(*it, 0, &compat_pkt, true);
2095 psound.clients.erase(it++);
2099 // Remove sound reference
2100 if (!play_sound || psound.clients.empty())
2101 m_playing_sounds.erase(i);
2103 if (play_sound && !compat_psound.clients.empty()) {
2104 // Play new sound volume on older clients
2105 playSound(compat_psound.spec, compat_psound.params);
2109 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2112 float maxd = far_d_nodes * BS;
2113 v3f p_f = intToFloat(p, BS);
2114 v3s16 block_pos = getNodeBlockPos(p);
2116 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2119 std::vector<session_t> clients = m_clients.getClientIDs();
2122 for (session_t client_id : clients) {
2123 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2127 RemotePlayer *player = m_env->getPlayer(client_id);
2128 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2130 // If player is far away, only set modified blocks not sent
2131 if (!client->isBlockSent(block_pos) || (sao &&
2132 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2134 far_players->emplace(client_id);
2136 client->SetBlockNotSent(block_pos);
2141 m_clients.send(client_id, 0, &pkt, true);
2147 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2148 float far_d_nodes, bool remove_metadata)
2150 float maxd = far_d_nodes * BS;
2151 v3f p_f = intToFloat(p, BS);
2152 v3s16 block_pos = getNodeBlockPos(p);
2154 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2155 pkt << p << n.param0 << n.param1 << n.param2
2156 << (u8) (remove_metadata ? 0 : 1);
2158 std::vector<session_t> clients = m_clients.getClientIDs();
2161 for (session_t client_id : clients) {
2162 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2166 RemotePlayer *player = m_env->getPlayer(client_id);
2167 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2169 // If player is far away, only set modified blocks not sent
2170 if (!client->isBlockSent(block_pos) || (sao &&
2171 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2173 far_players->emplace(client_id);
2175 client->SetBlockNotSent(block_pos);
2180 m_clients.send(client_id, 0, &pkt, true);
2186 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2188 float maxd = far_d_nodes * BS;
2189 NodeMetadataList meta_updates_list(false);
2190 std::vector<session_t> clients = m_clients.getClientIDs();
2194 for (session_t i : clients) {
2195 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2199 ServerActiveObject *player = m_env->getActiveObject(i);
2200 v3f player_pos = player ? player->getBasePosition() : v3f();
2202 for (const v3s16 &pos : meta_updates) {
2203 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2208 v3s16 block_pos = getNodeBlockPos(pos);
2209 if (!client->isBlockSent(block_pos) || (player &&
2210 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2211 client->SetBlockNotSent(block_pos);
2215 // Add the change to send list
2216 meta_updates_list.set(pos, meta);
2218 if (meta_updates_list.size() == 0)
2221 // Send the meta changes
2222 std::ostringstream os(std::ios::binary);
2223 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2224 std::ostringstream oss(std::ios::binary);
2225 compressZlib(os.str(), oss);
2227 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2228 pkt.putLongString(oss.str());
2229 m_clients.send(i, 0, &pkt, true);
2231 meta_updates_list.clear();
2237 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2238 u16 net_proto_version)
2241 Create a packet with the block in the right format
2244 std::ostringstream os(std::ios_base::binary);
2245 block->serialize(os, ver, false);
2246 block->serializeNetworkSpecific(os);
2247 std::string s = os.str();
2249 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2251 pkt << block->getPos();
2252 pkt.putRawString(s.c_str(), s.size());
2256 void Server::SendBlocks(float dtime)
2258 MutexAutoLock envlock(m_env_mutex);
2259 //TODO check if one big lock could be faster then multiple small ones
2261 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2263 std::vector<PrioritySortedBlockTransfer> queue;
2265 u32 total_sending = 0;
2268 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2270 std::vector<session_t> clients = m_clients.getClientIDs();
2273 for (const session_t client_id : clients) {
2274 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2279 total_sending += client->getSendingCount();
2280 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2286 // Lowest priority number comes first.
2287 // Lowest is most important.
2288 std::sort(queue.begin(), queue.end());
2292 // Maximal total count calculation
2293 // The per-client block sends is halved with the maximal online users
2294 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2295 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2297 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2298 if (total_sending >= max_blocks_to_send)
2301 MapBlock *block = nullptr;
2303 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2304 } catch (const InvalidPositionException &e) {
2308 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2313 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2314 client->net_proto_version);
2316 client->SentBlock(block_to_send.pos);
2322 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2324 MapBlock *block = nullptr;
2326 block = m_env->getMap().getBlockNoCreate(blockpos);
2327 } catch (InvalidPositionException &e) {};
2332 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2333 if (!client || client->isBlockSent(blockpos)) {
2337 SendBlockNoLock(peer_id, block, client->serialization_version,
2338 client->net_proto_version);
2344 void Server::fillMediaCache()
2346 infostream<<"Server: Calculating media file checksums"<<std::endl;
2348 // Collect all media file paths
2349 std::vector<std::string> paths;
2350 m_modmgr->getModsMediaPaths(paths);
2351 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2352 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2354 // Collect media file information from paths into cache
2355 for (const std::string &mediapath : paths) {
2356 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2357 for (const fs::DirListNode &dln : dirlist) {
2358 if (dln.dir) // Ignode dirs
2360 std::string filename = dln.name;
2361 // If name contains illegal characters, ignore the file
2362 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2363 infostream<<"Server: ignoring illegal file name: \""
2364 << filename << "\"" << std::endl;
2367 // If name is not in a supported format, ignore it
2368 const char *supported_ext[] = {
2369 ".png", ".jpg", ".bmp", ".tga",
2370 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2372 ".x", ".b3d", ".md2", ".obj",
2373 // Custom translation file format
2377 if (removeStringEnd(filename, supported_ext).empty()){
2378 infostream << "Server: ignoring unsupported file extension: \""
2379 << filename << "\"" << std::endl;
2382 // Ok, attempt to load the file and add to cache
2383 std::string filepath;
2384 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2387 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2389 errorstream << "Server::fillMediaCache(): Could not open \""
2390 << filename << "\" for reading" << std::endl;
2393 std::ostringstream tmp_os(std::ios_base::binary);
2397 fis.read(buf, 1024);
2398 std::streamsize len = fis.gcount();
2399 tmp_os.write(buf, len);
2408 errorstream<<"Server::fillMediaCache(): Failed to read \""
2409 << filename << "\"" << std::endl;
2412 if(tmp_os.str().length() == 0) {
2413 errorstream << "Server::fillMediaCache(): Empty file \""
2414 << filepath << "\"" << std::endl;
2419 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2421 unsigned char *digest = sha1.getDigest();
2422 std::string sha1_base64 = base64_encode(digest, 20);
2423 std::string sha1_hex = hex_encode((char*)digest, 20);
2427 m_media[filename] = MediaInfo(filepath, sha1_base64);
2428 verbosestream << "Server: " << sha1_hex << " is " << filename
2434 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2436 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2440 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2443 std::string lang_suffix;
2444 lang_suffix.append(".").append(lang_code).append(".tr");
2445 for (const auto &i : m_media) {
2446 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2453 for (const auto &i : m_media) {
2454 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2456 pkt << i.first << i.second.sha1_digest;
2459 pkt << g_settings->get("remote_media");
2463 struct SendableMedia
2469 SendableMedia(const std::string &name_="", const std::string &path_="",
2470 const std::string &data_=""):
2477 void Server::sendRequestedMedia(session_t peer_id,
2478 const std::vector<std::string> &tosend)
2480 verbosestream<<"Server::sendRequestedMedia(): "
2481 <<"Sending files to client"<<std::endl;
2485 // Put 5kB in one bunch (this is not accurate)
2486 u32 bytes_per_bunch = 5000;
2488 std::vector< std::vector<SendableMedia> > file_bunches;
2489 file_bunches.emplace_back();
2491 u32 file_size_bunch_total = 0;
2493 for (const std::string &name : tosend) {
2494 if (m_media.find(name) == m_media.end()) {
2495 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2496 <<"unknown file \""<<(name)<<"\""<<std::endl;
2500 //TODO get path + name
2501 std::string tpath = m_media[name].path;
2504 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2506 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2507 <<tpath<<"\" for reading"<<std::endl;
2510 std::ostringstream tmp_os(std::ios_base::binary);
2514 fis.read(buf, 1024);
2515 std::streamsize len = fis.gcount();
2516 tmp_os.write(buf, len);
2517 file_size_bunch_total += len;
2526 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2527 <<name<<"\""<<std::endl;
2530 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2531 <<tname<<"\""<<std::endl;*/
2533 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2535 // Start next bunch if got enough data
2536 if(file_size_bunch_total >= bytes_per_bunch) {
2537 file_bunches.emplace_back();
2538 file_size_bunch_total = 0;
2543 /* Create and send packets */
2545 u16 num_bunches = file_bunches.size();
2546 for (u16 i = 0; i < num_bunches; i++) {
2549 u16 total number of texture bunches
2550 u16 index of this bunch
2551 u32 number of files in this bunch
2560 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2561 pkt << num_bunches << i << (u32) file_bunches[i].size();
2563 for (const SendableMedia &j : file_bunches[i]) {
2565 pkt.putLongString(j.data);
2568 verbosestream << "Server::sendRequestedMedia(): bunch "
2569 << i << "/" << num_bunches
2570 << " files=" << file_bunches[i].size()
2571 << " size=" << pkt.getSize() << std::endl;
2576 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2578 const auto &inv_it = m_detached_inventories.find(name);
2579 const auto &player_it = m_detached_inventories_player.find(name);
2581 if (player_it == m_detached_inventories_player.end() ||
2582 player_it->second.empty()) {
2583 // OK. Send to everyone
2585 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2587 return; // Player is offline
2589 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2590 return; // Caller requested send to a different player, so don't send.
2592 peer_id = p->getPeerId();
2595 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2598 if (inv_it == m_detached_inventories.end()) {
2599 pkt << false; // Remove inventory
2601 pkt << true; // Update inventory
2603 // Serialization & NetworkPacket isn't a love story
2604 std::ostringstream os(std::ios_base::binary);
2605 inv_it->second->serialize(os);
2607 std::string os_str = os.str();
2608 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2609 pkt.putRawString(os_str);
2612 if (peer_id == PEER_ID_INEXISTENT)
2613 m_clients.sendToAll(&pkt);
2618 void Server::sendDetachedInventories(session_t peer_id)
2620 for (const auto &detached_inventory : m_detached_inventories) {
2621 const std::string &name = detached_inventory.first;
2622 //Inventory *inv = i->second;
2623 sendDetachedInventory(name, peer_id);
2631 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2633 PlayerSAO *playersao = getPlayerSAO(peer_id);
2634 // In some rare cases this can be NULL -- if the player is disconnected
2635 // when a Lua function modifies l_punch, for example
2639 infostream << "Server::DiePlayer(): Player "
2640 << playersao->getPlayer()->getName()
2641 << " dies" << std::endl;
2643 playersao->setHP(0, reason);
2644 playersao->clearParentAttachment();
2646 // Trigger scripted stuff
2647 m_script->on_dieplayer(playersao, reason);
2649 SendPlayerHP(peer_id);
2650 SendDeathscreen(peer_id, false, v3f(0,0,0));
2653 void Server::RespawnPlayer(session_t peer_id)
2655 PlayerSAO *playersao = getPlayerSAO(peer_id);
2658 infostream << "Server::RespawnPlayer(): Player "
2659 << playersao->getPlayer()->getName()
2660 << " respawns" << std::endl;
2662 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2663 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2664 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2666 bool repositioned = m_script->on_respawnplayer(playersao);
2667 if (!repositioned) {
2668 // setPos will send the new position to client
2669 playersao->setPos(findSpawnPos());
2672 SendPlayerHP(peer_id);
2676 void Server::DenySudoAccess(session_t peer_id)
2678 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2683 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2684 const std::string &str_reason, bool reconnect)
2686 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2688 m_clients.event(peer_id, CSE_SetDenied);
2689 DisconnectPeer(peer_id);
2693 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2694 const std::string &custom_reason)
2696 SendAccessDenied(peer_id, reason, custom_reason);
2697 m_clients.event(peer_id, CSE_SetDenied);
2698 DisconnectPeer(peer_id);
2701 // 13/03/15: remove this function when protocol version 25 will become
2702 // the minimum version for MT users, maybe in 1 year
2703 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2705 SendAccessDenied_Legacy(peer_id, reason);
2706 m_clients.event(peer_id, CSE_SetDenied);
2707 DisconnectPeer(peer_id);
2710 void Server::DisconnectPeer(session_t peer_id)
2712 m_modchannel_mgr->leaveAllChannels(peer_id);
2713 m_con->DisconnectPeer(peer_id);
2716 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2719 RemoteClient* client = getClient(peer_id, CS_Invalid);
2721 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2723 // Right now, the auth mechs don't change between login and sudo mode.
2724 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2725 client->allowed_sudo_mechs = sudo_auth_mechs;
2727 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2728 << g_settings->getFloat("dedicated_server_step")
2732 m_clients.event(peer_id, CSE_AuthAccept);
2734 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2736 // We only support SRP right now
2737 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2739 resp_pkt << sudo_auth_mechs;
2741 m_clients.event(peer_id, CSE_SudoSuccess);
2745 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2747 std::wstring message;
2750 Clear references to playing sounds
2752 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2753 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2754 ServerPlayingSound &psound = i->second;
2755 psound.clients.erase(peer_id);
2756 if (psound.clients.empty())
2757 m_playing_sounds.erase(i++);
2762 // clear formspec info so the next client can't abuse the current state
2763 m_formspec_state_data.erase(peer_id);
2765 RemotePlayer *player = m_env->getPlayer(peer_id);
2767 /* Run scripts and remove from environment */
2769 PlayerSAO *playersao = player->getPlayerSAO();
2772 playersao->clearChildAttachments();
2773 playersao->clearParentAttachment();
2775 // inform connected clients
2776 const std::string &player_name = player->getName();
2777 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2778 // (u16) 1 + std::string represents a vector serialization representation
2779 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2780 m_clients.sendToAll(¬ice);
2782 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2784 playersao->disconnected();
2791 if (player && reason != CDR_DENY) {
2792 std::ostringstream os(std::ios_base::binary);
2793 std::vector<session_t> clients = m_clients.getClientIDs();
2795 for (const session_t client_id : clients) {
2797 RemotePlayer *player = m_env->getPlayer(client_id);
2801 // Get name of player
2802 os << player->getName() << " ";
2805 std::string name = player->getName();
2806 actionstream << name << " "
2807 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2808 << " List of players: " << os.str() << std::endl;
2810 m_admin_chat->outgoing_queue.push_back(
2811 new ChatEventNick(CET_NICK_REMOVE, name));
2815 MutexAutoLock env_lock(m_env_mutex);
2816 m_clients.DeleteClient(peer_id);
2820 // Send leave chat message to all remaining clients
2821 if (!message.empty()) {
2822 SendChatMessage(PEER_ID_INEXISTENT,
2823 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2827 void Server::UpdateCrafting(RemotePlayer *player)
2829 InventoryList *clist = player->inventory.getList("craft");
2830 if (!clist || clist->getSize() == 0)
2833 // Get a preview for crafting
2835 InventoryLocation loc;
2836 loc.setPlayer(player->getName());
2837 std::vector<ItemStack> output_replacements;
2838 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2839 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2842 InventoryList *plist = player->inventory.getList("craftpreview");
2843 if (plist && plist->getSize() >= 1) {
2844 // Put the new preview in
2845 plist->changeItem(0, preview);
2849 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2851 if (evt->type == CET_NICK_ADD) {
2852 // The terminal informed us of its nick choice
2853 m_admin_nick = ((ChatEventNick *)evt)->nick;
2854 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2855 errorstream << "You haven't set up an account." << std::endl
2856 << "Please log in using the client as '"
2857 << m_admin_nick << "' with a secure password." << std::endl
2858 << "Until then, you can't execute admin tasks via the console," << std::endl
2859 << "and everybody can claim the user account instead of you," << std::endl
2860 << "giving them full control over this server." << std::endl;
2863 assert(evt->type == CET_CHAT);
2864 handleAdminChat((ChatEventChat *)evt);
2868 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2869 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2871 // If something goes wrong, this player is to blame
2872 RollbackScopeActor rollback_scope(m_rollback,
2873 std::string("player:") + name);
2875 if (g_settings->getBool("strip_color_codes"))
2876 wmessage = unescape_enriched(wmessage);
2879 switch (player->canSendChatMessage()) {
2880 case RPLAYER_CHATRESULT_FLOODING: {
2881 std::wstringstream ws;
2882 ws << L"You cannot send more messages. You are limited to "
2883 << g_settings->getFloat("chat_message_limit_per_10sec")
2884 << L" messages per 10 seconds.";
2887 case RPLAYER_CHATRESULT_KICK:
2888 DenyAccess_Legacy(player->getPeerId(),
2889 L"You have been kicked due to message flooding.");
2891 case RPLAYER_CHATRESULT_OK:
2894 FATAL_ERROR("Unhandled chat filtering result found.");
2898 if (m_max_chatmessage_length > 0
2899 && wmessage.length() > m_max_chatmessage_length) {
2900 return L"Your message exceed the maximum chat message limit set on the server. "
2901 L"It was refused. Send a shorter message";
2904 auto message = trim(wide_to_utf8(wmessage));
2905 if (message.find_first_of("\n\r") != std::wstring::npos) {
2906 return L"New lines are not permitted in chat messages";
2909 // Run script hook, exit if script ate the chat message
2910 if (m_script->on_chat_message(name, message))
2915 // Whether to send line to the player that sent the message, or to all players
2916 bool broadcast_line = true;
2918 if (check_shout_priv && !checkPriv(name, "shout")) {
2919 line += L"-!- You don't have permission to shout.";
2920 broadcast_line = false;
2922 line += narrow_to_wide(m_script->formatChatMessage(name,
2923 wide_to_narrow(wmessage)));
2927 Tell calling method to send the message to sender
2929 if (!broadcast_line)
2933 Send the message to others
2935 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2937 std::vector<session_t> clients = m_clients.getClientIDs();
2940 Send the message back to the inital sender
2941 if they are using protocol version >= 29
2944 session_t peer_id_to_avoid_sending =
2945 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2947 if (player && player->protocol_version >= 29)
2948 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2950 for (u16 cid : clients) {
2951 if (cid != peer_id_to_avoid_sending)
2952 SendChatMessage(cid, ChatMessage(line));
2957 void Server::handleAdminChat(const ChatEventChat *evt)
2959 std::string name = evt->nick;
2960 std::wstring wname = utf8_to_wide(name);
2961 std::wstring wmessage = evt->evt_msg;
2963 std::wstring answer = handleChat(name, wname, wmessage);
2965 // If asked to send answer to sender
2966 if (!answer.empty()) {
2967 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2971 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2973 RemoteClient *client = getClientNoEx(peer_id,state_min);
2975 throw ClientNotFoundException("Client not found");
2979 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2981 return m_clients.getClientNoEx(peer_id, state_min);
2984 std::string Server::getPlayerName(session_t peer_id)
2986 RemotePlayer *player = m_env->getPlayer(peer_id);
2988 return "[id="+itos(peer_id)+"]";
2989 return player->getName();
2992 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2994 RemotePlayer *player = m_env->getPlayer(peer_id);
2997 return player->getPlayerSAO();
3000 std::wstring Server::getStatusString()
3002 std::wostringstream os(std::ios_base::binary);
3003 os << L"# Server: ";
3005 os << L"version=" << narrow_to_wide(g_version_string);
3007 os << L", uptime=" << m_uptime.get();
3009 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3011 // Information about clients
3013 os << L", clients={";
3015 std::vector<session_t> clients = m_clients.getClientIDs();
3016 for (session_t client_id : clients) {
3017 RemotePlayer *player = m_env->getPlayer(client_id);
3019 // Get name of player
3020 std::wstring name = L"unknown";
3022 name = narrow_to_wide(player->getName());
3024 // Add name to information string
3035 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3036 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3038 if (!g_settings->get("motd").empty())
3039 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3044 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3046 std::set<std::string> privs;
3047 m_script->getAuth(name, NULL, &privs);
3051 bool Server::checkPriv(const std::string &name, const std::string &priv)
3053 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3054 return (privs.count(priv) != 0);
3057 void Server::reportPrivsModified(const std::string &name)
3060 std::vector<session_t> clients = m_clients.getClientIDs();
3061 for (const session_t client_id : clients) {
3062 RemotePlayer *player = m_env->getPlayer(client_id);
3063 reportPrivsModified(player->getName());
3066 RemotePlayer *player = m_env->getPlayer(name.c_str());
3069 SendPlayerPrivileges(player->getPeerId());
3070 PlayerSAO *sao = player->getPlayerSAO();
3073 sao->updatePrivileges(
3074 getPlayerEffectivePrivs(name),
3079 void Server::reportInventoryFormspecModified(const std::string &name)
3081 RemotePlayer *player = m_env->getPlayer(name.c_str());
3084 SendPlayerInventoryFormspec(player->getPeerId());
3087 void Server::reportFormspecPrependModified(const std::string &name)
3089 RemotePlayer *player = m_env->getPlayer(name.c_str());
3092 SendPlayerFormspecPrepend(player->getPeerId());
3095 void Server::setIpBanned(const std::string &ip, const std::string &name)
3097 m_banmanager->add(ip, name);
3100 void Server::unsetIpBanned(const std::string &ip_or_name)
3102 m_banmanager->remove(ip_or_name);
3105 std::string Server::getBanDescription(const std::string &ip_or_name)
3107 return m_banmanager->getBanDescription(ip_or_name);
3110 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3112 // m_env will be NULL if the server is initializing
3116 if (m_admin_nick == name && !m_admin_nick.empty()) {
3117 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3120 RemotePlayer *player = m_env->getPlayer(name);
3125 if (player->getPeerId() == PEER_ID_INEXISTENT)
3128 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3131 bool Server::showFormspec(const char *playername, const std::string &formspec,
3132 const std::string &formname)
3134 // m_env will be NULL if the server is initializing
3138 RemotePlayer *player = m_env->getPlayer(playername);
3142 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3146 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3151 u32 id = player->addHud(form);
3153 SendHUDAdd(player->getPeerId(), id, form);
3158 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3162 HudElement* todel = player->removeHud(id);
3169 SendHUDRemove(player->getPeerId(), id);
3173 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3178 SendHUDChange(player->getPeerId(), id, stat, data);
3182 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3187 SendHUDSetFlags(player->getPeerId(), flags, mask);
3188 player->hud_flags &= ~mask;
3189 player->hud_flags |= flags;
3191 PlayerSAO* playersao = player->getPlayerSAO();
3196 m_script->player_event(playersao, "hud_changed");
3200 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3205 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3208 player->setHotbarItemcount(hotbar_itemcount);
3209 std::ostringstream os(std::ios::binary);
3210 writeS32(os, hotbar_itemcount);
3211 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3215 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3220 player->setHotbarImage(name);
3221 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3224 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3229 player->setHotbarSelectedImage(name);
3230 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3233 Address Server::getPeerAddress(session_t peer_id)
3235 return m_con->GetPeerAddress(peer_id);
3238 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3239 v2s32 animation_frames[4], f32 frame_speed)
3241 sanity_check(player);
3242 player->setLocalAnimations(animation_frames, frame_speed);
3243 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3246 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3248 sanity_check(player);
3249 player->eye_offset_first = first;
3250 player->eye_offset_third = third;
3251 SendEyeOffset(player->getPeerId(), first, third);
3254 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3255 const std::string &type, const std::vector<std::string> ¶ms,
3258 sanity_check(player);
3259 player->setSky(bgcolor, type, params, clouds);
3260 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3263 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3265 sanity_check(player);
3266 player->setCloudParams(params);
3267 SendCloudParams(player->getPeerId(), params);
3270 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3276 player->overrideDayNightRatio(do_override, ratio);
3277 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3281 void Server::notifyPlayers(const std::wstring &msg)
3283 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3286 void Server::spawnParticle(const std::string &playername, v3f pos,
3287 v3f velocity, v3f acceleration,
3288 float expirationtime, float size, bool
3289 collisiondetection, bool collision_removal, bool object_collision,
3290 bool vertical, const std::string &texture,
3291 const struct TileAnimationParams &animation, u8 glow)
3293 // m_env will be NULL if the server is initializing
3297 session_t peer_id = PEER_ID_INEXISTENT;
3299 if (!playername.empty()) {
3300 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3303 peer_id = player->getPeerId();
3304 proto_ver = player->protocol_version;
3307 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3308 expirationtime, size, collisiondetection, collision_removal,
3309 object_collision, vertical, texture, animation, glow);
3312 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3313 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3314 float minexptime, float maxexptime, float minsize, float maxsize,
3315 bool collisiondetection, bool collision_removal, bool object_collision,
3316 ServerActiveObject *attached, bool vertical, const std::string &texture,
3317 const std::string &playername, const struct TileAnimationParams &animation,
3320 // m_env will be NULL if the server is initializing
3324 session_t peer_id = PEER_ID_INEXISTENT;
3326 if (!playername.empty()) {
3327 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3330 peer_id = player->getPeerId();
3331 proto_ver = player->protocol_version;
3334 u16 attached_id = attached ? attached->getId() : 0;
3337 if (attached_id == 0)
3338 id = m_env->addParticleSpawner(spawntime);
3340 id = m_env->addParticleSpawner(spawntime, attached_id);
3342 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3343 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3344 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3345 collision_removal, object_collision, attached_id, vertical,
3346 texture, id, animation, glow);
3351 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3353 // m_env will be NULL if the server is initializing
3355 throw ServerError("Can't delete particle spawners during initialisation!");
3357 session_t peer_id = PEER_ID_INEXISTENT;
3358 if (!playername.empty()) {
3359 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3362 peer_id = player->getPeerId();
3365 m_env->deleteParticleSpawner(id);
3366 SendDeleteParticleSpawner(peer_id, id);
3369 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3371 if(m_detached_inventories.count(name) > 0){
3372 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3373 delete m_detached_inventories[name];
3375 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3377 Inventory *inv = new Inventory(m_itemdef);
3379 m_detached_inventories[name] = inv;
3380 m_detached_inventories_player[name] = player;
3381 //TODO find a better way to do this
3382 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3386 bool Server::removeDetachedInventory(const std::string &name)
3388 const auto &inv_it = m_detached_inventories.find(name);
3389 if (inv_it == m_detached_inventories.end())
3392 delete inv_it->second;
3393 m_detached_inventories.erase(inv_it);
3395 const auto &player_it = m_detached_inventories_player.find(name);
3396 if (player_it != m_detached_inventories_player.end()) {
3397 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3399 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3400 sendDetachedInventory(name, player->getPeerId());
3402 m_detached_inventories_player.erase(player_it);
3404 // Notify all players about the change
3405 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3410 // actions: time-reversed list
3411 // Return value: success/failure
3412 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3413 std::list<std::string> *log)
3415 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3416 ServerMap *map = (ServerMap*)(&m_env->getMap());
3418 // Fail if no actions to handle
3419 if (actions.empty()) {
3421 log->push_back("Nothing to do.");
3428 for (const RollbackAction &action : actions) {
3430 bool success = action.applyRevert(map, this, this);
3433 std::ostringstream os;
3434 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3435 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3437 log->push_back(os.str());
3439 std::ostringstream os;
3440 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3441 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3443 log->push_back(os.str());
3447 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3448 <<" failed"<<std::endl;
3450 // Call it done if less than half failed
3451 return num_failed <= num_tried/2;
3454 // IGameDef interface
3456 IItemDefManager *Server::getItemDefManager()
3461 const NodeDefManager *Server::getNodeDefManager()
3466 ICraftDefManager *Server::getCraftDefManager()
3471 u16 Server::allocateUnknownNodeId(const std::string &name)
3473 return m_nodedef->allocateDummy(name);
3476 IWritableItemDefManager *Server::getWritableItemDefManager()
3481 NodeDefManager *Server::getWritableNodeDefManager()
3486 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3491 const std::vector<ModSpec> & Server::getMods() const
3493 return m_modmgr->getMods();
3496 const ModSpec *Server::getModSpec(const std::string &modname) const
3498 return m_modmgr->getModSpec(modname);
3501 void Server::getModNames(std::vector<std::string> &modlist)
3503 m_modmgr->getModNames(modlist);
3506 std::string Server::getBuiltinLuaPath()
3508 return porting::path_share + DIR_DELIM + "builtin";
3511 std::string Server::getModStoragePath() const
3513 return m_path_world + DIR_DELIM + "mod_storage";
3516 v3f Server::findSpawnPos()
3518 ServerMap &map = m_env->getServerMap();
3520 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3521 return nodeposf * BS;
3523 bool is_good = false;
3524 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3525 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3527 // Try to find a good place a few times
3528 for (s32 i = 0; i < 4000 && !is_good; i++) {
3529 s32 range = MYMIN(1 + i, range_max);
3530 // We're going to try to throw the player to this position
3531 v2s16 nodepos2d = v2s16(
3532 -range + (myrand() % (range * 2)),
3533 -range + (myrand() % (range * 2)));
3534 // Get spawn level at point
3535 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3536 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3537 // signify an unsuitable spawn position, or if outside limits.
3538 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3539 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3542 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3543 // Consecutive empty nodes
3546 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3547 // avoid obstructions in already-generated mapblocks.
3548 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3549 // no obstructions, but mapgen decorations are generated after spawn so
3550 // the player may end up inside one.
3551 for (s32 i = 0; i < 8; i++) {
3552 v3s16 blockpos = getNodeBlockPos(nodepos);
3553 map.emergeBlock(blockpos, true);
3554 content_t c = map.getNode(nodepos).getContent();
3556 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3557 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3558 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3560 if (air_count >= 2) {
3561 // Spawn in lower empty node
3563 nodeposf = intToFloat(nodepos, BS);
3564 // Don't spawn the player outside map boundaries
3565 if (objectpos_over_limit(nodeposf))
3566 // Exit this loop, positions above are probably over limit
3569 // Good position found, cause an exit from main loop
3583 // No suitable spawn point found, return fallback 0,0,0
3584 return v3f(0.0f, 0.0f, 0.0f);
3587 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3589 if (delay == 0.0f) {
3590 // No delay, shutdown immediately
3591 m_shutdown_state.is_requested = true;
3592 // only print to the infostream, a chat message saying
3593 // "Server Shutting Down" is sent when the server destructs.
3594 infostream << "*** Immediate Server shutdown requested." << std::endl;
3595 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3596 // Negative delay, cancel shutdown if requested
3597 m_shutdown_state.reset();
3598 std::wstringstream ws;
3600 ws << L"*** Server shutdown canceled.";
3602 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3603 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3604 // m_shutdown_* are already handled, skip.
3606 } else if (delay > 0.0f) {
3607 // Positive delay, tell the clients when the server will shut down
3608 std::wstringstream ws;
3610 ws << L"*** Server shutting down in "
3611 << duration_to_string(myround(delay)).c_str()
3614 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3615 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3618 m_shutdown_state.trigger(delay, msg, reconnect);
3621 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3624 Try to get an existing player
3626 RemotePlayer *player = m_env->getPlayer(name);
3628 // If player is already connected, cancel
3629 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3630 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3635 If player with the wanted peer_id already exists, cancel.
3637 if (m_env->getPlayer(peer_id)) {
3638 infostream<<"emergePlayer(): Player with wrong name but same"
3639 " peer_id already exists"<<std::endl;
3644 player = new RemotePlayer(name, idef());
3647 bool newplayer = false;
3650 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3652 // Complete init with server parts
3653 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3654 player->protocol_version = proto_version;
3658 m_script->on_newplayer(playersao);
3664 bool Server::registerModStorage(ModMetadata *storage)
3666 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3667 errorstream << "Unable to register same mod storage twice. Storage name: "
3668 << storage->getModName() << std::endl;
3672 m_mod_storages[storage->getModName()] = storage;
3676 void Server::unregisterModStorage(const std::string &name)
3678 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3679 if (it != m_mod_storages.end()) {
3680 // Save unconditionaly on unregistration
3681 it->second->save(getModStoragePath());
3682 m_mod_storages.erase(name);
3686 void dedicated_server_loop(Server &server, bool &kill)
3688 verbosestream<<"dedicated_server_loop()"<<std::endl;
3690 IntervalLimiter m_profiler_interval;
3692 static thread_local const float steplen =
3693 g_settings->getFloat("dedicated_server_step");
3694 static thread_local const float profiler_print_interval =
3695 g_settings->getFloat("profiler_print_interval");
3698 // This is kind of a hack but can be done like this
3699 // because server.step() is very light
3701 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3702 sleep_ms((int)(steplen*1000.0));
3704 server.step(steplen);
3706 if (server.isShutdownRequested() || kill)
3712 if (profiler_print_interval != 0) {
3713 if(m_profiler_interval.step(steplen, profiler_print_interval))
3715 infostream<<"Profiler:"<<std::endl;
3716 g_profiler->print(infostream);
3717 g_profiler->clear();
3722 infostream << "Dedicated server quitting" << std::endl;
3724 if (g_settings->getBool("server_announce"))
3725 ServerList::sendAnnounce(ServerList::AA_DELETE,
3726 server.m_bind_addr.getPort());
3735 bool Server::joinModChannel(const std::string &channel)
3737 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3738 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3741 bool Server::leaveModChannel(const std::string &channel)
3743 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3746 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3748 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3751 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3755 ModChannel* Server::getModChannel(const std::string &channel)
3757 return m_modchannel_mgr->getModChannel(channel);
3760 void Server::broadcastModChannelMessage(const std::string &channel,
3761 const std::string &message, session_t from_peer)
3763 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3767 if (message.size() > STRING_MAX_LEN) {
3768 warningstream << "ModChannel message too long, dropping before sending "
3769 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3770 << channel << ")" << std::endl;
3775 if (from_peer != PEER_ID_SERVER) {
3776 sender = getPlayerName(from_peer);
3779 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3780 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3781 resp_pkt << channel << sender << message;
3782 for (session_t peer_id : peers) {
3784 if (peer_id == from_peer)
3787 Send(peer_id, &resp_pkt);
3790 if (from_peer != PEER_ID_SERVER) {
3791 m_script->on_modchannel_message(channel, sender, message);