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()),
226 m_modchannel_mgr(new ModChannelMgr())
228 m_lag = g_settings->getFloat("dedicated_server_step");
230 if (m_path_world.empty())
231 throw ServerError("Supplied empty world path");
233 if (!gamespec.isValid())
234 throw ServerError("Supplied invalid gamespec");
240 // Send shutdown message
241 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
242 L"*** Server shutting down"));
245 MutexAutoLock envlock(m_env_mutex);
247 infostream << "Server: Saving players" << std::endl;
248 m_env->saveLoadedPlayers();
250 infostream << "Server: Kicking players" << std::endl;
251 std::string kick_msg;
252 bool reconnect = false;
253 if (isShutdownRequested()) {
254 reconnect = m_shutdown_state.should_reconnect;
255 kick_msg = m_shutdown_state.message;
257 if (kick_msg.empty()) {
258 kick_msg = g_settings->get("kick_msg_shutdown");
260 m_env->saveLoadedPlayers(true);
261 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
262 kick_msg, reconnect);
265 actionstream << "Server: Shutting down" << std::endl;
267 // Do this before stopping the server in case mapgen callbacks need to access
268 // server-controlled resources (like ModStorages). Also do them before
269 // shutdown callbacks since they may modify state that is finalized in a
272 m_emerge->stopThreads();
275 MutexAutoLock envlock(m_env_mutex);
277 // Execute script shutdown hooks
278 infostream << "Executing shutdown hooks" << std::endl;
279 m_script->on_shutdown();
281 infostream << "Server: Saving environment metadata" << std::endl;
291 // Delete things in the reverse order of creation
300 // Deinitialize scripting
301 infostream << "Server: Deinitializing scripting" << std::endl;
304 // Delete detached inventories
305 for (auto &detached_inventory : m_detached_inventories) {
306 delete detached_inventory.second;
312 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
313 if (m_simple_singleplayer_mode)
314 infostream << " in simple singleplayer mode" << std::endl;
316 infostream << std::endl;
317 infostream << "- world: " << m_path_world << std::endl;
318 infostream << "- game: " << m_gamespec.path << std::endl;
320 // Create world if it doesn't exist
321 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
322 throw ServerError("Failed to initialize world");
324 // Create server thread
325 m_thread = new ServerThread(this);
327 // Create emerge manager
328 m_emerge = new EmergeManager(this);
330 // Create ban manager
331 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
332 m_banmanager = new BanManager(ban_path);
334 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
335 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
336 // complain about mods with unsatisfied dependencies
337 if (!m_modmgr->isConsistent()) {
338 m_modmgr->printUnsatisfiedModsError();
342 MutexAutoLock envlock(m_env_mutex);
344 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
345 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
347 // Initialize scripting
348 infostream << "Server: Initializing Lua" << std::endl;
350 m_script = new ServerScripting(this);
352 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
354 m_modmgr->loadMods(m_script);
356 // Read Textures and calculate sha1 sums
359 // Apply item aliases in the node definition manager
360 m_nodedef->updateAliases(m_itemdef);
362 // Apply texture overrides from texturepack/override.txt
363 std::vector<std::string> paths;
364 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
365 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
366 for (const std::string &path : paths)
367 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
369 m_nodedef->setNodeRegistrationStatus(true);
371 // Perform pending node name resolutions
372 m_nodedef->runNodeResolveCallbacks();
374 // unmap node names for connected nodeboxes
375 m_nodedef->mapNodeboxConnections();
377 // init the recipe hashes to speed up crafting
378 m_craftdef->initHashes(this);
380 // Initialize Environment
381 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
383 m_clients.setEnv(m_env);
385 if (!servermap->settings_mgr.makeMapgenParams())
386 FATAL_ERROR("Couldn't create any mapgen type");
388 // Initialize mapgens
389 m_emerge->initMapgens(servermap->getMapgenParams());
391 if (g_settings->getBool("enable_rollback_recording")) {
392 // Create rollback manager
393 m_rollback = new RollbackManager(m_path_world, this);
396 // Give environment reference to scripting api
397 m_script->initializeEnvironment(m_env);
399 // Register us to receive map edit events
400 servermap->addEventReceiver(this);
404 m_liquid_transform_every = g_settings->getFloat("liquid_update");
405 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
406 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
407 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
412 infostream << "Starting server on " << m_bind_addr.serializeString()
413 << "..." << std::endl;
415 // Stop thread if already running
418 // Initialize connection
419 m_con->SetTimeoutMs(30);
420 m_con->Serve(m_bind_addr);
425 // ASCII art for the win!
427 << " .__ __ __ " << std::endl
428 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
429 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
430 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
431 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
432 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
433 actionstream << "World at [" << m_path_world << "]" << std::endl;
434 actionstream << "Server for gameid=\"" << m_gamespec.id
435 << "\" listening on " << m_bind_addr.serializeString() << ":"
436 << m_bind_addr.getPort() << "." << std::endl;
441 infostream<<"Server: Stopping and waiting threads"<<std::endl;
443 // Stop threads (set run=false first so both start stopping)
445 //m_emergethread.setRun(false);
447 //m_emergethread.stop();
449 infostream<<"Server: Threads stopped"<<std::endl;
452 void Server::step(float dtime)
458 MutexAutoLock lock(m_step_dtime_mutex);
459 m_step_dtime += dtime;
461 // Throw if fatal error occurred in thread
462 std::string async_err = m_async_fatal_error.get();
463 if (!async_err.empty()) {
464 if (!m_simple_singleplayer_mode) {
465 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
466 g_settings->get("kick_msg_crash"),
467 g_settings->getBool("ask_reconnect_on_crash"));
469 throw ServerError("AsyncErr: " + async_err);
473 void Server::AsyncRunStep(bool initial_step)
475 g_profiler->add("Server::AsyncRunStep (num)", 1);
479 MutexAutoLock lock1(m_step_dtime_mutex);
480 dtime = m_step_dtime;
484 // Send blocks to clients
488 if((dtime < 0.001) && !initial_step)
491 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
493 //infostream<<"Server steps "<<dtime<<std::endl;
494 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
497 MutexAutoLock lock1(m_step_dtime_mutex);
498 m_step_dtime -= dtime;
505 m_uptime.set(m_uptime.get() + dtime);
511 Update time of day and overall game time
513 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
516 Send to clients at constant intervals
519 m_time_of_day_send_timer -= dtime;
520 if(m_time_of_day_send_timer < 0.0) {
521 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
522 u16 time = m_env->getTimeOfDay();
523 float time_speed = g_settings->getFloat("time_speed");
524 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
528 MutexAutoLock lock(m_env_mutex);
529 // Figure out and report maximum lag to environment
530 float max_lag = m_env->getMaxLagEstimate();
531 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
533 if(dtime > 0.1 && dtime > max_lag * 2.0)
534 infostream<<"Server: Maximum lag peaked to "<<dtime
538 m_env->reportMaxLagEstimate(max_lag);
540 ScopeProfiler sp(g_profiler, "SEnv step");
541 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
545 static const float map_timer_and_unload_dtime = 2.92;
546 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
548 MutexAutoLock lock(m_env_mutex);
549 // Run Map's timers and unload unused data
550 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
551 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
552 g_settings->getFloat("server_unload_unused_data_timeout"),
557 Listen to the admin chat, if available
560 if (!m_admin_chat->command_queue.empty()) {
561 MutexAutoLock lock(m_env_mutex);
562 while (!m_admin_chat->command_queue.empty()) {
563 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
564 handleChatInterfaceEvent(evt);
568 m_admin_chat->outgoing_queue.push_back(
569 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
576 /* Transform liquids */
577 m_liquid_transform_timer += dtime;
578 if(m_liquid_transform_timer >= m_liquid_transform_every)
580 m_liquid_transform_timer -= m_liquid_transform_every;
582 MutexAutoLock lock(m_env_mutex);
584 ScopeProfiler sp(g_profiler, "Server: liquid transform");
586 std::map<v3s16, MapBlock*> modified_blocks;
587 m_env->getMap().transformLiquids(modified_blocks, m_env);
590 Set the modified blocks unsent for all the clients
592 if (!modified_blocks.empty()) {
593 SetBlocksNotSent(modified_blocks);
596 m_clients.step(dtime);
598 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
600 // send masterserver announce
602 float &counter = m_masterserver_timer;
603 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
604 g_settings->getBool("server_announce")) {
605 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
606 ServerList::AA_START,
607 m_bind_addr.getPort(),
608 m_clients.getPlayerNames(),
610 m_env->getGameTime(),
613 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
623 Check added and deleted active objects
626 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
627 MutexAutoLock envlock(m_env_mutex);
630 const RemoteClientMap &clients = m_clients.getClientList();
631 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
633 // Radius inside which objects are active
634 static thread_local const s16 radius =
635 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
637 // Radius inside which players are active
638 static thread_local const bool is_transfer_limited =
639 g_settings->exists("unlimited_player_transfer_distance") &&
640 !g_settings->getBool("unlimited_player_transfer_distance");
641 static thread_local const s16 player_transfer_dist =
642 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
643 s16 player_radius = player_transfer_dist;
644 if (player_radius == 0 && is_transfer_limited)
645 player_radius = radius;
647 for (const auto &client_it : clients) {
648 RemoteClient *client = client_it.second;
650 // If definitions and textures have not been sent, don't
651 // send objects either
652 if (client->getState() < CS_DefinitionsSent)
655 RemotePlayer *player = m_env->getPlayer(client->peer_id);
657 // This can happen if the client timeouts somehow
661 PlayerSAO *playersao = player->getPlayerSAO();
665 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
666 if (my_radius <= 0) my_radius = radius;
667 //infostream << "Server: Active Radius " << my_radius << std::endl;
669 std::queue<u16> removed_objects;
670 std::queue<u16> added_objects;
671 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
672 client->m_known_objects, removed_objects);
673 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
674 client->m_known_objects, added_objects);
676 // Ignore if nothing happened
677 if (removed_objects.empty() && added_objects.empty()) {
681 std::string data_buffer;
685 // Handle removed objects
686 writeU16((u8*)buf, removed_objects.size());
687 data_buffer.append(buf, 2);
688 while (!removed_objects.empty()) {
690 u16 id = removed_objects.front();
691 ServerActiveObject* obj = m_env->getActiveObject(id);
693 // Add to data buffer for sending
694 writeU16((u8*)buf, id);
695 data_buffer.append(buf, 2);
697 // Remove from known objects
698 client->m_known_objects.erase(id);
700 if(obj && obj->m_known_by_count > 0)
701 obj->m_known_by_count--;
702 removed_objects.pop();
705 // Handle added objects
706 writeU16((u8*)buf, added_objects.size());
707 data_buffer.append(buf, 2);
708 while (!added_objects.empty()) {
710 u16 id = added_objects.front();
711 ServerActiveObject* obj = m_env->getActiveObject(id);
714 u8 type = ACTIVEOBJECT_TYPE_INVALID;
716 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
718 type = obj->getSendType();
720 // Add to data buffer for sending
721 writeU16((u8*)buf, id);
722 data_buffer.append(buf, 2);
723 writeU8((u8*)buf, type);
724 data_buffer.append(buf, 1);
727 data_buffer.append(serializeLongString(
728 obj->getClientInitializationData(client->net_proto_version)));
730 data_buffer.append(serializeLongString(""));
732 // Add to known objects
733 client->m_known_objects.insert(id);
736 obj->m_known_by_count++;
741 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
742 verbosestream << "Server: Sent object remove/add: "
743 << removed_objects.size() << " removed, "
744 << added_objects.size() << " added, "
745 << "packet size is " << pktSize << std::endl;
749 m_mod_storage_save_timer -= dtime;
750 if (m_mod_storage_save_timer <= 0.0f) {
751 infostream << "Saving registered mod storages." << std::endl;
752 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
753 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
754 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
755 if (it->second->isModified()) {
756 it->second->save(getModStoragePath());
766 MutexAutoLock envlock(m_env_mutex);
767 ScopeProfiler sp(g_profiler, "Server: sending object messages");
770 // Value = data sent by object
771 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
773 // Get active object messages from environment
775 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
779 std::vector<ActiveObjectMessage>* message_list = nullptr;
780 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
781 n = buffered_messages.find(aom.id);
782 if (n == buffered_messages.end()) {
783 message_list = new std::vector<ActiveObjectMessage>;
784 buffered_messages[aom.id] = message_list;
787 message_list = n->second;
789 message_list->push_back(aom);
793 const RemoteClientMap &clients = m_clients.getClientList();
794 // Route data to every client
795 for (const auto &client_it : clients) {
796 RemoteClient *client = client_it.second;
797 std::string reliable_data;
798 std::string unreliable_data;
799 // Go through all objects in message buffer
800 for (const auto &buffered_message : buffered_messages) {
801 // If object is not known by client, skip it
802 u16 id = buffered_message.first;
803 if (client->m_known_objects.find(id) == client->m_known_objects.end())
806 // Get message list of object
807 std::vector<ActiveObjectMessage>* list = buffered_message.second;
808 // Go through every message
809 for (const ActiveObjectMessage &aom : *list) {
810 // Compose the full new data with header
811 std::string new_data;
814 writeU16((u8*)&buf[0], aom.id);
815 new_data.append(buf, 2);
817 new_data += serializeString(aom.datastring);
818 // Add data to buffer
820 reliable_data += new_data;
822 unreliable_data += new_data;
826 reliable_data and unreliable_data are now ready.
829 if (!reliable_data.empty()) {
830 SendActiveObjectMessages(client->peer_id, reliable_data);
833 if (!unreliable_data.empty()) {
834 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
839 // Clear buffered_messages
840 for (auto &buffered_message : buffered_messages) {
841 delete buffered_message.second;
846 Send queued-for-sending map edit events.
849 // We will be accessing the environment
850 MutexAutoLock lock(m_env_mutex);
852 // Don't send too many at a time
855 // Single change sending is disabled if queue size is not small
856 bool disable_single_change_sending = false;
857 if(m_unsent_map_edit_queue.size() >= 4)
858 disable_single_change_sending = true;
860 int event_count = m_unsent_map_edit_queue.size();
862 // We'll log the amount of each
865 std::list<v3s16> node_meta_updates;
867 while (!m_unsent_map_edit_queue.empty()) {
868 MapEditEvent* event = m_unsent_map_edit_queue.front();
869 m_unsent_map_edit_queue.pop();
871 // Players far away from the change are stored here.
872 // Instead of sending the changes, MapBlocks are set not sent
874 std::unordered_set<u16> far_players;
876 switch (event->type) {
879 prof.add("MEET_ADDNODE", 1);
880 sendAddNode(event->p, event->n, &far_players,
881 disable_single_change_sending ? 5 : 30,
882 event->type == MEET_ADDNODE);
884 case MEET_REMOVENODE:
885 prof.add("MEET_REMOVENODE", 1);
886 sendRemoveNode(event->p, &far_players,
887 disable_single_change_sending ? 5 : 30);
889 case MEET_BLOCK_NODE_METADATA_CHANGED: {
890 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
891 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
892 if (!event->is_private_change) {
893 // Don't send the change yet. Collect them to eliminate dupes.
894 node_meta_updates.remove(event->p);
895 node_meta_updates.push_back(event->p);
898 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
899 getNodeBlockPos(event->p))) {
900 block->raiseModified(MOD_STATE_WRITE_NEEDED,
901 MOD_REASON_REPORT_META_CHANGE);
906 infostream << "Server: MEET_OTHER" << std::endl;
907 prof.add("MEET_OTHER", 1);
908 for (const v3s16 &modified_block : event->modified_blocks) {
909 m_clients.markBlockposAsNotSent(modified_block);
913 prof.add("unknown", 1);
914 warningstream << "Server: Unknown MapEditEvent "
915 << ((u32)event->type) << std::endl;
920 Set blocks not sent to far players
922 if (!far_players.empty()) {
923 // Convert list format to that wanted by SetBlocksNotSent
924 std::map<v3s16, MapBlock*> modified_blocks2;
925 for (const v3s16 &modified_block : event->modified_blocks) {
926 modified_blocks2[modified_block] =
927 m_env->getMap().getBlockNoCreateNoEx(modified_block);
930 // Set blocks not sent
931 for (const u16 far_player : far_players) {
932 if (RemoteClient *client = getClient(far_player))
933 client->SetBlocksNotSent(modified_blocks2);
940 if (event_count >= 5) {
941 infostream << "Server: MapEditEvents:" << std::endl;
942 prof.print(infostream);
943 } else if (event_count != 0) {
944 verbosestream << "Server: MapEditEvents:" << std::endl;
945 prof.print(verbosestream);
948 // Send all metadata updates
949 if (node_meta_updates.size())
950 sendMetadataChanged(node_meta_updates);
954 Trigger emergethread (it somehow gets to a non-triggered but
955 bysy state sometimes)
958 float &counter = m_emergethread_trigger_timer;
960 if (counter >= 2.0) {
963 m_emerge->startThreads();
967 // Save map, players and auth stuff
969 float &counter = m_savemap_timer;
971 static thread_local const float save_interval =
972 g_settings->getFloat("server_map_save_interval");
973 if (counter >= save_interval) {
975 MutexAutoLock lock(m_env_mutex);
977 ScopeProfiler sp(g_profiler, "Server: saving stuff");
980 if (m_banmanager->isModified()) {
981 m_banmanager->save();
984 // Save changed parts of map
985 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
988 m_env->saveLoadedPlayers();
990 // Save environment metadata
995 m_shutdown_state.tick(dtime, this);
998 void Server::Receive()
1000 session_t peer_id = 0;
1003 m_con->Receive(&pkt);
1004 peer_id = pkt.getPeerId();
1006 } catch (const con::InvalidIncomingDataException &e) {
1007 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1008 << e.what() << std::endl;
1009 } catch (const SerializationError &e) {
1010 infostream << "Server::Receive(): SerializationError: what()="
1011 << e.what() << std::endl;
1012 } catch (const ClientStateError &e) {
1013 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1014 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1015 L"Try reconnecting or updating your client");
1016 } catch (const con::PeerNotFoundException &e) {
1021 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1023 std::string playername;
1024 PlayerSAO *playersao = NULL;
1027 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1029 playername = client->getName();
1030 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1032 } catch (std::exception &e) {
1038 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1040 // If failed, cancel
1041 if (!playersao || !player) {
1042 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1043 actionstream << "Server: Failed to emerge player \"" << playername
1044 << "\" (player allocated to an another client)" << std::endl;
1045 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1046 L"name. If your client closed unexpectedly, try again in "
1049 errorstream << "Server: " << playername << ": Failed to emerge player"
1051 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1057 Send complete position information
1059 SendMovePlayer(peer_id);
1062 SendPlayerPrivileges(peer_id);
1064 // Send inventory formspec
1065 SendPlayerInventoryFormspec(peer_id);
1068 SendInventory(playersao);
1070 // Send HP or death screen
1071 if (playersao->isDead())
1072 SendDeathscreen(peer_id, false, v3f(0,0,0));
1074 SendPlayerHPOrDie(playersao,
1075 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1078 SendPlayerBreath(playersao);
1080 Address addr = getPeerAddress(player->getPeerId());
1081 std::string ip_str = addr.serializeString();
1082 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1087 const std::vector<std::string> &names = m_clients.getPlayerNames();
1089 actionstream << player->getName() << " joins game. List of players: ";
1091 for (const std::string &name : names) {
1092 actionstream << name << " ";
1095 actionstream << player->getName() <<std::endl;
1100 inline void Server::handleCommand(NetworkPacket* pkt)
1102 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1103 (this->*opHandle.handler)(pkt);
1106 void Server::ProcessData(NetworkPacket *pkt)
1108 // Environment is locked first.
1109 MutexAutoLock envlock(m_env_mutex);
1111 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1112 u32 peer_id = pkt->getPeerId();
1115 Address address = getPeerAddress(peer_id);
1116 std::string addr_s = address.serializeString();
1118 if(m_banmanager->isIpBanned(addr_s)) {
1119 std::string ban_name = m_banmanager->getBanName(addr_s);
1120 infostream << "Server: A banned client tried to connect from "
1121 << addr_s << "; banned name was "
1122 << ban_name << std::endl;
1123 // This actually doesn't seem to transfer to the client
1124 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1125 + utf8_to_wide(ban_name));
1129 catch(con::PeerNotFoundException &e) {
1131 * no peer for this packet found
1132 * most common reason is peer timeout, e.g. peer didn't
1133 * respond for some time, your server was overloaded or
1136 infostream << "Server::ProcessData(): Canceling: peer "
1137 << peer_id << " not found" << std::endl;
1142 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1144 // Command must be handled into ToServerCommandHandler
1145 if (command >= TOSERVER_NUM_MSG_TYPES) {
1146 infostream << "Server: Ignoring unknown command "
1147 << command << std::endl;
1151 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1156 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1158 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1159 errorstream << "Server::ProcessData(): Cancelling: Peer"
1160 " serialization format invalid or not initialized."
1161 " Skipping incoming command=" << command << std::endl;
1165 /* Handle commands related to client startup */
1166 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1171 if (m_clients.getClientState(peer_id) < CS_Active) {
1172 if (command == TOSERVER_PLAYERPOS) return;
1174 errorstream << "Got packet command: " << command << " for peer id "
1175 << peer_id << " but client isn't active yet. Dropping packet "
1181 } catch (SendFailedException &e) {
1182 errorstream << "Server::ProcessData(): SendFailedException: "
1183 << "what=" << e.what()
1185 } catch (PacketError &e) {
1186 actionstream << "Server::ProcessData(): PacketError: "
1187 << "what=" << e.what()
1192 void Server::setTimeOfDay(u32 time)
1194 m_env->setTimeOfDay(time);
1195 m_time_of_day_send_timer = 0;
1198 void Server::onMapEditEvent(MapEditEvent *event)
1200 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1202 MapEditEvent *e = event->clone();
1203 m_unsent_map_edit_queue.push(e);
1206 Inventory* Server::getInventory(const InventoryLocation &loc)
1209 case InventoryLocation::UNDEFINED:
1210 case InventoryLocation::CURRENT_PLAYER:
1212 case InventoryLocation::PLAYER:
1214 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1217 PlayerSAO *playersao = player->getPlayerSAO();
1220 return playersao->getInventory();
1223 case InventoryLocation::NODEMETA:
1225 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1228 return meta->getInventory();
1231 case InventoryLocation::DETACHED:
1233 if(m_detached_inventories.count(loc.name) == 0)
1235 return m_detached_inventories[loc.name];
1239 sanity_check(false); // abort
1245 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1248 case InventoryLocation::UNDEFINED:
1250 case InventoryLocation::PLAYER:
1255 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1260 PlayerSAO *playersao = player->getPlayerSAO();
1264 SendInventory(playersao);
1267 case InventoryLocation::NODEMETA:
1270 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1272 m_env->getMap().dispatchEvent(&event);
1275 case InventoryLocation::DETACHED:
1277 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1281 sanity_check(false); // abort
1286 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1288 std::vector<session_t> clients = m_clients.getClientIDs();
1290 // Set the modified blocks unsent for all the clients
1291 for (const session_t client_id : clients) {
1292 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1293 client->SetBlocksNotSent(block);
1298 void Server::peerAdded(con::Peer *peer)
1300 verbosestream<<"Server::peerAdded(): peer->id="
1301 <<peer->id<<std::endl;
1303 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1306 void Server::deletingPeer(con::Peer *peer, bool timeout)
1308 verbosestream<<"Server::deletingPeer(): peer->id="
1309 <<peer->id<<", timeout="<<timeout<<std::endl;
1311 m_clients.event(peer->id, CSE_Disconnect);
1312 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1315 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1317 *retval = m_con->getPeerStat(peer_id,type);
1318 return *retval != -1;
1321 bool Server::getClientInfo(
1330 std::string* vers_string
1333 *state = m_clients.getClientState(peer_id);
1335 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1342 *uptime = client->uptime();
1343 *ser_vers = client->serialization_version;
1344 *prot_vers = client->net_proto_version;
1346 *major = client->getMajor();
1347 *minor = client->getMinor();
1348 *patch = client->getPatch();
1349 *vers_string = client->getPatch();
1356 void Server::handlePeerChanges()
1358 while(!m_peer_change_queue.empty())
1360 con::PeerChange c = m_peer_change_queue.front();
1361 m_peer_change_queue.pop();
1363 verbosestream<<"Server: Handling peer change: "
1364 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1369 case con::PEER_ADDED:
1370 m_clients.CreateClient(c.peer_id);
1373 case con::PEER_REMOVED:
1374 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1378 FATAL_ERROR("Invalid peer change event received!");
1384 void Server::printToConsoleOnly(const std::string &text)
1387 m_admin_chat->outgoing_queue.push_back(
1388 new ChatEventChat("", utf8_to_wide(text)));
1390 std::cout << text << std::endl;
1394 void Server::Send(NetworkPacket *pkt)
1396 Send(pkt->getPeerId(), pkt);
1399 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1401 m_clients.send(peer_id,
1402 clientCommandFactoryTable[pkt->getCommand()].channel,
1404 clientCommandFactoryTable[pkt->getCommand()].reliable);
1407 void Server::SendMovement(session_t peer_id)
1409 std::ostringstream os(std::ios_base::binary);
1411 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1413 pkt << g_settings->getFloat("movement_acceleration_default");
1414 pkt << g_settings->getFloat("movement_acceleration_air");
1415 pkt << g_settings->getFloat("movement_acceleration_fast");
1416 pkt << g_settings->getFloat("movement_speed_walk");
1417 pkt << g_settings->getFloat("movement_speed_crouch");
1418 pkt << g_settings->getFloat("movement_speed_fast");
1419 pkt << g_settings->getFloat("movement_speed_climb");
1420 pkt << g_settings->getFloat("movement_speed_jump");
1421 pkt << g_settings->getFloat("movement_liquid_fluidity");
1422 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1423 pkt << g_settings->getFloat("movement_liquid_sink");
1424 pkt << g_settings->getFloat("movement_gravity");
1429 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1431 if (!g_settings->getBool("enable_damage"))
1434 session_t peer_id = playersao->getPeerID();
1435 bool is_alive = playersao->getHP() > 0;
1438 SendPlayerHP(peer_id);
1440 DiePlayer(peer_id, reason);
1443 void Server::SendHP(session_t peer_id, u16 hp)
1445 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1450 void Server::SendBreath(session_t peer_id, u16 breath)
1452 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1453 pkt << (u16) breath;
1457 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1458 const std::string &custom_reason, bool reconnect)
1460 assert(reason < SERVER_ACCESSDENIED_MAX);
1462 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1464 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1465 pkt << custom_reason;
1466 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1467 reason == SERVER_ACCESSDENIED_CRASH)
1468 pkt << custom_reason << (u8)reconnect;
1472 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1474 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1479 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1480 v3f camera_point_target)
1482 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1483 pkt << set_camera_point_target << camera_point_target;
1487 void Server::SendItemDef(session_t peer_id,
1488 IItemDefManager *itemdef, u16 protocol_version)
1490 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1494 u32 length of the next item
1495 zlib-compressed serialized ItemDefManager
1497 std::ostringstream tmp_os(std::ios::binary);
1498 itemdef->serialize(tmp_os, protocol_version);
1499 std::ostringstream tmp_os2(std::ios::binary);
1500 compressZlib(tmp_os.str(), tmp_os2);
1501 pkt.putLongString(tmp_os2.str());
1504 verbosestream << "Server: Sending item definitions to id(" << peer_id
1505 << "): size=" << pkt.getSize() << std::endl;
1510 void Server::SendNodeDef(session_t peer_id,
1511 const NodeDefManager *nodedef, u16 protocol_version)
1513 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1517 u32 length of the next item
1518 zlib-compressed serialized NodeDefManager
1520 std::ostringstream tmp_os(std::ios::binary);
1521 nodedef->serialize(tmp_os, protocol_version);
1522 std::ostringstream tmp_os2(std::ios::binary);
1523 compressZlib(tmp_os.str(), tmp_os2);
1525 pkt.putLongString(tmp_os2.str());
1528 verbosestream << "Server: Sending node definitions to id(" << peer_id
1529 << "): size=" << pkt.getSize() << std::endl;
1535 Non-static send methods
1538 void Server::SendInventory(PlayerSAO* playerSAO)
1540 UpdateCrafting(playerSAO->getPlayer());
1546 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1548 std::ostringstream os;
1549 playerSAO->getInventory()->serialize(os);
1551 std::string s = os.str();
1553 pkt.putRawString(s.c_str(), s.size());
1557 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1559 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1561 u8 type = message.type;
1562 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1564 if (peer_id != PEER_ID_INEXISTENT) {
1565 RemotePlayer *player = m_env->getPlayer(peer_id);
1571 m_clients.sendToAll(&pkt);
1575 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1576 const std::string &formname)
1578 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1579 if (formspec.empty()){
1580 //the client should close the formspec
1581 //but make sure there wasn't another one open in meantime
1582 const auto it = m_formspec_state_data.find(peer_id);
1583 if (it != m_formspec_state_data.end() && it->second == formname) {
1584 m_formspec_state_data.erase(peer_id);
1586 pkt.putLongString("");
1588 m_formspec_state_data[peer_id] = formname;
1589 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1596 // Spawns a particle on peer with peer_id
1597 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1598 v3f pos, v3f velocity, v3f acceleration,
1599 float expirationtime, float size, bool collisiondetection,
1600 bool collision_removal, bool object_collision,
1601 bool vertical, const std::string &texture,
1602 const struct TileAnimationParams &animation, u8 glow)
1604 static thread_local const float radius =
1605 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1607 if (peer_id == PEER_ID_INEXISTENT) {
1608 std::vector<session_t> clients = m_clients.getClientIDs();
1610 for (const session_t client_id : clients) {
1611 RemotePlayer *player = m_env->getPlayer(client_id);
1615 PlayerSAO *sao = player->getPlayerSAO();
1619 // Do not send to distant clients
1620 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1623 SendSpawnParticle(client_id, player->protocol_version,
1624 pos, velocity, acceleration,
1625 expirationtime, size, collisiondetection, collision_removal,
1626 object_collision, vertical, texture, animation, glow);
1631 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1633 pkt << pos << velocity << acceleration << expirationtime
1634 << size << collisiondetection;
1635 pkt.putLongString(texture);
1637 pkt << collision_removal;
1638 // This is horrible but required (why are there two ways to serialize pkts?)
1639 std::ostringstream os(std::ios_base::binary);
1640 animation.serialize(os, protocol_version);
1641 pkt.putRawString(os.str());
1643 pkt << object_collision;
1648 // Adds a ParticleSpawner on peer with peer_id
1649 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1650 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1651 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1652 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1653 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1654 const struct TileAnimationParams &animation, u8 glow)
1656 if (peer_id == PEER_ID_INEXISTENT) {
1657 // This sucks and should be replaced:
1658 std::vector<session_t> clients = m_clients.getClientIDs();
1659 for (const session_t client_id : clients) {
1660 RemotePlayer *player = m_env->getPlayer(client_id);
1663 SendAddParticleSpawner(client_id, player->protocol_version,
1664 amount, spawntime, minpos, maxpos,
1665 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1666 minsize, maxsize, collisiondetection, collision_removal,
1667 object_collision, attached_id, vertical, texture, id,
1673 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1675 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1676 << minacc << maxacc << minexptime << maxexptime << minsize
1677 << maxsize << collisiondetection;
1679 pkt.putLongString(texture);
1681 pkt << id << vertical;
1682 pkt << collision_removal;
1684 // This is horrible but required
1685 std::ostringstream os(std::ios_base::binary);
1686 animation.serialize(os, protocol_version);
1687 pkt.putRawString(os.str());
1689 pkt << object_collision;
1694 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1696 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1698 // Ugly error in this packet
1701 if (peer_id != PEER_ID_INEXISTENT)
1704 m_clients.sendToAll(&pkt);
1708 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1710 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1712 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1713 << form->text << form->number << form->item << form->dir
1714 << form->align << form->offset << form->world_pos << form->size;
1719 void Server::SendHUDRemove(session_t peer_id, u32 id)
1721 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1726 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1728 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1729 pkt << id << (u8) stat;
1733 case HUD_STAT_SCALE:
1734 case HUD_STAT_ALIGN:
1735 case HUD_STAT_OFFSET:
1736 pkt << *(v2f *) value;
1740 pkt << *(std::string *) value;
1742 case HUD_STAT_WORLD_POS:
1743 pkt << *(v3f *) value;
1746 pkt << *(v2s32 *) value;
1748 case HUD_STAT_NUMBER:
1752 pkt << *(u32 *) value;
1759 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1761 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1763 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1765 pkt << flags << mask;
1770 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1772 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1773 pkt << param << value;
1777 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1778 const std::string &type, const std::vector<std::string> ¶ms,
1781 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1782 pkt << bgcolor << type << (u16) params.size();
1784 for (const std::string ¶m : params)
1792 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1794 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1795 pkt << params.density << params.color_bright << params.color_ambient
1796 << params.height << params.thickness << params.speed;
1800 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1803 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1806 pkt << do_override << (u16) (ratio * 65535);
1811 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1813 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1814 pkt << time << time_speed;
1816 if (peer_id == PEER_ID_INEXISTENT) {
1817 m_clients.sendToAll(&pkt);
1824 void Server::SendPlayerHP(session_t peer_id)
1826 PlayerSAO *playersao = getPlayerSAO(peer_id);
1827 // In some rare case if the player is disconnected
1828 // while Lua call l_punch, for example, this can be NULL
1832 SendHP(peer_id, playersao->getHP());
1833 m_script->player_event(playersao,"health_changed");
1835 // Send to other clients
1836 std::string str = gob_cmd_punched(playersao->getHP());
1837 ActiveObjectMessage aom(playersao->getId(), true, str);
1838 playersao->m_messages_out.push(aom);
1841 void Server::SendPlayerBreath(PlayerSAO *sao)
1845 m_script->player_event(sao, "breath_changed");
1846 SendBreath(sao->getPeerID(), sao->getBreath());
1849 void Server::SendMovePlayer(session_t peer_id)
1851 RemotePlayer *player = m_env->getPlayer(peer_id);
1853 PlayerSAO *sao = player->getPlayerSAO();
1856 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1857 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1860 v3f pos = sao->getBasePosition();
1861 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1862 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1863 << " pitch=" << sao->getLookPitch()
1864 << " yaw=" << sao->getRotation().Y
1871 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1872 f32 animation_speed)
1874 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1877 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1878 << animation_frames[3] << animation_speed;
1883 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1885 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1886 pkt << first << third;
1890 void Server::SendPlayerPrivileges(session_t peer_id)
1892 RemotePlayer *player = m_env->getPlayer(peer_id);
1894 if(player->getPeerId() == PEER_ID_INEXISTENT)
1897 std::set<std::string> privs;
1898 m_script->getAuth(player->getName(), NULL, &privs);
1900 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1901 pkt << (u16) privs.size();
1903 for (const std::string &priv : privs) {
1910 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1912 RemotePlayer *player = m_env->getPlayer(peer_id);
1914 if (player->getPeerId() == PEER_ID_INEXISTENT)
1917 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1918 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1922 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1924 RemotePlayer *player = m_env->getPlayer(peer_id);
1926 if (player->getPeerId() == PEER_ID_INEXISTENT)
1929 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1930 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1934 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1936 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1937 pkt.putRawString(datas.c_str(), datas.size());
1939 return pkt.getSize();
1942 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1945 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1946 datas.size(), peer_id);
1948 pkt.putRawString(datas.c_str(), datas.size());
1950 m_clients.send(pkt.getPeerId(),
1951 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1955 void Server::SendCSMRestrictionFlags(session_t peer_id)
1957 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1958 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1959 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1963 s32 Server::playSound(const SimpleSoundSpec &spec,
1964 const ServerSoundParams ¶ms)
1966 // Find out initial position of sound
1967 bool pos_exists = false;
1968 v3f pos = params.getPos(m_env, &pos_exists);
1969 // If position is not found while it should be, cancel sound
1970 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1973 // Filter destination clients
1974 std::vector<session_t> dst_clients;
1975 if(!params.to_player.empty()) {
1976 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1978 infostream<<"Server::playSound: Player \""<<params.to_player
1979 <<"\" not found"<<std::endl;
1982 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1983 infostream<<"Server::playSound: Player \""<<params.to_player
1984 <<"\" not connected"<<std::endl;
1987 dst_clients.push_back(player->getPeerId());
1989 std::vector<session_t> clients = m_clients.getClientIDs();
1991 for (const session_t client_id : clients) {
1992 RemotePlayer *player = m_env->getPlayer(client_id);
1996 PlayerSAO *sao = player->getPlayerSAO();
2001 if(sao->getBasePosition().getDistanceFrom(pos) >
2002 params.max_hear_distance)
2005 dst_clients.push_back(client_id);
2009 if(dst_clients.empty())
2013 s32 id = m_next_sound_id++;
2014 // The sound will exist as a reference in m_playing_sounds
2015 m_playing_sounds[id] = ServerPlayingSound();
2016 ServerPlayingSound &psound = m_playing_sounds[id];
2017 psound.params = params;
2020 float gain = params.gain * spec.gain;
2021 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2022 pkt << id << spec.name << gain
2023 << (u8) params.type << pos << params.object
2024 << params.loop << params.fade << params.pitch;
2026 // Backwards compability
2027 bool play_sound = gain > 0;
2029 for (const u16 dst_client : dst_clients) {
2030 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2031 psound.clients.insert(dst_client);
2032 m_clients.send(dst_client, 0, &pkt, true);
2037 void Server::stopSound(s32 handle)
2039 // Get sound reference
2040 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2041 m_playing_sounds.find(handle);
2042 if (i == m_playing_sounds.end())
2044 ServerPlayingSound &psound = i->second;
2046 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2049 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2050 si != psound.clients.end(); ++si) {
2052 m_clients.send(*si, 0, &pkt, true);
2054 // Remove sound reference
2055 m_playing_sounds.erase(i);
2058 void Server::fadeSound(s32 handle, float step, float gain)
2060 // Get sound reference
2061 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2062 m_playing_sounds.find(handle);
2063 if (i == m_playing_sounds.end())
2066 ServerPlayingSound &psound = i->second;
2067 psound.params.gain = gain;
2069 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2070 pkt << handle << step << gain;
2072 // Backwards compability
2073 bool play_sound = gain > 0;
2074 ServerPlayingSound compat_psound = psound;
2075 compat_psound.clients.clear();
2077 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2078 compat_pkt << handle;
2080 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2081 it != psound.clients.end();) {
2082 if (m_clients.getProtocolVersion(*it) >= 32) {
2084 m_clients.send(*it, 0, &pkt, true);
2087 compat_psound.clients.insert(*it);
2089 m_clients.send(*it, 0, &compat_pkt, true);
2090 psound.clients.erase(it++);
2094 // Remove sound reference
2095 if (!play_sound || psound.clients.empty())
2096 m_playing_sounds.erase(i);
2098 if (play_sound && !compat_psound.clients.empty()) {
2099 // Play new sound volume on older clients
2100 playSound(compat_psound.spec, compat_psound.params);
2104 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2107 float maxd = far_d_nodes * BS;
2108 v3f p_f = intToFloat(p, BS);
2109 v3s16 block_pos = getNodeBlockPos(p);
2111 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2114 std::vector<session_t> clients = m_clients.getClientIDs();
2117 for (session_t client_id : clients) {
2118 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2122 RemotePlayer *player = m_env->getPlayer(client_id);
2123 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2125 // If player is far away, only set modified blocks not sent
2126 if (!client->isBlockSent(block_pos) || (sao &&
2127 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2129 far_players->emplace(client_id);
2131 client->SetBlockNotSent(block_pos);
2136 m_clients.send(client_id, 0, &pkt, true);
2142 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2143 float far_d_nodes, bool remove_metadata)
2145 float maxd = far_d_nodes * BS;
2146 v3f p_f = intToFloat(p, BS);
2147 v3s16 block_pos = getNodeBlockPos(p);
2149 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2150 pkt << p << n.param0 << n.param1 << n.param2
2151 << (u8) (remove_metadata ? 0 : 1);
2153 std::vector<session_t> clients = m_clients.getClientIDs();
2156 for (session_t client_id : clients) {
2157 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2161 RemotePlayer *player = m_env->getPlayer(client_id);
2162 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2164 // If player is far away, only set modified blocks not sent
2165 if (!client->isBlockSent(block_pos) || (sao &&
2166 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2168 far_players->emplace(client_id);
2170 client->SetBlockNotSent(block_pos);
2175 m_clients.send(client_id, 0, &pkt, true);
2181 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2183 float maxd = far_d_nodes * BS;
2184 NodeMetadataList meta_updates_list(false);
2185 std::vector<session_t> clients = m_clients.getClientIDs();
2189 for (session_t i : clients) {
2190 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2194 ServerActiveObject *player = m_env->getActiveObject(i);
2195 v3f player_pos = player ? player->getBasePosition() : v3f();
2197 for (const v3s16 &pos : meta_updates) {
2198 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2203 v3s16 block_pos = getNodeBlockPos(pos);
2204 if (!client->isBlockSent(block_pos) || (player &&
2205 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2206 client->SetBlockNotSent(block_pos);
2210 // Add the change to send list
2211 meta_updates_list.set(pos, meta);
2213 if (meta_updates_list.size() == 0)
2216 // Send the meta changes
2217 std::ostringstream os(std::ios::binary);
2218 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2219 std::ostringstream oss(std::ios::binary);
2220 compressZlib(os.str(), oss);
2222 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2223 pkt.putLongString(oss.str());
2224 m_clients.send(i, 0, &pkt, true);
2226 meta_updates_list.clear();
2232 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2233 u16 net_proto_version)
2236 Create a packet with the block in the right format
2239 std::ostringstream os(std::ios_base::binary);
2240 block->serialize(os, ver, false);
2241 block->serializeNetworkSpecific(os);
2242 std::string s = os.str();
2244 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2246 pkt << block->getPos();
2247 pkt.putRawString(s.c_str(), s.size());
2251 void Server::SendBlocks(float dtime)
2253 MutexAutoLock envlock(m_env_mutex);
2254 //TODO check if one big lock could be faster then multiple small ones
2256 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2258 std::vector<PrioritySortedBlockTransfer> queue;
2260 u32 total_sending = 0;
2263 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2265 std::vector<session_t> clients = m_clients.getClientIDs();
2268 for (const session_t client_id : clients) {
2269 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2274 total_sending += client->getSendingCount();
2275 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2281 // Lowest priority number comes first.
2282 // Lowest is most important.
2283 std::sort(queue.begin(), queue.end());
2287 // Maximal total count calculation
2288 // The per-client block sends is halved with the maximal online users
2289 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2290 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2292 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2293 if (total_sending >= max_blocks_to_send)
2296 MapBlock *block = nullptr;
2298 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2299 } catch (const InvalidPositionException &e) {
2303 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2308 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2309 client->net_proto_version);
2311 client->SentBlock(block_to_send.pos);
2317 void Server::fillMediaCache()
2319 infostream<<"Server: Calculating media file checksums"<<std::endl;
2321 // Collect all media file paths
2322 std::vector<std::string> paths;
2323 m_modmgr->getModsMediaPaths(paths);
2324 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2325 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2327 // Collect media file information from paths into cache
2328 for (const std::string &mediapath : paths) {
2329 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2330 for (const fs::DirListNode &dln : dirlist) {
2331 if (dln.dir) // Ignode dirs
2333 std::string filename = dln.name;
2334 // If name contains illegal characters, ignore the file
2335 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2336 infostream<<"Server: ignoring illegal file name: \""
2337 << filename << "\"" << std::endl;
2340 // If name is not in a supported format, ignore it
2341 const char *supported_ext[] = {
2342 ".png", ".jpg", ".bmp", ".tga",
2343 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2345 ".x", ".b3d", ".md2", ".obj",
2346 // Custom translation file format
2350 if (removeStringEnd(filename, supported_ext).empty()){
2351 infostream << "Server: ignoring unsupported file extension: \""
2352 << filename << "\"" << std::endl;
2355 // Ok, attempt to load the file and add to cache
2356 std::string filepath;
2357 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2360 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2362 errorstream << "Server::fillMediaCache(): Could not open \""
2363 << filename << "\" for reading" << std::endl;
2366 std::ostringstream tmp_os(std::ios_base::binary);
2370 fis.read(buf, 1024);
2371 std::streamsize len = fis.gcount();
2372 tmp_os.write(buf, len);
2381 errorstream<<"Server::fillMediaCache(): Failed to read \""
2382 << filename << "\"" << std::endl;
2385 if(tmp_os.str().length() == 0) {
2386 errorstream << "Server::fillMediaCache(): Empty file \""
2387 << filepath << "\"" << std::endl;
2392 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2394 unsigned char *digest = sha1.getDigest();
2395 std::string sha1_base64 = base64_encode(digest, 20);
2396 std::string sha1_hex = hex_encode((char*)digest, 20);
2400 m_media[filename] = MediaInfo(filepath, sha1_base64);
2401 verbosestream << "Server: " << sha1_hex << " is " << filename
2407 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2409 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2413 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2416 std::string lang_suffix;
2417 lang_suffix.append(".").append(lang_code).append(".tr");
2418 for (const auto &i : m_media) {
2419 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2426 for (const auto &i : m_media) {
2427 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2429 pkt << i.first << i.second.sha1_digest;
2432 pkt << g_settings->get("remote_media");
2436 struct SendableMedia
2442 SendableMedia(const std::string &name_="", const std::string &path_="",
2443 const std::string &data_=""):
2450 void Server::sendRequestedMedia(session_t peer_id,
2451 const std::vector<std::string> &tosend)
2453 verbosestream<<"Server::sendRequestedMedia(): "
2454 <<"Sending files to client"<<std::endl;
2458 // Put 5kB in one bunch (this is not accurate)
2459 u32 bytes_per_bunch = 5000;
2461 std::vector< std::vector<SendableMedia> > file_bunches;
2462 file_bunches.emplace_back();
2464 u32 file_size_bunch_total = 0;
2466 for (const std::string &name : tosend) {
2467 if (m_media.find(name) == m_media.end()) {
2468 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2469 <<"unknown file \""<<(name)<<"\""<<std::endl;
2473 //TODO get path + name
2474 std::string tpath = m_media[name].path;
2477 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2479 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2480 <<tpath<<"\" for reading"<<std::endl;
2483 std::ostringstream tmp_os(std::ios_base::binary);
2487 fis.read(buf, 1024);
2488 std::streamsize len = fis.gcount();
2489 tmp_os.write(buf, len);
2490 file_size_bunch_total += len;
2499 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2500 <<name<<"\""<<std::endl;
2503 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2504 <<tname<<"\""<<std::endl;*/
2506 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2508 // Start next bunch if got enough data
2509 if(file_size_bunch_total >= bytes_per_bunch) {
2510 file_bunches.emplace_back();
2511 file_size_bunch_total = 0;
2516 /* Create and send packets */
2518 u16 num_bunches = file_bunches.size();
2519 for (u16 i = 0; i < num_bunches; i++) {
2522 u16 total number of texture bunches
2523 u16 index of this bunch
2524 u32 number of files in this bunch
2533 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2534 pkt << num_bunches << i << (u32) file_bunches[i].size();
2536 for (const SendableMedia &j : file_bunches[i]) {
2538 pkt.putLongString(j.data);
2541 verbosestream << "Server::sendRequestedMedia(): bunch "
2542 << i << "/" << num_bunches
2543 << " files=" << file_bunches[i].size()
2544 << " size=" << pkt.getSize() << std::endl;
2549 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2551 const auto &inv_it = m_detached_inventories.find(name);
2552 const auto &player_it = m_detached_inventories_player.find(name);
2554 if (player_it == m_detached_inventories_player.end() ||
2555 player_it->second.empty()) {
2556 // OK. Send to everyone
2558 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2560 return; // Player is offline
2562 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2563 return; // Caller requested send to a different player, so don't send.
2565 peer_id = p->getPeerId();
2568 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2571 if (inv_it == m_detached_inventories.end()) {
2572 pkt << false; // Remove inventory
2574 pkt << true; // Update inventory
2576 // Serialization & NetworkPacket isn't a love story
2577 std::ostringstream os(std::ios_base::binary);
2578 inv_it->second->serialize(os);
2580 std::string os_str = os.str();
2581 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2582 pkt.putRawString(os_str);
2585 if (peer_id == PEER_ID_INEXISTENT)
2586 m_clients.sendToAll(&pkt);
2591 void Server::sendDetachedInventories(session_t peer_id)
2593 for (const auto &detached_inventory : m_detached_inventories) {
2594 const std::string &name = detached_inventory.first;
2595 //Inventory *inv = i->second;
2596 sendDetachedInventory(name, peer_id);
2604 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2606 PlayerSAO *playersao = getPlayerSAO(peer_id);
2607 // In some rare cases this can be NULL -- if the player is disconnected
2608 // when a Lua function modifies l_punch, for example
2612 infostream << "Server::DiePlayer(): Player "
2613 << playersao->getPlayer()->getName()
2614 << " dies" << std::endl;
2616 playersao->setHP(0, reason);
2617 playersao->clearParentAttachment();
2619 // Trigger scripted stuff
2620 m_script->on_dieplayer(playersao, reason);
2622 SendPlayerHP(peer_id);
2623 SendDeathscreen(peer_id, false, v3f(0,0,0));
2626 void Server::RespawnPlayer(session_t peer_id)
2628 PlayerSAO *playersao = getPlayerSAO(peer_id);
2631 infostream << "Server::RespawnPlayer(): Player "
2632 << playersao->getPlayer()->getName()
2633 << " respawns" << std::endl;
2635 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2636 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2637 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2639 bool repositioned = m_script->on_respawnplayer(playersao);
2640 if (!repositioned) {
2641 // setPos will send the new position to client
2642 playersao->setPos(findSpawnPos());
2645 SendPlayerHP(peer_id);
2649 void Server::DenySudoAccess(session_t peer_id)
2651 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2656 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2657 const std::string &str_reason, bool reconnect)
2659 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2661 m_clients.event(peer_id, CSE_SetDenied);
2662 DisconnectPeer(peer_id);
2666 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2667 const std::string &custom_reason)
2669 SendAccessDenied(peer_id, reason, custom_reason);
2670 m_clients.event(peer_id, CSE_SetDenied);
2671 DisconnectPeer(peer_id);
2674 // 13/03/15: remove this function when protocol version 25 will become
2675 // the minimum version for MT users, maybe in 1 year
2676 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2678 SendAccessDenied_Legacy(peer_id, reason);
2679 m_clients.event(peer_id, CSE_SetDenied);
2680 DisconnectPeer(peer_id);
2683 void Server::DisconnectPeer(session_t peer_id)
2685 m_modchannel_mgr->leaveAllChannels(peer_id);
2686 m_con->DisconnectPeer(peer_id);
2689 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2692 RemoteClient* client = getClient(peer_id, CS_Invalid);
2694 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2696 // Right now, the auth mechs don't change between login and sudo mode.
2697 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2698 client->allowed_sudo_mechs = sudo_auth_mechs;
2700 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2701 << g_settings->getFloat("dedicated_server_step")
2705 m_clients.event(peer_id, CSE_AuthAccept);
2707 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2709 // We only support SRP right now
2710 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2712 resp_pkt << sudo_auth_mechs;
2714 m_clients.event(peer_id, CSE_SudoSuccess);
2718 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2720 std::wstring message;
2723 Clear references to playing sounds
2725 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2726 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2727 ServerPlayingSound &psound = i->second;
2728 psound.clients.erase(peer_id);
2729 if (psound.clients.empty())
2730 m_playing_sounds.erase(i++);
2735 // clear formspec info so the next client can't abuse the current state
2736 m_formspec_state_data.erase(peer_id);
2738 RemotePlayer *player = m_env->getPlayer(peer_id);
2740 /* Run scripts and remove from environment */
2742 PlayerSAO *playersao = player->getPlayerSAO();
2745 playersao->clearChildAttachments();
2746 playersao->clearParentAttachment();
2748 // inform connected clients
2749 const std::string &player_name = player->getName();
2750 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2751 // (u16) 1 + std::string represents a vector serialization representation
2752 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2753 m_clients.sendToAll(¬ice);
2755 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2757 playersao->disconnected();
2764 if (player && reason != CDR_DENY) {
2765 std::ostringstream os(std::ios_base::binary);
2766 std::vector<session_t> clients = m_clients.getClientIDs();
2768 for (const session_t client_id : clients) {
2770 RemotePlayer *player = m_env->getPlayer(client_id);
2774 // Get name of player
2775 os << player->getName() << " ";
2778 std::string name = player->getName();
2779 actionstream << name << " "
2780 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2781 << " List of players: " << os.str() << std::endl;
2783 m_admin_chat->outgoing_queue.push_back(
2784 new ChatEventNick(CET_NICK_REMOVE, name));
2788 MutexAutoLock env_lock(m_env_mutex);
2789 m_clients.DeleteClient(peer_id);
2793 // Send leave chat message to all remaining clients
2794 if (!message.empty()) {
2795 SendChatMessage(PEER_ID_INEXISTENT,
2796 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2800 void Server::UpdateCrafting(RemotePlayer *player)
2802 InventoryList *clist = player->inventory.getList("craft");
2803 if (!clist || clist->getSize() == 0)
2806 // Get a preview for crafting
2808 InventoryLocation loc;
2809 loc.setPlayer(player->getName());
2810 std::vector<ItemStack> output_replacements;
2811 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2812 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2815 InventoryList *plist = player->inventory.getList("craftpreview");
2816 if (plist && plist->getSize() >= 1) {
2817 // Put the new preview in
2818 plist->changeItem(0, preview);
2822 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2824 if (evt->type == CET_NICK_ADD) {
2825 // The terminal informed us of its nick choice
2826 m_admin_nick = ((ChatEventNick *)evt)->nick;
2827 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2828 errorstream << "You haven't set up an account." << std::endl
2829 << "Please log in using the client as '"
2830 << m_admin_nick << "' with a secure password." << std::endl
2831 << "Until then, you can't execute admin tasks via the console," << std::endl
2832 << "and everybody can claim the user account instead of you," << std::endl
2833 << "giving them full control over this server." << std::endl;
2836 assert(evt->type == CET_CHAT);
2837 handleAdminChat((ChatEventChat *)evt);
2841 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2842 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2844 // If something goes wrong, this player is to blame
2845 RollbackScopeActor rollback_scope(m_rollback,
2846 std::string("player:") + name);
2848 if (g_settings->getBool("strip_color_codes"))
2849 wmessage = unescape_enriched(wmessage);
2852 switch (player->canSendChatMessage()) {
2853 case RPLAYER_CHATRESULT_FLOODING: {
2854 std::wstringstream ws;
2855 ws << L"You cannot send more messages. You are limited to "
2856 << g_settings->getFloat("chat_message_limit_per_10sec")
2857 << L" messages per 10 seconds.";
2860 case RPLAYER_CHATRESULT_KICK:
2861 DenyAccess_Legacy(player->getPeerId(),
2862 L"You have been kicked due to message flooding.");
2864 case RPLAYER_CHATRESULT_OK:
2867 FATAL_ERROR("Unhandled chat filtering result found.");
2871 if (m_max_chatmessage_length > 0
2872 && wmessage.length() > m_max_chatmessage_length) {
2873 return L"Your message exceed the maximum chat message limit set on the server. "
2874 L"It was refused. Send a shorter message";
2877 auto message = trim(wide_to_utf8(wmessage));
2878 if (message.find_first_of("\n\r") != std::wstring::npos) {
2879 return L"New lines are not permitted in chat messages";
2882 // Run script hook, exit if script ate the chat message
2883 if (m_script->on_chat_message(name, message))
2888 // Whether to send line to the player that sent the message, or to all players
2889 bool broadcast_line = true;
2891 if (check_shout_priv && !checkPriv(name, "shout")) {
2892 line += L"-!- You don't have permission to shout.";
2893 broadcast_line = false;
2902 Tell calling method to send the message to sender
2904 if (!broadcast_line)
2908 Send the message to others
2910 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2912 std::vector<session_t> clients = m_clients.getClientIDs();
2915 Send the message back to the inital sender
2916 if they are using protocol version >= 29
2919 session_t peer_id_to_avoid_sending =
2920 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2922 if (player && player->protocol_version >= 29)
2923 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2925 for (u16 cid : clients) {
2926 if (cid != peer_id_to_avoid_sending)
2927 SendChatMessage(cid, ChatMessage(line));
2932 void Server::handleAdminChat(const ChatEventChat *evt)
2934 std::string name = evt->nick;
2935 std::wstring wname = utf8_to_wide(name);
2936 std::wstring wmessage = evt->evt_msg;
2938 std::wstring answer = handleChat(name, wname, wmessage);
2940 // If asked to send answer to sender
2941 if (!answer.empty()) {
2942 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2946 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2948 RemoteClient *client = getClientNoEx(peer_id,state_min);
2950 throw ClientNotFoundException("Client not found");
2954 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2956 return m_clients.getClientNoEx(peer_id, state_min);
2959 std::string Server::getPlayerName(session_t peer_id)
2961 RemotePlayer *player = m_env->getPlayer(peer_id);
2963 return "[id="+itos(peer_id)+"]";
2964 return player->getName();
2967 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2969 RemotePlayer *player = m_env->getPlayer(peer_id);
2972 return player->getPlayerSAO();
2975 std::wstring Server::getStatusString()
2977 std::wostringstream os(std::ios_base::binary);
2978 os << L"# Server: ";
2980 os << L"version=" << narrow_to_wide(g_version_string);
2982 os << L", uptime=" << m_uptime.get();
2984 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
2986 // Information about clients
2988 os << L", clients={";
2990 std::vector<session_t> clients = m_clients.getClientIDs();
2991 for (session_t client_id : clients) {
2992 RemotePlayer *player = m_env->getPlayer(client_id);
2994 // Get name of player
2995 std::wstring name = L"unknown";
2997 name = narrow_to_wide(player->getName());
2999 // Add name to information string
3010 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3011 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3013 if (!g_settings->get("motd").empty())
3014 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3019 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3021 std::set<std::string> privs;
3022 m_script->getAuth(name, NULL, &privs);
3026 bool Server::checkPriv(const std::string &name, const std::string &priv)
3028 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3029 return (privs.count(priv) != 0);
3032 void Server::reportPrivsModified(const std::string &name)
3035 std::vector<session_t> clients = m_clients.getClientIDs();
3036 for (const session_t client_id : clients) {
3037 RemotePlayer *player = m_env->getPlayer(client_id);
3038 reportPrivsModified(player->getName());
3041 RemotePlayer *player = m_env->getPlayer(name.c_str());
3044 SendPlayerPrivileges(player->getPeerId());
3045 PlayerSAO *sao = player->getPlayerSAO();
3048 sao->updatePrivileges(
3049 getPlayerEffectivePrivs(name),
3054 void Server::reportInventoryFormspecModified(const std::string &name)
3056 RemotePlayer *player = m_env->getPlayer(name.c_str());
3059 SendPlayerInventoryFormspec(player->getPeerId());
3062 void Server::reportFormspecPrependModified(const std::string &name)
3064 RemotePlayer *player = m_env->getPlayer(name.c_str());
3067 SendPlayerFormspecPrepend(player->getPeerId());
3070 void Server::setIpBanned(const std::string &ip, const std::string &name)
3072 m_banmanager->add(ip, name);
3075 void Server::unsetIpBanned(const std::string &ip_or_name)
3077 m_banmanager->remove(ip_or_name);
3080 std::string Server::getBanDescription(const std::string &ip_or_name)
3082 return m_banmanager->getBanDescription(ip_or_name);
3085 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3087 // m_env will be NULL if the server is initializing
3091 if (m_admin_nick == name && !m_admin_nick.empty()) {
3092 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3095 RemotePlayer *player = m_env->getPlayer(name);
3100 if (player->getPeerId() == PEER_ID_INEXISTENT)
3103 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3106 bool Server::showFormspec(const char *playername, const std::string &formspec,
3107 const std::string &formname)
3109 // m_env will be NULL if the server is initializing
3113 RemotePlayer *player = m_env->getPlayer(playername);
3117 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3121 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3126 u32 id = player->addHud(form);
3128 SendHUDAdd(player->getPeerId(), id, form);
3133 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3137 HudElement* todel = player->removeHud(id);
3144 SendHUDRemove(player->getPeerId(), id);
3148 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3153 SendHUDChange(player->getPeerId(), id, stat, data);
3157 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3162 SendHUDSetFlags(player->getPeerId(), flags, mask);
3163 player->hud_flags &= ~mask;
3164 player->hud_flags |= flags;
3166 PlayerSAO* playersao = player->getPlayerSAO();
3171 m_script->player_event(playersao, "hud_changed");
3175 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3180 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3183 player->setHotbarItemcount(hotbar_itemcount);
3184 std::ostringstream os(std::ios::binary);
3185 writeS32(os, hotbar_itemcount);
3186 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3190 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3195 player->setHotbarImage(name);
3196 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3199 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3204 player->setHotbarSelectedImage(name);
3205 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3208 Address Server::getPeerAddress(session_t peer_id)
3210 return m_con->GetPeerAddress(peer_id);
3213 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3214 v2s32 animation_frames[4], f32 frame_speed)
3216 sanity_check(player);
3217 player->setLocalAnimations(animation_frames, frame_speed);
3218 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3221 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3223 sanity_check(player);
3224 player->eye_offset_first = first;
3225 player->eye_offset_third = third;
3226 SendEyeOffset(player->getPeerId(), first, third);
3229 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3230 const std::string &type, const std::vector<std::string> ¶ms,
3233 sanity_check(player);
3234 player->setSky(bgcolor, type, params, clouds);
3235 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3238 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3240 sanity_check(player);
3241 player->setCloudParams(params);
3242 SendCloudParams(player->getPeerId(), params);
3245 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3251 player->overrideDayNightRatio(do_override, ratio);
3252 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3256 void Server::notifyPlayers(const std::wstring &msg)
3258 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3261 void Server::spawnParticle(const std::string &playername, v3f pos,
3262 v3f velocity, v3f acceleration,
3263 float expirationtime, float size, bool
3264 collisiondetection, bool collision_removal, bool object_collision,
3265 bool vertical, const std::string &texture,
3266 const struct TileAnimationParams &animation, u8 glow)
3268 // m_env will be NULL if the server is initializing
3272 session_t peer_id = PEER_ID_INEXISTENT;
3274 if (!playername.empty()) {
3275 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3278 peer_id = player->getPeerId();
3279 proto_ver = player->protocol_version;
3282 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3283 expirationtime, size, collisiondetection, collision_removal,
3284 object_collision, vertical, texture, animation, glow);
3287 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3288 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3289 float minexptime, float maxexptime, float minsize, float maxsize,
3290 bool collisiondetection, bool collision_removal, bool object_collision,
3291 ServerActiveObject *attached, bool vertical, const std::string &texture,
3292 const std::string &playername, const struct TileAnimationParams &animation,
3295 // m_env will be NULL if the server is initializing
3299 session_t peer_id = PEER_ID_INEXISTENT;
3301 if (!playername.empty()) {
3302 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3305 peer_id = player->getPeerId();
3306 proto_ver = player->protocol_version;
3309 u16 attached_id = attached ? attached->getId() : 0;
3312 if (attached_id == 0)
3313 id = m_env->addParticleSpawner(spawntime);
3315 id = m_env->addParticleSpawner(spawntime, attached_id);
3317 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3318 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3319 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3320 collision_removal, object_collision, attached_id, vertical,
3321 texture, id, animation, glow);
3326 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3328 // m_env will be NULL if the server is initializing
3330 throw ServerError("Can't delete particle spawners during initialisation!");
3332 session_t peer_id = PEER_ID_INEXISTENT;
3333 if (!playername.empty()) {
3334 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3337 peer_id = player->getPeerId();
3340 m_env->deleteParticleSpawner(id);
3341 SendDeleteParticleSpawner(peer_id, id);
3344 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3346 if(m_detached_inventories.count(name) > 0){
3347 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3348 delete m_detached_inventories[name];
3350 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3352 Inventory *inv = new Inventory(m_itemdef);
3354 m_detached_inventories[name] = inv;
3355 m_detached_inventories_player[name] = player;
3356 //TODO find a better way to do this
3357 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3361 bool Server::removeDetachedInventory(const std::string &name)
3363 const auto &inv_it = m_detached_inventories.find(name);
3364 if (inv_it == m_detached_inventories.end())
3367 delete inv_it->second;
3368 m_detached_inventories.erase(inv_it);
3370 const auto &player_it = m_detached_inventories_player.find(name);
3371 if (player_it != m_detached_inventories_player.end()) {
3372 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3374 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3375 sendDetachedInventory(name, player->getPeerId());
3377 m_detached_inventories_player.erase(player_it);
3379 // Notify all players about the change
3380 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3385 // actions: time-reversed list
3386 // Return value: success/failure
3387 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3388 std::list<std::string> *log)
3390 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3391 ServerMap *map = (ServerMap*)(&m_env->getMap());
3393 // Fail if no actions to handle
3394 if (actions.empty()) {
3396 log->push_back("Nothing to do.");
3403 for (const RollbackAction &action : actions) {
3405 bool success = action.applyRevert(map, this, this);
3408 std::ostringstream os;
3409 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3410 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3412 log->push_back(os.str());
3414 std::ostringstream os;
3415 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3416 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3418 log->push_back(os.str());
3422 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3423 <<" failed"<<std::endl;
3425 // Call it done if less than half failed
3426 return num_failed <= num_tried/2;
3429 // IGameDef interface
3431 IItemDefManager *Server::getItemDefManager()
3436 const NodeDefManager *Server::getNodeDefManager()
3441 ICraftDefManager *Server::getCraftDefManager()
3446 u16 Server::allocateUnknownNodeId(const std::string &name)
3448 return m_nodedef->allocateDummy(name);
3451 IWritableItemDefManager *Server::getWritableItemDefManager()
3456 NodeDefManager *Server::getWritableNodeDefManager()
3461 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3466 const std::vector<ModSpec> & Server::getMods() const
3468 return m_modmgr->getMods();
3471 const ModSpec *Server::getModSpec(const std::string &modname) const
3473 return m_modmgr->getModSpec(modname);
3476 void Server::getModNames(std::vector<std::string> &modlist)
3478 m_modmgr->getModNames(modlist);
3481 std::string Server::getBuiltinLuaPath()
3483 return porting::path_share + DIR_DELIM + "builtin";
3486 std::string Server::getModStoragePath() const
3488 return m_path_world + DIR_DELIM + "mod_storage";
3491 v3f Server::findSpawnPos()
3493 ServerMap &map = m_env->getServerMap();
3495 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3496 return nodeposf * BS;
3499 bool is_good = false;
3500 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3501 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3503 // Try to find a good place a few times
3504 for(s32 i = 0; i < 4000 && !is_good; i++) {
3505 s32 range = MYMIN(1 + i, range_max);
3506 // We're going to try to throw the player to this position
3507 v2s16 nodepos2d = v2s16(
3508 -range + (myrand() % (range * 2)),
3509 -range + (myrand() % (range * 2)));
3511 // Get spawn level at point
3512 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3513 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3514 // the mapgen to signify an unsuitable spawn position
3515 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3518 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3521 for (s32 i = 0; i < 10; i++) {
3522 v3s16 blockpos = getNodeBlockPos(nodepos);
3523 map.emergeBlock(blockpos, true);
3524 content_t c = map.getNodeNoEx(nodepos).getContent();
3525 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3527 if (air_count >= 2) {
3528 nodeposf = intToFloat(nodepos, BS);
3529 // Don't spawn the player outside map boundaries
3530 if (objectpos_over_limit(nodeposf))
3543 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3545 if (delay == 0.0f) {
3546 // No delay, shutdown immediately
3547 m_shutdown_state.is_requested = true;
3548 // only print to the infostream, a chat message saying
3549 // "Server Shutting Down" is sent when the server destructs.
3550 infostream << "*** Immediate Server shutdown requested." << std::endl;
3551 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3552 // Negative delay, cancel shutdown if requested
3553 m_shutdown_state.reset();
3554 std::wstringstream ws;
3556 ws << L"*** Server shutdown canceled.";
3558 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3559 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3560 // m_shutdown_* are already handled, skip.
3562 } else if (delay > 0.0f) {
3563 // Positive delay, tell the clients when the server will shut down
3564 std::wstringstream ws;
3566 ws << L"*** Server shutting down in "
3567 << duration_to_string(myround(delay)).c_str()
3570 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3571 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3574 m_shutdown_state.trigger(delay, msg, reconnect);
3577 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3580 Try to get an existing player
3582 RemotePlayer *player = m_env->getPlayer(name);
3584 // If player is already connected, cancel
3585 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3586 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3591 If player with the wanted peer_id already exists, cancel.
3593 if (m_env->getPlayer(peer_id)) {
3594 infostream<<"emergePlayer(): Player with wrong name but same"
3595 " peer_id already exists"<<std::endl;
3600 player = new RemotePlayer(name, idef());
3603 bool newplayer = false;
3606 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3608 // Complete init with server parts
3609 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3610 player->protocol_version = proto_version;
3614 m_script->on_newplayer(playersao);
3620 bool Server::registerModStorage(ModMetadata *storage)
3622 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3623 errorstream << "Unable to register same mod storage twice. Storage name: "
3624 << storage->getModName() << std::endl;
3628 m_mod_storages[storage->getModName()] = storage;
3632 void Server::unregisterModStorage(const std::string &name)
3634 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3635 if (it != m_mod_storages.end()) {
3636 // Save unconditionaly on unregistration
3637 it->second->save(getModStoragePath());
3638 m_mod_storages.erase(name);
3642 void dedicated_server_loop(Server &server, bool &kill)
3644 verbosestream<<"dedicated_server_loop()"<<std::endl;
3646 IntervalLimiter m_profiler_interval;
3648 static thread_local const float steplen =
3649 g_settings->getFloat("dedicated_server_step");
3650 static thread_local const float profiler_print_interval =
3651 g_settings->getFloat("profiler_print_interval");
3654 // This is kind of a hack but can be done like this
3655 // because server.step() is very light
3657 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3658 sleep_ms((int)(steplen*1000.0));
3660 server.step(steplen);
3662 if (server.isShutdownRequested() || kill)
3668 if (profiler_print_interval != 0) {
3669 if(m_profiler_interval.step(steplen, profiler_print_interval))
3671 infostream<<"Profiler:"<<std::endl;
3672 g_profiler->print(infostream);
3673 g_profiler->clear();
3678 infostream << "Dedicated server quitting" << std::endl;
3680 if (g_settings->getBool("server_announce"))
3681 ServerList::sendAnnounce(ServerList::AA_DELETE,
3682 server.m_bind_addr.getPort());
3691 bool Server::joinModChannel(const std::string &channel)
3693 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3694 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3697 bool Server::leaveModChannel(const std::string &channel)
3699 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3702 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3704 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3707 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3711 ModChannel* Server::getModChannel(const std::string &channel)
3713 return m_modchannel_mgr->getModChannel(channel);
3716 void Server::broadcastModChannelMessage(const std::string &channel,
3717 const std::string &message, session_t from_peer)
3719 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3723 if (message.size() > STRING_MAX_LEN) {
3724 warningstream << "ModChannel message too long, dropping before sending "
3725 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3726 << channel << ")" << std::endl;
3731 if (from_peer != PEER_ID_SERVER) {
3732 sender = getPlayerName(from_peer);
3735 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3736 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3737 resp_pkt << channel << sender << message;
3738 for (session_t peer_id : peers) {
3740 if (peer_id == from_peer)
3743 Send(peer_id, &resp_pkt);
3746 if (from_peer != PEER_ID_SERVER) {
3747 m_script->on_modchannel_message(channel, sender, message);