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 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<session_t> dst_clients;
1973 if(!params.to_player.empty()) {
1974 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1976 infostream<<"Server::playSound: Player \""<<params.to_player
1977 <<"\" not found"<<std::endl;
1980 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1981 infostream<<"Server::playSound: Player \""<<params.to_player
1982 <<"\" not connected"<<std::endl;
1985 dst_clients.push_back(player->getPeerId());
1987 std::vector<session_t> clients = m_clients.getClientIDs();
1989 for (const session_t client_id : clients) {
1990 RemotePlayer *player = m_env->getPlayer(client_id);
1994 PlayerSAO *sao = player->getPlayerSAO();
1999 if(sao->getBasePosition().getDistanceFrom(pos) >
2000 params.max_hear_distance)
2003 dst_clients.push_back(client_id);
2007 if(dst_clients.empty())
2011 s32 id = m_next_sound_id++;
2012 // The sound will exist as a reference in m_playing_sounds
2013 m_playing_sounds[id] = ServerPlayingSound();
2014 ServerPlayingSound &psound = m_playing_sounds[id];
2015 psound.params = params;
2018 float gain = params.gain * spec.gain;
2019 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2020 pkt << id << spec.name << gain
2021 << (u8) params.type << pos << params.object
2022 << params.loop << params.fade << params.pitch;
2024 // Backwards compability
2025 bool play_sound = gain > 0;
2027 for (const u16 dst_client : dst_clients) {
2028 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2029 psound.clients.insert(dst_client);
2030 m_clients.send(dst_client, 0, &pkt, true);
2035 void Server::stopSound(s32 handle)
2037 // Get sound reference
2038 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2039 m_playing_sounds.find(handle);
2040 if (i == m_playing_sounds.end())
2042 ServerPlayingSound &psound = i->second;
2044 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2047 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2048 si != psound.clients.end(); ++si) {
2050 m_clients.send(*si, 0, &pkt, true);
2052 // Remove sound reference
2053 m_playing_sounds.erase(i);
2056 void Server::fadeSound(s32 handle, float step, float gain)
2058 // Get sound reference
2059 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2060 m_playing_sounds.find(handle);
2061 if (i == m_playing_sounds.end())
2064 ServerPlayingSound &psound = i->second;
2065 psound.params.gain = gain;
2067 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2068 pkt << handle << step << gain;
2070 // Backwards compability
2071 bool play_sound = gain > 0;
2072 ServerPlayingSound compat_psound = psound;
2073 compat_psound.clients.clear();
2075 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2076 compat_pkt << handle;
2078 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2079 it != psound.clients.end();) {
2080 if (m_clients.getProtocolVersion(*it) >= 32) {
2082 m_clients.send(*it, 0, &pkt, true);
2085 compat_psound.clients.insert(*it);
2087 m_clients.send(*it, 0, &compat_pkt, true);
2088 psound.clients.erase(it++);
2092 // Remove sound reference
2093 if (!play_sound || psound.clients.empty())
2094 m_playing_sounds.erase(i);
2096 if (play_sound && !compat_psound.clients.empty()) {
2097 // Play new sound volume on older clients
2098 playSound(compat_psound.spec, compat_psound.params);
2102 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2105 float maxd = far_d_nodes * BS;
2106 v3f p_f = intToFloat(p, BS);
2107 v3s16 block_pos = getNodeBlockPos(p);
2109 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2112 std::vector<session_t> clients = m_clients.getClientIDs();
2115 for (session_t client_id : clients) {
2116 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2120 RemotePlayer *player = m_env->getPlayer(client_id);
2121 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2123 // If player is far away, only set modified blocks not sent
2124 if (!client->isBlockSent(block_pos) || (sao &&
2125 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2127 far_players->emplace(client_id);
2129 client->SetBlockNotSent(block_pos);
2134 m_clients.send(client_id, 0, &pkt, true);
2140 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2141 float far_d_nodes, bool remove_metadata)
2143 float maxd = far_d_nodes * BS;
2144 v3f p_f = intToFloat(p, BS);
2145 v3s16 block_pos = getNodeBlockPos(p);
2147 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2148 pkt << p << n.param0 << n.param1 << n.param2
2149 << (u8) (remove_metadata ? 0 : 1);
2151 std::vector<session_t> clients = m_clients.getClientIDs();
2154 for (session_t client_id : clients) {
2155 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2159 RemotePlayer *player = m_env->getPlayer(client_id);
2160 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2162 // If player is far away, only set modified blocks not sent
2163 if (!client->isBlockSent(block_pos) || (sao &&
2164 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2166 far_players->emplace(client_id);
2168 client->SetBlockNotSent(block_pos);
2173 m_clients.send(client_id, 0, &pkt, true);
2179 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2181 float maxd = far_d_nodes * BS;
2182 NodeMetadataList meta_updates_list(false);
2183 std::vector<session_t> clients = m_clients.getClientIDs();
2187 for (session_t i : clients) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2192 ServerActiveObject *player = m_env->getActiveObject(i);
2193 v3f player_pos = player ? player->getBasePosition() : v3f();
2195 for (const v3s16 &pos : meta_updates) {
2196 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2201 v3s16 block_pos = getNodeBlockPos(pos);
2202 if (!client->isBlockSent(block_pos) || (player &&
2203 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2204 client->SetBlockNotSent(block_pos);
2208 // Add the change to send list
2209 meta_updates_list.set(pos, meta);
2211 if (meta_updates_list.size() == 0)
2214 // Send the meta changes
2215 std::ostringstream os(std::ios::binary);
2216 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2217 std::ostringstream oss(std::ios::binary);
2218 compressZlib(os.str(), oss);
2220 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2221 pkt.putLongString(oss.str());
2222 m_clients.send(i, 0, &pkt, true);
2224 meta_updates_list.clear();
2230 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2231 u16 net_proto_version)
2234 Create a packet with the block in the right format
2237 std::ostringstream os(std::ios_base::binary);
2238 block->serialize(os, ver, false);
2239 block->serializeNetworkSpecific(os);
2240 std::string s = os.str();
2242 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2244 pkt << block->getPos();
2245 pkt.putRawString(s.c_str(), s.size());
2249 void Server::SendBlocks(float dtime)
2251 MutexAutoLock envlock(m_env_mutex);
2252 //TODO check if one big lock could be faster then multiple small ones
2254 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2256 std::vector<PrioritySortedBlockTransfer> queue;
2258 u32 total_sending = 0;
2261 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (const session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2272 total_sending += client->getSendingCount();
2273 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2279 // Lowest priority number comes first.
2280 // Lowest is most important.
2281 std::sort(queue.begin(), queue.end());
2285 // Maximal total count calculation
2286 // The per-client block sends is halved with the maximal online users
2287 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2288 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2290 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2291 if (total_sending >= max_blocks_to_send)
2294 MapBlock *block = nullptr;
2296 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2297 } catch (const InvalidPositionException &e) {
2301 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2306 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2307 client->net_proto_version);
2309 client->SentBlock(block_to_send.pos);
2315 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2317 MapBlock *block = nullptr;
2319 block = m_env->getMap().getBlockNoCreate(blockpos);
2320 } catch (InvalidPositionException &e) {};
2325 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2326 if (!client || client->isBlockSent(blockpos)) {
2330 SendBlockNoLock(peer_id, block, client->serialization_version,
2331 client->net_proto_version);
2337 void Server::fillMediaCache()
2339 infostream<<"Server: Calculating media file checksums"<<std::endl;
2341 // Collect all media file paths
2342 std::vector<std::string> paths;
2343 m_modmgr->getModsMediaPaths(paths);
2344 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2345 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2347 // Collect media file information from paths into cache
2348 for (const std::string &mediapath : paths) {
2349 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2350 for (const fs::DirListNode &dln : dirlist) {
2351 if (dln.dir) // Ignode dirs
2353 std::string filename = dln.name;
2354 // If name contains illegal characters, ignore the file
2355 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2356 infostream<<"Server: ignoring illegal file name: \""
2357 << filename << "\"" << std::endl;
2360 // If name is not in a supported format, ignore it
2361 const char *supported_ext[] = {
2362 ".png", ".jpg", ".bmp", ".tga",
2363 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2365 ".x", ".b3d", ".md2", ".obj",
2366 // Custom translation file format
2370 if (removeStringEnd(filename, supported_ext).empty()){
2371 infostream << "Server: ignoring unsupported file extension: \""
2372 << filename << "\"" << std::endl;
2375 // Ok, attempt to load the file and add to cache
2376 std::string filepath;
2377 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2380 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2382 errorstream << "Server::fillMediaCache(): Could not open \""
2383 << filename << "\" for reading" << std::endl;
2386 std::ostringstream tmp_os(std::ios_base::binary);
2390 fis.read(buf, 1024);
2391 std::streamsize len = fis.gcount();
2392 tmp_os.write(buf, len);
2401 errorstream<<"Server::fillMediaCache(): Failed to read \""
2402 << filename << "\"" << std::endl;
2405 if(tmp_os.str().length() == 0) {
2406 errorstream << "Server::fillMediaCache(): Empty file \""
2407 << filepath << "\"" << std::endl;
2412 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2414 unsigned char *digest = sha1.getDigest();
2415 std::string sha1_base64 = base64_encode(digest, 20);
2416 std::string sha1_hex = hex_encode((char*)digest, 20);
2420 m_media[filename] = MediaInfo(filepath, sha1_base64);
2421 verbosestream << "Server: " << sha1_hex << " is " << filename
2427 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2429 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2433 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2436 std::string lang_suffix;
2437 lang_suffix.append(".").append(lang_code).append(".tr");
2438 for (const auto &i : m_media) {
2439 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2446 for (const auto &i : m_media) {
2447 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2449 pkt << i.first << i.second.sha1_digest;
2452 pkt << g_settings->get("remote_media");
2456 struct SendableMedia
2462 SendableMedia(const std::string &name_="", const std::string &path_="",
2463 const std::string &data_=""):
2470 void Server::sendRequestedMedia(session_t peer_id,
2471 const std::vector<std::string> &tosend)
2473 verbosestream<<"Server::sendRequestedMedia(): "
2474 <<"Sending files to client"<<std::endl;
2478 // Put 5kB in one bunch (this is not accurate)
2479 u32 bytes_per_bunch = 5000;
2481 std::vector< std::vector<SendableMedia> > file_bunches;
2482 file_bunches.emplace_back();
2484 u32 file_size_bunch_total = 0;
2486 for (const std::string &name : tosend) {
2487 if (m_media.find(name) == m_media.end()) {
2488 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2489 <<"unknown file \""<<(name)<<"\""<<std::endl;
2493 //TODO get path + name
2494 std::string tpath = m_media[name].path;
2497 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2499 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2500 <<tpath<<"\" for reading"<<std::endl;
2503 std::ostringstream tmp_os(std::ios_base::binary);
2507 fis.read(buf, 1024);
2508 std::streamsize len = fis.gcount();
2509 tmp_os.write(buf, len);
2510 file_size_bunch_total += len;
2519 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2520 <<name<<"\""<<std::endl;
2523 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2524 <<tname<<"\""<<std::endl;*/
2526 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2528 // Start next bunch if got enough data
2529 if(file_size_bunch_total >= bytes_per_bunch) {
2530 file_bunches.emplace_back();
2531 file_size_bunch_total = 0;
2536 /* Create and send packets */
2538 u16 num_bunches = file_bunches.size();
2539 for (u16 i = 0; i < num_bunches; i++) {
2542 u16 total number of texture bunches
2543 u16 index of this bunch
2544 u32 number of files in this bunch
2553 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2554 pkt << num_bunches << i << (u32) file_bunches[i].size();
2556 for (const SendableMedia &j : file_bunches[i]) {
2558 pkt.putLongString(j.data);
2561 verbosestream << "Server::sendRequestedMedia(): bunch "
2562 << i << "/" << num_bunches
2563 << " files=" << file_bunches[i].size()
2564 << " size=" << pkt.getSize() << std::endl;
2569 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2571 const auto &inv_it = m_detached_inventories.find(name);
2572 const auto &player_it = m_detached_inventories_player.find(name);
2574 if (player_it == m_detached_inventories_player.end() ||
2575 player_it->second.empty()) {
2576 // OK. Send to everyone
2578 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2580 return; // Player is offline
2582 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2583 return; // Caller requested send to a different player, so don't send.
2585 peer_id = p->getPeerId();
2588 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2591 if (inv_it == m_detached_inventories.end()) {
2592 pkt << false; // Remove inventory
2594 pkt << true; // Update inventory
2596 // Serialization & NetworkPacket isn't a love story
2597 std::ostringstream os(std::ios_base::binary);
2598 inv_it->second->serialize(os);
2600 std::string os_str = os.str();
2601 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2602 pkt.putRawString(os_str);
2605 if (peer_id == PEER_ID_INEXISTENT)
2606 m_clients.sendToAll(&pkt);
2611 void Server::sendDetachedInventories(session_t peer_id)
2613 for (const auto &detached_inventory : m_detached_inventories) {
2614 const std::string &name = detached_inventory.first;
2615 //Inventory *inv = i->second;
2616 sendDetachedInventory(name, peer_id);
2624 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2626 PlayerSAO *playersao = getPlayerSAO(peer_id);
2627 // In some rare cases this can be NULL -- if the player is disconnected
2628 // when a Lua function modifies l_punch, for example
2632 infostream << "Server::DiePlayer(): Player "
2633 << playersao->getPlayer()->getName()
2634 << " dies" << std::endl;
2636 playersao->setHP(0, reason);
2637 playersao->clearParentAttachment();
2639 // Trigger scripted stuff
2640 m_script->on_dieplayer(playersao, reason);
2642 SendPlayerHP(peer_id);
2643 SendDeathscreen(peer_id, false, v3f(0,0,0));
2646 void Server::RespawnPlayer(session_t peer_id)
2648 PlayerSAO *playersao = getPlayerSAO(peer_id);
2651 infostream << "Server::RespawnPlayer(): Player "
2652 << playersao->getPlayer()->getName()
2653 << " respawns" << std::endl;
2655 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2656 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2657 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2659 bool repositioned = m_script->on_respawnplayer(playersao);
2660 if (!repositioned) {
2661 // setPos will send the new position to client
2662 playersao->setPos(findSpawnPos());
2665 SendPlayerHP(peer_id);
2669 void Server::DenySudoAccess(session_t peer_id)
2671 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2676 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2677 const std::string &str_reason, bool reconnect)
2679 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2681 m_clients.event(peer_id, CSE_SetDenied);
2682 DisconnectPeer(peer_id);
2686 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2687 const std::string &custom_reason)
2689 SendAccessDenied(peer_id, reason, custom_reason);
2690 m_clients.event(peer_id, CSE_SetDenied);
2691 DisconnectPeer(peer_id);
2694 // 13/03/15: remove this function when protocol version 25 will become
2695 // the minimum version for MT users, maybe in 1 year
2696 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2698 SendAccessDenied_Legacy(peer_id, reason);
2699 m_clients.event(peer_id, CSE_SetDenied);
2700 DisconnectPeer(peer_id);
2703 void Server::DisconnectPeer(session_t peer_id)
2705 m_modchannel_mgr->leaveAllChannels(peer_id);
2706 m_con->DisconnectPeer(peer_id);
2709 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2712 RemoteClient* client = getClient(peer_id, CS_Invalid);
2714 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2716 // Right now, the auth mechs don't change between login and sudo mode.
2717 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2718 client->allowed_sudo_mechs = sudo_auth_mechs;
2720 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2721 << g_settings->getFloat("dedicated_server_step")
2725 m_clients.event(peer_id, CSE_AuthAccept);
2727 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2729 // We only support SRP right now
2730 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2732 resp_pkt << sudo_auth_mechs;
2734 m_clients.event(peer_id, CSE_SudoSuccess);
2738 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2740 std::wstring message;
2743 Clear references to playing sounds
2745 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2746 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2747 ServerPlayingSound &psound = i->second;
2748 psound.clients.erase(peer_id);
2749 if (psound.clients.empty())
2750 m_playing_sounds.erase(i++);
2755 // clear formspec info so the next client can't abuse the current state
2756 m_formspec_state_data.erase(peer_id);
2758 RemotePlayer *player = m_env->getPlayer(peer_id);
2760 /* Run scripts and remove from environment */
2762 PlayerSAO *playersao = player->getPlayerSAO();
2765 playersao->clearChildAttachments();
2766 playersao->clearParentAttachment();
2768 // inform connected clients
2769 const std::string &player_name = player->getName();
2770 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2771 // (u16) 1 + std::string represents a vector serialization representation
2772 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2773 m_clients.sendToAll(¬ice);
2775 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2777 playersao->disconnected();
2784 if (player && reason != CDR_DENY) {
2785 std::ostringstream os(std::ios_base::binary);
2786 std::vector<session_t> clients = m_clients.getClientIDs();
2788 for (const session_t client_id : clients) {
2790 RemotePlayer *player = m_env->getPlayer(client_id);
2794 // Get name of player
2795 os << player->getName() << " ";
2798 std::string name = player->getName();
2799 actionstream << name << " "
2800 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2801 << " List of players: " << os.str() << std::endl;
2803 m_admin_chat->outgoing_queue.push_back(
2804 new ChatEventNick(CET_NICK_REMOVE, name));
2808 MutexAutoLock env_lock(m_env_mutex);
2809 m_clients.DeleteClient(peer_id);
2813 // Send leave chat message to all remaining clients
2814 if (!message.empty()) {
2815 SendChatMessage(PEER_ID_INEXISTENT,
2816 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2820 void Server::UpdateCrafting(RemotePlayer *player)
2822 InventoryList *clist = player->inventory.getList("craft");
2823 if (!clist || clist->getSize() == 0)
2826 // Get a preview for crafting
2828 InventoryLocation loc;
2829 loc.setPlayer(player->getName());
2830 std::vector<ItemStack> output_replacements;
2831 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2832 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2835 InventoryList *plist = player->inventory.getList("craftpreview");
2836 if (plist && plist->getSize() >= 1) {
2837 // Put the new preview in
2838 plist->changeItem(0, preview);
2842 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2844 if (evt->type == CET_NICK_ADD) {
2845 // The terminal informed us of its nick choice
2846 m_admin_nick = ((ChatEventNick *)evt)->nick;
2847 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2848 errorstream << "You haven't set up an account." << std::endl
2849 << "Please log in using the client as '"
2850 << m_admin_nick << "' with a secure password." << std::endl
2851 << "Until then, you can't execute admin tasks via the console," << std::endl
2852 << "and everybody can claim the user account instead of you," << std::endl
2853 << "giving them full control over this server." << std::endl;
2856 assert(evt->type == CET_CHAT);
2857 handleAdminChat((ChatEventChat *)evt);
2861 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2862 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2864 // If something goes wrong, this player is to blame
2865 RollbackScopeActor rollback_scope(m_rollback,
2866 std::string("player:") + name);
2868 if (g_settings->getBool("strip_color_codes"))
2869 wmessage = unescape_enriched(wmessage);
2872 switch (player->canSendChatMessage()) {
2873 case RPLAYER_CHATRESULT_FLOODING: {
2874 std::wstringstream ws;
2875 ws << L"You cannot send more messages. You are limited to "
2876 << g_settings->getFloat("chat_message_limit_per_10sec")
2877 << L" messages per 10 seconds.";
2880 case RPLAYER_CHATRESULT_KICK:
2881 DenyAccess_Legacy(player->getPeerId(),
2882 L"You have been kicked due to message flooding.");
2884 case RPLAYER_CHATRESULT_OK:
2887 FATAL_ERROR("Unhandled chat filtering result found.");
2891 if (m_max_chatmessage_length > 0
2892 && wmessage.length() > m_max_chatmessage_length) {
2893 return L"Your message exceed the maximum chat message limit set on the server. "
2894 L"It was refused. Send a shorter message";
2897 auto message = trim(wide_to_utf8(wmessage));
2898 if (message.find_first_of("\n\r") != std::wstring::npos) {
2899 return L"New lines are not permitted in chat messages";
2902 // Run script hook, exit if script ate the chat message
2903 if (m_script->on_chat_message(name, message))
2908 // Whether to send line to the player that sent the message, or to all players
2909 bool broadcast_line = true;
2911 if (check_shout_priv && !checkPriv(name, "shout")) {
2912 line += L"-!- You don't have permission to shout.";
2913 broadcast_line = false;
2915 line += narrow_to_wide(m_script->formatChatMessage(name,
2916 wide_to_narrow(wmessage)));
2920 Tell calling method to send the message to sender
2922 if (!broadcast_line)
2926 Send the message to others
2928 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2930 std::vector<session_t> clients = m_clients.getClientIDs();
2933 Send the message back to the inital sender
2934 if they are using protocol version >= 29
2937 session_t peer_id_to_avoid_sending =
2938 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2940 if (player && player->protocol_version >= 29)
2941 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2943 for (u16 cid : clients) {
2944 if (cid != peer_id_to_avoid_sending)
2945 SendChatMessage(cid, ChatMessage(line));
2950 void Server::handleAdminChat(const ChatEventChat *evt)
2952 std::string name = evt->nick;
2953 std::wstring wname = utf8_to_wide(name);
2954 std::wstring wmessage = evt->evt_msg;
2956 std::wstring answer = handleChat(name, wname, wmessage);
2958 // If asked to send answer to sender
2959 if (!answer.empty()) {
2960 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2964 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2966 RemoteClient *client = getClientNoEx(peer_id,state_min);
2968 throw ClientNotFoundException("Client not found");
2972 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2974 return m_clients.getClientNoEx(peer_id, state_min);
2977 std::string Server::getPlayerName(session_t peer_id)
2979 RemotePlayer *player = m_env->getPlayer(peer_id);
2981 return "[id="+itos(peer_id)+"]";
2982 return player->getName();
2985 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2987 RemotePlayer *player = m_env->getPlayer(peer_id);
2990 return player->getPlayerSAO();
2993 std::wstring Server::getStatusString()
2995 std::wostringstream os(std::ios_base::binary);
2996 os << L"# Server: ";
2998 os << L"version=" << narrow_to_wide(g_version_string);
3000 os << L", uptime=" << m_uptime.get();
3002 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3004 // Information about clients
3006 os << L", clients={";
3008 std::vector<session_t> clients = m_clients.getClientIDs();
3009 for (session_t client_id : clients) {
3010 RemotePlayer *player = m_env->getPlayer(client_id);
3012 // Get name of player
3013 std::wstring name = L"unknown";
3015 name = narrow_to_wide(player->getName());
3017 // Add name to information string
3028 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3029 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3031 if (!g_settings->get("motd").empty())
3032 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3037 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3039 std::set<std::string> privs;
3040 m_script->getAuth(name, NULL, &privs);
3044 bool Server::checkPriv(const std::string &name, const std::string &priv)
3046 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3047 return (privs.count(priv) != 0);
3050 void Server::reportPrivsModified(const std::string &name)
3053 std::vector<session_t> clients = m_clients.getClientIDs();
3054 for (const session_t client_id : clients) {
3055 RemotePlayer *player = m_env->getPlayer(client_id);
3056 reportPrivsModified(player->getName());
3059 RemotePlayer *player = m_env->getPlayer(name.c_str());
3062 SendPlayerPrivileges(player->getPeerId());
3063 PlayerSAO *sao = player->getPlayerSAO();
3066 sao->updatePrivileges(
3067 getPlayerEffectivePrivs(name),
3072 void Server::reportInventoryFormspecModified(const std::string &name)
3074 RemotePlayer *player = m_env->getPlayer(name.c_str());
3077 SendPlayerInventoryFormspec(player->getPeerId());
3080 void Server::reportFormspecPrependModified(const std::string &name)
3082 RemotePlayer *player = m_env->getPlayer(name.c_str());
3085 SendPlayerFormspecPrepend(player->getPeerId());
3088 void Server::setIpBanned(const std::string &ip, const std::string &name)
3090 m_banmanager->add(ip, name);
3093 void Server::unsetIpBanned(const std::string &ip_or_name)
3095 m_banmanager->remove(ip_or_name);
3098 std::string Server::getBanDescription(const std::string &ip_or_name)
3100 return m_banmanager->getBanDescription(ip_or_name);
3103 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3105 // m_env will be NULL if the server is initializing
3109 if (m_admin_nick == name && !m_admin_nick.empty()) {
3110 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3113 RemotePlayer *player = m_env->getPlayer(name);
3118 if (player->getPeerId() == PEER_ID_INEXISTENT)
3121 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3124 bool Server::showFormspec(const char *playername, const std::string &formspec,
3125 const std::string &formname)
3127 // m_env will be NULL if the server is initializing
3131 RemotePlayer *player = m_env->getPlayer(playername);
3135 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3139 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3144 u32 id = player->addHud(form);
3146 SendHUDAdd(player->getPeerId(), id, form);
3151 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3155 HudElement* todel = player->removeHud(id);
3162 SendHUDRemove(player->getPeerId(), id);
3166 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3171 SendHUDChange(player->getPeerId(), id, stat, data);
3175 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3180 SendHUDSetFlags(player->getPeerId(), flags, mask);
3181 player->hud_flags &= ~mask;
3182 player->hud_flags |= flags;
3184 PlayerSAO* playersao = player->getPlayerSAO();
3189 m_script->player_event(playersao, "hud_changed");
3193 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3198 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3201 player->setHotbarItemcount(hotbar_itemcount);
3202 std::ostringstream os(std::ios::binary);
3203 writeS32(os, hotbar_itemcount);
3204 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3208 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3213 player->setHotbarImage(name);
3214 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3217 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3222 player->setHotbarSelectedImage(name);
3223 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3226 Address Server::getPeerAddress(session_t peer_id)
3228 return m_con->GetPeerAddress(peer_id);
3231 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3232 v2s32 animation_frames[4], f32 frame_speed)
3234 sanity_check(player);
3235 player->setLocalAnimations(animation_frames, frame_speed);
3236 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3239 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3241 sanity_check(player);
3242 player->eye_offset_first = first;
3243 player->eye_offset_third = third;
3244 SendEyeOffset(player->getPeerId(), first, third);
3247 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3248 const std::string &type, const std::vector<std::string> ¶ms,
3251 sanity_check(player);
3252 player->setSky(bgcolor, type, params, clouds);
3253 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3256 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3258 sanity_check(player);
3259 player->setCloudParams(params);
3260 SendCloudParams(player->getPeerId(), params);
3263 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3269 player->overrideDayNightRatio(do_override, ratio);
3270 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3274 void Server::notifyPlayers(const std::wstring &msg)
3276 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3279 void Server::spawnParticle(const std::string &playername, v3f pos,
3280 v3f velocity, v3f acceleration,
3281 float expirationtime, float size, bool
3282 collisiondetection, bool collision_removal, bool object_collision,
3283 bool vertical, const std::string &texture,
3284 const struct TileAnimationParams &animation, u8 glow)
3286 // m_env will be NULL if the server is initializing
3290 session_t peer_id = PEER_ID_INEXISTENT;
3292 if (!playername.empty()) {
3293 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3296 peer_id = player->getPeerId();
3297 proto_ver = player->protocol_version;
3300 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3301 expirationtime, size, collisiondetection, collision_removal,
3302 object_collision, vertical, texture, animation, glow);
3305 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3306 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3307 float minexptime, float maxexptime, float minsize, float maxsize,
3308 bool collisiondetection, bool collision_removal, bool object_collision,
3309 ServerActiveObject *attached, bool vertical, const std::string &texture,
3310 const std::string &playername, const struct TileAnimationParams &animation,
3313 // m_env will be NULL if the server is initializing
3317 session_t peer_id = PEER_ID_INEXISTENT;
3319 if (!playername.empty()) {
3320 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3323 peer_id = player->getPeerId();
3324 proto_ver = player->protocol_version;
3327 u16 attached_id = attached ? attached->getId() : 0;
3330 if (attached_id == 0)
3331 id = m_env->addParticleSpawner(spawntime);
3333 id = m_env->addParticleSpawner(spawntime, attached_id);
3335 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3336 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3337 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3338 collision_removal, object_collision, attached_id, vertical,
3339 texture, id, animation, glow);
3344 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3346 // m_env will be NULL if the server is initializing
3348 throw ServerError("Can't delete particle spawners during initialisation!");
3350 session_t peer_id = PEER_ID_INEXISTENT;
3351 if (!playername.empty()) {
3352 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3355 peer_id = player->getPeerId();
3358 m_env->deleteParticleSpawner(id);
3359 SendDeleteParticleSpawner(peer_id, id);
3362 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3364 if(m_detached_inventories.count(name) > 0){
3365 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3366 delete m_detached_inventories[name];
3368 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3370 Inventory *inv = new Inventory(m_itemdef);
3372 m_detached_inventories[name] = inv;
3373 m_detached_inventories_player[name] = player;
3374 //TODO find a better way to do this
3375 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3379 bool Server::removeDetachedInventory(const std::string &name)
3381 const auto &inv_it = m_detached_inventories.find(name);
3382 if (inv_it == m_detached_inventories.end())
3385 delete inv_it->second;
3386 m_detached_inventories.erase(inv_it);
3388 const auto &player_it = m_detached_inventories_player.find(name);
3389 if (player_it != m_detached_inventories_player.end()) {
3390 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3392 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3393 sendDetachedInventory(name, player->getPeerId());
3395 m_detached_inventories_player.erase(player_it);
3397 // Notify all players about the change
3398 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3403 // actions: time-reversed list
3404 // Return value: success/failure
3405 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3406 std::list<std::string> *log)
3408 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3409 ServerMap *map = (ServerMap*)(&m_env->getMap());
3411 // Fail if no actions to handle
3412 if (actions.empty()) {
3414 log->push_back("Nothing to do.");
3421 for (const RollbackAction &action : actions) {
3423 bool success = action.applyRevert(map, this, this);
3426 std::ostringstream os;
3427 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3428 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3430 log->push_back(os.str());
3432 std::ostringstream os;
3433 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3434 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3436 log->push_back(os.str());
3440 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3441 <<" failed"<<std::endl;
3443 // Call it done if less than half failed
3444 return num_failed <= num_tried/2;
3447 // IGameDef interface
3449 IItemDefManager *Server::getItemDefManager()
3454 const NodeDefManager *Server::getNodeDefManager()
3459 ICraftDefManager *Server::getCraftDefManager()
3464 u16 Server::allocateUnknownNodeId(const std::string &name)
3466 return m_nodedef->allocateDummy(name);
3469 IWritableItemDefManager *Server::getWritableItemDefManager()
3474 NodeDefManager *Server::getWritableNodeDefManager()
3479 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3484 const std::vector<ModSpec> & Server::getMods() const
3486 return m_modmgr->getMods();
3489 const ModSpec *Server::getModSpec(const std::string &modname) const
3491 return m_modmgr->getModSpec(modname);
3494 void Server::getModNames(std::vector<std::string> &modlist)
3496 m_modmgr->getModNames(modlist);
3499 std::string Server::getBuiltinLuaPath()
3501 return porting::path_share + DIR_DELIM + "builtin";
3504 std::string Server::getModStoragePath() const
3506 return m_path_world + DIR_DELIM + "mod_storage";
3509 v3f Server::findSpawnPos()
3511 ServerMap &map = m_env->getServerMap();
3513 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3514 return nodeposf * BS;
3516 bool is_good = false;
3517 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3518 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3520 // Try to find a good place a few times
3521 for (s32 i = 0; i < 4000 && !is_good; i++) {
3522 s32 range = MYMIN(1 + i, range_max);
3523 // We're going to try to throw the player to this position
3524 v2s16 nodepos2d = v2s16(
3525 -range + (myrand() % (range * 2)),
3526 -range + (myrand() % (range * 2)));
3527 // Get spawn level at point
3528 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3529 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3530 // signify an unsuitable spawn position, or if outside limits.
3531 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3532 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3535 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3536 // Consecutive empty nodes
3539 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3540 // avoid obstructions in already-generated mapblocks.
3541 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3542 // no obstructions, but mapgen decorations are generated after spawn so
3543 // the player may end up inside one.
3544 for (s32 i = 0; i < 8; i++) {
3545 v3s16 blockpos = getNodeBlockPos(nodepos);
3546 map.emergeBlock(blockpos, true);
3547 content_t c = map.getNodeNoEx(nodepos).getContent();
3549 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3550 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3551 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3553 if (air_count >= 2) {
3554 // Spawn in lower empty node
3556 nodeposf = intToFloat(nodepos, BS);
3557 // Don't spawn the player outside map boundaries
3558 if (objectpos_over_limit(nodeposf))
3559 // Exit this loop, positions above are probably over limit
3562 // Good position found, cause an exit from main loop
3576 // No suitable spawn point found, return fallback 0,0,0
3577 return v3f(0.0f, 0.0f, 0.0f);
3580 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3582 if (delay == 0.0f) {
3583 // No delay, shutdown immediately
3584 m_shutdown_state.is_requested = true;
3585 // only print to the infostream, a chat message saying
3586 // "Server Shutting Down" is sent when the server destructs.
3587 infostream << "*** Immediate Server shutdown requested." << std::endl;
3588 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3589 // Negative delay, cancel shutdown if requested
3590 m_shutdown_state.reset();
3591 std::wstringstream ws;
3593 ws << L"*** Server shutdown canceled.";
3595 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3596 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3597 // m_shutdown_* are already handled, skip.
3599 } else if (delay > 0.0f) {
3600 // Positive delay, tell the clients when the server will shut down
3601 std::wstringstream ws;
3603 ws << L"*** Server shutting down in "
3604 << duration_to_string(myround(delay)).c_str()
3607 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3608 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3611 m_shutdown_state.trigger(delay, msg, reconnect);
3614 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3617 Try to get an existing player
3619 RemotePlayer *player = m_env->getPlayer(name);
3621 // If player is already connected, cancel
3622 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3623 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3628 If player with the wanted peer_id already exists, cancel.
3630 if (m_env->getPlayer(peer_id)) {
3631 infostream<<"emergePlayer(): Player with wrong name but same"
3632 " peer_id already exists"<<std::endl;
3637 player = new RemotePlayer(name, idef());
3640 bool newplayer = false;
3643 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3645 // Complete init with server parts
3646 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3647 player->protocol_version = proto_version;
3651 m_script->on_newplayer(playersao);
3657 bool Server::registerModStorage(ModMetadata *storage)
3659 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3660 errorstream << "Unable to register same mod storage twice. Storage name: "
3661 << storage->getModName() << std::endl;
3665 m_mod_storages[storage->getModName()] = storage;
3669 void Server::unregisterModStorage(const std::string &name)
3671 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3672 if (it != m_mod_storages.end()) {
3673 // Save unconditionaly on unregistration
3674 it->second->save(getModStoragePath());
3675 m_mod_storages.erase(name);
3679 void dedicated_server_loop(Server &server, bool &kill)
3681 verbosestream<<"dedicated_server_loop()"<<std::endl;
3683 IntervalLimiter m_profiler_interval;
3685 static thread_local const float steplen =
3686 g_settings->getFloat("dedicated_server_step");
3687 static thread_local const float profiler_print_interval =
3688 g_settings->getFloat("profiler_print_interval");
3691 // This is kind of a hack but can be done like this
3692 // because server.step() is very light
3694 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3695 sleep_ms((int)(steplen*1000.0));
3697 server.step(steplen);
3699 if (server.isShutdownRequested() || kill)
3705 if (profiler_print_interval != 0) {
3706 if(m_profiler_interval.step(steplen, profiler_print_interval))
3708 infostream<<"Profiler:"<<std::endl;
3709 g_profiler->print(infostream);
3710 g_profiler->clear();
3715 infostream << "Dedicated server quitting" << std::endl;
3717 if (g_settings->getBool("server_announce"))
3718 ServerList::sendAnnounce(ServerList::AA_DELETE,
3719 server.m_bind_addr.getPort());
3728 bool Server::joinModChannel(const std::string &channel)
3730 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3731 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3734 bool Server::leaveModChannel(const std::string &channel)
3736 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3739 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3741 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3744 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3748 ModChannel* Server::getModChannel(const std::string &channel)
3750 return m_modchannel_mgr->getModChannel(channel);
3753 void Server::broadcastModChannelMessage(const std::string &channel,
3754 const std::string &message, session_t from_peer)
3756 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3760 if (message.size() > STRING_MAX_LEN) {
3761 warningstream << "ModChannel message too long, dropping before sending "
3762 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3763 << channel << ")" << std::endl;
3768 if (from_peer != PEER_ID_SERVER) {
3769 sender = getPlayerName(from_peer);
3772 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3773 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3774 resp_pkt << channel << sender << message;
3775 for (session_t peer_id : peers) {
3777 if (peer_id == from_peer)
3780 Send(peer_id, &resp_pkt);
3783 if (from_peer != PEER_ID_SERVER) {
3784 m_script->on_modchannel_message(channel, sender, message);