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 << 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);
2582 if (peer_id == PEER_ID_INEXISTENT)
2583 m_clients.sendToAll(&pkt);
2588 void Server::sendDetachedInventories(session_t peer_id)
2590 for (const auto &detached_inventory : m_detached_inventories) {
2591 const std::string &name = detached_inventory.first;
2592 //Inventory *inv = i->second;
2593 sendDetachedInventory(name, peer_id);
2601 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2603 PlayerSAO *playersao = getPlayerSAO(peer_id);
2604 // In some rare cases this can be NULL -- if the player is disconnected
2605 // when a Lua function modifies l_punch, for example
2609 infostream << "Server::DiePlayer(): Player "
2610 << playersao->getPlayer()->getName()
2611 << " dies" << std::endl;
2613 playersao->setHP(0, reason);
2614 playersao->clearParentAttachment();
2616 // Trigger scripted stuff
2617 m_script->on_dieplayer(playersao, reason);
2619 SendPlayerHP(peer_id);
2620 SendDeathscreen(peer_id, false, v3f(0,0,0));
2623 void Server::RespawnPlayer(session_t peer_id)
2625 PlayerSAO *playersao = getPlayerSAO(peer_id);
2628 infostream << "Server::RespawnPlayer(): Player "
2629 << playersao->getPlayer()->getName()
2630 << " respawns" << std::endl;
2632 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2633 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2634 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2636 bool repositioned = m_script->on_respawnplayer(playersao);
2637 if (!repositioned) {
2638 // setPos will send the new position to client
2639 playersao->setPos(findSpawnPos());
2642 SendPlayerHP(peer_id);
2646 void Server::DenySudoAccess(session_t peer_id)
2648 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2653 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2654 const std::string &str_reason, bool reconnect)
2656 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2658 m_clients.event(peer_id, CSE_SetDenied);
2659 DisconnectPeer(peer_id);
2663 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2664 const std::string &custom_reason)
2666 SendAccessDenied(peer_id, reason, custom_reason);
2667 m_clients.event(peer_id, CSE_SetDenied);
2668 DisconnectPeer(peer_id);
2671 // 13/03/15: remove this function when protocol version 25 will become
2672 // the minimum version for MT users, maybe in 1 year
2673 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2675 SendAccessDenied_Legacy(peer_id, reason);
2676 m_clients.event(peer_id, CSE_SetDenied);
2677 DisconnectPeer(peer_id);
2680 void Server::DisconnectPeer(session_t peer_id)
2682 m_modchannel_mgr->leaveAllChannels(peer_id);
2683 m_con->DisconnectPeer(peer_id);
2686 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2689 RemoteClient* client = getClient(peer_id, CS_Invalid);
2691 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2693 // Right now, the auth mechs don't change between login and sudo mode.
2694 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2695 client->allowed_sudo_mechs = sudo_auth_mechs;
2697 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2698 << g_settings->getFloat("dedicated_server_step")
2702 m_clients.event(peer_id, CSE_AuthAccept);
2704 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2706 // We only support SRP right now
2707 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2709 resp_pkt << sudo_auth_mechs;
2711 m_clients.event(peer_id, CSE_SudoSuccess);
2715 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2717 std::wstring message;
2720 Clear references to playing sounds
2722 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2723 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2724 ServerPlayingSound &psound = i->second;
2725 psound.clients.erase(peer_id);
2726 if (psound.clients.empty())
2727 m_playing_sounds.erase(i++);
2732 // clear formspec info so the next client can't abuse the current state
2733 m_formspec_state_data.erase(peer_id);
2735 RemotePlayer *player = m_env->getPlayer(peer_id);
2737 /* Run scripts and remove from environment */
2739 PlayerSAO *playersao = player->getPlayerSAO();
2742 playersao->clearChildAttachments();
2743 playersao->clearParentAttachment();
2745 // inform connected clients
2746 const std::string &player_name = player->getName();
2747 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2748 // (u16) 1 + std::string represents a vector serialization representation
2749 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2750 m_clients.sendToAll(¬ice);
2752 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2754 playersao->disconnected();
2761 if (player && reason != CDR_DENY) {
2762 std::ostringstream os(std::ios_base::binary);
2763 std::vector<session_t> clients = m_clients.getClientIDs();
2765 for (const session_t client_id : clients) {
2767 RemotePlayer *player = m_env->getPlayer(client_id);
2771 // Get name of player
2772 os << player->getName() << " ";
2775 std::string name = player->getName();
2776 actionstream << name << " "
2777 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2778 << " List of players: " << os.str() << std::endl;
2780 m_admin_chat->outgoing_queue.push_back(
2781 new ChatEventNick(CET_NICK_REMOVE, name));
2785 MutexAutoLock env_lock(m_env_mutex);
2786 m_clients.DeleteClient(peer_id);
2790 // Send leave chat message to all remaining clients
2791 if (!message.empty()) {
2792 SendChatMessage(PEER_ID_INEXISTENT,
2793 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2797 void Server::UpdateCrafting(RemotePlayer *player)
2799 InventoryList *clist = player->inventory.getList("craft");
2800 if (!clist || clist->getSize() == 0)
2803 // Get a preview for crafting
2805 InventoryLocation loc;
2806 loc.setPlayer(player->getName());
2807 std::vector<ItemStack> output_replacements;
2808 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2809 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2812 InventoryList *plist = player->inventory.getList("craftpreview");
2813 if (plist && plist->getSize() >= 1) {
2814 // Put the new preview in
2815 plist->changeItem(0, preview);
2819 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2821 if (evt->type == CET_NICK_ADD) {
2822 // The terminal informed us of its nick choice
2823 m_admin_nick = ((ChatEventNick *)evt)->nick;
2824 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2825 errorstream << "You haven't set up an account." << std::endl
2826 << "Please log in using the client as '"
2827 << m_admin_nick << "' with a secure password." << std::endl
2828 << "Until then, you can't execute admin tasks via the console," << std::endl
2829 << "and everybody can claim the user account instead of you," << std::endl
2830 << "giving them full control over this server." << std::endl;
2833 assert(evt->type == CET_CHAT);
2834 handleAdminChat((ChatEventChat *)evt);
2838 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2839 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2841 // If something goes wrong, this player is to blame
2842 RollbackScopeActor rollback_scope(m_rollback,
2843 std::string("player:") + name);
2845 if (g_settings->getBool("strip_color_codes"))
2846 wmessage = unescape_enriched(wmessage);
2849 switch (player->canSendChatMessage()) {
2850 case RPLAYER_CHATRESULT_FLOODING: {
2851 std::wstringstream ws;
2852 ws << L"You cannot send more messages. You are limited to "
2853 << g_settings->getFloat("chat_message_limit_per_10sec")
2854 << L" messages per 10 seconds.";
2857 case RPLAYER_CHATRESULT_KICK:
2858 DenyAccess_Legacy(player->getPeerId(),
2859 L"You have been kicked due to message flooding.");
2861 case RPLAYER_CHATRESULT_OK:
2864 FATAL_ERROR("Unhandled chat filtering result found.");
2868 if (m_max_chatmessage_length > 0
2869 && wmessage.length() > m_max_chatmessage_length) {
2870 return L"Your message exceed the maximum chat message limit set on the server. "
2871 L"It was refused. Send a shorter message";
2874 // Run script hook, exit if script ate the chat message
2875 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2880 // Whether to send line to the player that sent the message, or to all players
2881 bool broadcast_line = true;
2883 if (check_shout_priv && !checkPriv(name, "shout")) {
2884 line += L"-!- You don't have permission to shout.";
2885 broadcast_line = false;
2894 Tell calling method to send the message to sender
2896 if (!broadcast_line)
2900 Send the message to others
2902 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2904 std::vector<session_t> clients = m_clients.getClientIDs();
2907 Send the message back to the inital sender
2908 if they are using protocol version >= 29
2911 session_t peer_id_to_avoid_sending =
2912 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2914 if (player && player->protocol_version >= 29)
2915 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2917 for (u16 cid : clients) {
2918 if (cid != peer_id_to_avoid_sending)
2919 SendChatMessage(cid, ChatMessage(line));
2924 void Server::handleAdminChat(const ChatEventChat *evt)
2926 std::string name = evt->nick;
2927 std::wstring wname = utf8_to_wide(name);
2928 std::wstring wmessage = evt->evt_msg;
2930 std::wstring answer = handleChat(name, wname, wmessage);
2932 // If asked to send answer to sender
2933 if (!answer.empty()) {
2934 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2938 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2940 RemoteClient *client = getClientNoEx(peer_id,state_min);
2942 throw ClientNotFoundException("Client not found");
2946 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2948 return m_clients.getClientNoEx(peer_id, state_min);
2951 std::string Server::getPlayerName(session_t peer_id)
2953 RemotePlayer *player = m_env->getPlayer(peer_id);
2955 return "[id="+itos(peer_id)+"]";
2956 return player->getName();
2959 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2961 RemotePlayer *player = m_env->getPlayer(peer_id);
2964 return player->getPlayerSAO();
2967 std::wstring Server::getStatusString()
2969 std::wostringstream os(std::ios_base::binary);
2970 os << L"# Server: ";
2972 os << L"version=" << narrow_to_wide(g_version_string);
2974 os << L", uptime=" << m_uptime.get();
2976 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
2978 // Information about clients
2980 os << L", clients={";
2982 std::vector<session_t> clients = m_clients.getClientIDs();
2983 for (session_t client_id : clients) {
2984 RemotePlayer *player = m_env->getPlayer(client_id);
2986 // Get name of player
2987 std::wstring name = L"unknown";
2989 name = narrow_to_wide(player->getName());
2991 // Add name to information string
3002 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3003 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3005 if (!g_settings->get("motd").empty())
3006 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3011 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3013 std::set<std::string> privs;
3014 m_script->getAuth(name, NULL, &privs);
3018 bool Server::checkPriv(const std::string &name, const std::string &priv)
3020 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3021 return (privs.count(priv) != 0);
3024 void Server::reportPrivsModified(const std::string &name)
3027 std::vector<session_t> clients = m_clients.getClientIDs();
3028 for (const session_t client_id : clients) {
3029 RemotePlayer *player = m_env->getPlayer(client_id);
3030 reportPrivsModified(player->getName());
3033 RemotePlayer *player = m_env->getPlayer(name.c_str());
3036 SendPlayerPrivileges(player->getPeerId());
3037 PlayerSAO *sao = player->getPlayerSAO();
3040 sao->updatePrivileges(
3041 getPlayerEffectivePrivs(name),
3046 void Server::reportInventoryFormspecModified(const std::string &name)
3048 RemotePlayer *player = m_env->getPlayer(name.c_str());
3051 SendPlayerInventoryFormspec(player->getPeerId());
3054 void Server::reportFormspecPrependModified(const std::string &name)
3056 RemotePlayer *player = m_env->getPlayer(name.c_str());
3059 SendPlayerFormspecPrepend(player->getPeerId());
3062 void Server::setIpBanned(const std::string &ip, const std::string &name)
3064 m_banmanager->add(ip, name);
3067 void Server::unsetIpBanned(const std::string &ip_or_name)
3069 m_banmanager->remove(ip_or_name);
3072 std::string Server::getBanDescription(const std::string &ip_or_name)
3074 return m_banmanager->getBanDescription(ip_or_name);
3077 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3079 // m_env will be NULL if the server is initializing
3083 if (m_admin_nick == name && !m_admin_nick.empty()) {
3084 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3087 RemotePlayer *player = m_env->getPlayer(name);
3092 if (player->getPeerId() == PEER_ID_INEXISTENT)
3095 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3098 bool Server::showFormspec(const char *playername, const std::string &formspec,
3099 const std::string &formname)
3101 // m_env will be NULL if the server is initializing
3105 RemotePlayer *player = m_env->getPlayer(playername);
3109 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3113 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3118 u32 id = player->addHud(form);
3120 SendHUDAdd(player->getPeerId(), id, form);
3125 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3129 HudElement* todel = player->removeHud(id);
3136 SendHUDRemove(player->getPeerId(), id);
3140 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3145 SendHUDChange(player->getPeerId(), id, stat, data);
3149 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3154 SendHUDSetFlags(player->getPeerId(), flags, mask);
3155 player->hud_flags &= ~mask;
3156 player->hud_flags |= flags;
3158 PlayerSAO* playersao = player->getPlayerSAO();
3163 m_script->player_event(playersao, "hud_changed");
3167 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3172 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3175 player->setHotbarItemcount(hotbar_itemcount);
3176 std::ostringstream os(std::ios::binary);
3177 writeS32(os, hotbar_itemcount);
3178 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3182 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3187 player->setHotbarImage(name);
3188 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3191 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3196 player->setHotbarSelectedImage(name);
3197 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3200 Address Server::getPeerAddress(session_t peer_id)
3202 return m_con->GetPeerAddress(peer_id);
3205 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3206 v2s32 animation_frames[4], f32 frame_speed)
3208 sanity_check(player);
3209 player->setLocalAnimations(animation_frames, frame_speed);
3210 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3213 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3215 sanity_check(player);
3216 player->eye_offset_first = first;
3217 player->eye_offset_third = third;
3218 SendEyeOffset(player->getPeerId(), first, third);
3221 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3222 const std::string &type, const std::vector<std::string> ¶ms,
3225 sanity_check(player);
3226 player->setSky(bgcolor, type, params, clouds);
3227 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3230 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3232 sanity_check(player);
3233 player->setCloudParams(params);
3234 SendCloudParams(player->getPeerId(), params);
3237 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3243 player->overrideDayNightRatio(do_override, ratio);
3244 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3248 void Server::notifyPlayers(const std::wstring &msg)
3250 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3253 void Server::spawnParticle(const std::string &playername, v3f pos,
3254 v3f velocity, v3f acceleration,
3255 float expirationtime, float size, bool
3256 collisiondetection, bool collision_removal, bool object_collision,
3257 bool vertical, const std::string &texture,
3258 const struct TileAnimationParams &animation, u8 glow)
3260 // m_env will be NULL if the server is initializing
3264 session_t peer_id = PEER_ID_INEXISTENT;
3266 if (!playername.empty()) {
3267 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3270 peer_id = player->getPeerId();
3271 proto_ver = player->protocol_version;
3274 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3275 expirationtime, size, collisiondetection, collision_removal,
3276 object_collision, vertical, texture, animation, glow);
3279 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3280 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3281 float minexptime, float maxexptime, float minsize, float maxsize,
3282 bool collisiondetection, bool collision_removal, bool object_collision,
3283 ServerActiveObject *attached, bool vertical, const std::string &texture,
3284 const std::string &playername, const struct TileAnimationParams &animation,
3287 // m_env will be NULL if the server is initializing
3291 session_t peer_id = PEER_ID_INEXISTENT;
3293 if (!playername.empty()) {
3294 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3297 peer_id = player->getPeerId();
3298 proto_ver = player->protocol_version;
3301 u16 attached_id = attached ? attached->getId() : 0;
3304 if (attached_id == 0)
3305 id = m_env->addParticleSpawner(spawntime);
3307 id = m_env->addParticleSpawner(spawntime, attached_id);
3309 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3310 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3311 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3312 collision_removal, object_collision, attached_id, vertical,
3313 texture, id, animation, glow);
3318 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3320 // m_env will be NULL if the server is initializing
3322 throw ServerError("Can't delete particle spawners during initialisation!");
3324 session_t peer_id = PEER_ID_INEXISTENT;
3325 if (!playername.empty()) {
3326 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3329 peer_id = player->getPeerId();
3332 m_env->deleteParticleSpawner(id);
3333 SendDeleteParticleSpawner(peer_id, id);
3336 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3338 if(m_detached_inventories.count(name) > 0){
3339 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3340 delete m_detached_inventories[name];
3342 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3344 Inventory *inv = new Inventory(m_itemdef);
3346 m_detached_inventories[name] = inv;
3347 m_detached_inventories_player[name] = player;
3348 //TODO find a better way to do this
3349 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3353 bool Server::removeDetachedInventory(const std::string &name)
3355 const auto &inv_it = m_detached_inventories.find(name);
3356 if (inv_it == m_detached_inventories.end())
3359 delete inv_it->second;
3360 m_detached_inventories.erase(inv_it);
3362 const auto &player_it = m_detached_inventories_player.find(name);
3363 if (player_it != m_detached_inventories_player.end()) {
3364 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3366 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3367 sendDetachedInventory(name, player->getPeerId());
3369 m_detached_inventories_player.erase(player_it);
3371 // Notify all players about the change
3372 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3377 // actions: time-reversed list
3378 // Return value: success/failure
3379 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3380 std::list<std::string> *log)
3382 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3383 ServerMap *map = (ServerMap*)(&m_env->getMap());
3385 // Fail if no actions to handle
3386 if (actions.empty()) {
3388 log->push_back("Nothing to do.");
3395 for (const RollbackAction &action : actions) {
3397 bool success = action.applyRevert(map, this, this);
3400 std::ostringstream os;
3401 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3402 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3404 log->push_back(os.str());
3406 std::ostringstream os;
3407 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3408 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3410 log->push_back(os.str());
3414 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3415 <<" failed"<<std::endl;
3417 // Call it done if less than half failed
3418 return num_failed <= num_tried/2;
3421 // IGameDef interface
3423 IItemDefManager *Server::getItemDefManager()
3428 const NodeDefManager *Server::getNodeDefManager()
3433 ICraftDefManager *Server::getCraftDefManager()
3438 u16 Server::allocateUnknownNodeId(const std::string &name)
3440 return m_nodedef->allocateDummy(name);
3443 IWritableItemDefManager *Server::getWritableItemDefManager()
3448 NodeDefManager *Server::getWritableNodeDefManager()
3453 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3458 const std::vector<ModSpec> & Server::getMods() const
3460 return m_modmgr->getMods();
3463 const ModSpec *Server::getModSpec(const std::string &modname) const
3465 return m_modmgr->getModSpec(modname);
3468 void Server::getModNames(std::vector<std::string> &modlist)
3470 m_modmgr->getModNames(modlist);
3473 std::string Server::getBuiltinLuaPath()
3475 return porting::path_share + DIR_DELIM + "builtin";
3478 std::string Server::getModStoragePath() const
3480 return m_path_world + DIR_DELIM + "mod_storage";
3483 v3f Server::findSpawnPos()
3485 ServerMap &map = m_env->getServerMap();
3487 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3488 return nodeposf * BS;
3491 bool is_good = false;
3492 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3493 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3495 // Try to find a good place a few times
3496 for(s32 i = 0; i < 4000 && !is_good; i++) {
3497 s32 range = MYMIN(1 + i, range_max);
3498 // We're going to try to throw the player to this position
3499 v2s16 nodepos2d = v2s16(
3500 -range + (myrand() % (range * 2)),
3501 -range + (myrand() % (range * 2)));
3503 // Get spawn level at point
3504 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3505 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3506 // the mapgen to signify an unsuitable spawn position
3507 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3510 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3513 for (s32 i = 0; i < 10; i++) {
3514 v3s16 blockpos = getNodeBlockPos(nodepos);
3515 map.emergeBlock(blockpos, true);
3516 content_t c = map.getNodeNoEx(nodepos).getContent();
3517 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3519 if (air_count >= 2) {
3520 nodeposf = intToFloat(nodepos, BS);
3521 // Don't spawn the player outside map boundaries
3522 if (objectpos_over_limit(nodeposf))
3535 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3537 if (delay == 0.0f) {
3538 // No delay, shutdown immediately
3539 m_shutdown_state.is_requested = true;
3540 // only print to the infostream, a chat message saying
3541 // "Server Shutting Down" is sent when the server destructs.
3542 infostream << "*** Immediate Server shutdown requested." << std::endl;
3543 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3544 // Negative delay, cancel shutdown if requested
3545 m_shutdown_state.reset();
3546 std::wstringstream ws;
3548 ws << L"*** Server shutdown canceled.";
3550 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3551 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3552 // m_shutdown_* are already handled, skip.
3554 } else if (delay > 0.0f) {
3555 // Positive delay, tell the clients when the server will shut down
3556 std::wstringstream ws;
3558 ws << L"*** Server shutting down in "
3559 << duration_to_string(myround(delay)).c_str()
3562 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3563 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3566 m_shutdown_state.trigger(delay, msg, reconnect);
3569 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3572 Try to get an existing player
3574 RemotePlayer *player = m_env->getPlayer(name);
3576 // If player is already connected, cancel
3577 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3578 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3583 If player with the wanted peer_id already exists, cancel.
3585 if (m_env->getPlayer(peer_id)) {
3586 infostream<<"emergePlayer(): Player with wrong name but same"
3587 " peer_id already exists"<<std::endl;
3592 player = new RemotePlayer(name, idef());
3595 bool newplayer = false;
3598 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3600 // Complete init with server parts
3601 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3602 player->protocol_version = proto_version;
3606 m_script->on_newplayer(playersao);
3612 bool Server::registerModStorage(ModMetadata *storage)
3614 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3615 errorstream << "Unable to register same mod storage twice. Storage name: "
3616 << storage->getModName() << std::endl;
3620 m_mod_storages[storage->getModName()] = storage;
3624 void Server::unregisterModStorage(const std::string &name)
3626 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3627 if (it != m_mod_storages.end()) {
3628 // Save unconditionaly on unregistration
3629 it->second->save(getModStoragePath());
3630 m_mod_storages.erase(name);
3634 void dedicated_server_loop(Server &server, bool &kill)
3636 verbosestream<<"dedicated_server_loop()"<<std::endl;
3638 IntervalLimiter m_profiler_interval;
3640 static thread_local const float steplen =
3641 g_settings->getFloat("dedicated_server_step");
3642 static thread_local const float profiler_print_interval =
3643 g_settings->getFloat("profiler_print_interval");
3646 // This is kind of a hack but can be done like this
3647 // because server.step() is very light
3649 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3650 sleep_ms((int)(steplen*1000.0));
3652 server.step(steplen);
3654 if (server.isShutdownRequested() || kill)
3660 if (profiler_print_interval != 0) {
3661 if(m_profiler_interval.step(steplen, profiler_print_interval))
3663 infostream<<"Profiler:"<<std::endl;
3664 g_profiler->print(infostream);
3665 g_profiler->clear();
3670 infostream << "Dedicated server quitting" << std::endl;
3672 if (g_settings->getBool("server_announce"))
3673 ServerList::sendAnnounce(ServerList::AA_DELETE,
3674 server.m_bind_addr.getPort());
3683 bool Server::joinModChannel(const std::string &channel)
3685 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3686 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3689 bool Server::leaveModChannel(const std::string &channel)
3691 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3694 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3696 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3699 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3703 ModChannel* Server::getModChannel(const std::string &channel)
3705 return m_modchannel_mgr->getModChannel(channel);
3708 void Server::broadcastModChannelMessage(const std::string &channel,
3709 const std::string &message, session_t from_peer)
3711 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3715 if (message.size() > STRING_MAX_LEN) {
3716 warningstream << "ModChannel message too long, dropping before sending "
3717 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3718 << channel << ")" << std::endl;
3723 if (from_peer != PEER_ID_SERVER) {
3724 sender = getPlayerName(from_peer);
3727 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3728 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3729 resp_pkt << channel << sender << message;
3730 for (session_t peer_id : peers) {
3732 if (peer_id == from_peer)
3735 Send(peer_id, &resp_pkt);
3738 if (from_peer != PEER_ID_SERVER) {
3739 m_script->on_modchannel_message(channel, sender, message);