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);
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 // Run script hook, exit if script ate the chat message
2878 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2883 // Whether to send line to the player that sent the message, or to all players
2884 bool broadcast_line = true;
2886 if (check_shout_priv && !checkPriv(name, "shout")) {
2887 line += L"-!- You don't have permission to shout.";
2888 broadcast_line = false;
2897 Tell calling method to send the message to sender
2899 if (!broadcast_line)
2903 Send the message to others
2905 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2907 std::vector<session_t> clients = m_clients.getClientIDs();
2910 Send the message back to the inital sender
2911 if they are using protocol version >= 29
2914 session_t peer_id_to_avoid_sending =
2915 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2917 if (player && player->protocol_version >= 29)
2918 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2920 for (u16 cid : clients) {
2921 if (cid != peer_id_to_avoid_sending)
2922 SendChatMessage(cid, ChatMessage(line));
2927 void Server::handleAdminChat(const ChatEventChat *evt)
2929 std::string name = evt->nick;
2930 std::wstring wname = utf8_to_wide(name);
2931 std::wstring wmessage = evt->evt_msg;
2933 std::wstring answer = handleChat(name, wname, wmessage);
2935 // If asked to send answer to sender
2936 if (!answer.empty()) {
2937 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2941 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2943 RemoteClient *client = getClientNoEx(peer_id,state_min);
2945 throw ClientNotFoundException("Client not found");
2949 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2951 return m_clients.getClientNoEx(peer_id, state_min);
2954 std::string Server::getPlayerName(session_t peer_id)
2956 RemotePlayer *player = m_env->getPlayer(peer_id);
2958 return "[id="+itos(peer_id)+"]";
2959 return player->getName();
2962 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2964 RemotePlayer *player = m_env->getPlayer(peer_id);
2967 return player->getPlayerSAO();
2970 std::wstring Server::getStatusString()
2972 std::wostringstream os(std::ios_base::binary);
2973 os << L"# Server: ";
2975 os << L"version=" << narrow_to_wide(g_version_string);
2977 os << L", uptime=" << m_uptime.get();
2979 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
2981 // Information about clients
2983 os << L", clients={";
2985 std::vector<session_t> clients = m_clients.getClientIDs();
2986 for (session_t client_id : clients) {
2987 RemotePlayer *player = m_env->getPlayer(client_id);
2989 // Get name of player
2990 std::wstring name = L"unknown";
2992 name = narrow_to_wide(player->getName());
2994 // Add name to information string
3005 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3006 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3008 if (!g_settings->get("motd").empty())
3009 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3014 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3016 std::set<std::string> privs;
3017 m_script->getAuth(name, NULL, &privs);
3021 bool Server::checkPriv(const std::string &name, const std::string &priv)
3023 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3024 return (privs.count(priv) != 0);
3027 void Server::reportPrivsModified(const std::string &name)
3030 std::vector<session_t> clients = m_clients.getClientIDs();
3031 for (const session_t client_id : clients) {
3032 RemotePlayer *player = m_env->getPlayer(client_id);
3033 reportPrivsModified(player->getName());
3036 RemotePlayer *player = m_env->getPlayer(name.c_str());
3039 SendPlayerPrivileges(player->getPeerId());
3040 PlayerSAO *sao = player->getPlayerSAO();
3043 sao->updatePrivileges(
3044 getPlayerEffectivePrivs(name),
3049 void Server::reportInventoryFormspecModified(const std::string &name)
3051 RemotePlayer *player = m_env->getPlayer(name.c_str());
3054 SendPlayerInventoryFormspec(player->getPeerId());
3057 void Server::reportFormspecPrependModified(const std::string &name)
3059 RemotePlayer *player = m_env->getPlayer(name.c_str());
3062 SendPlayerFormspecPrepend(player->getPeerId());
3065 void Server::setIpBanned(const std::string &ip, const std::string &name)
3067 m_banmanager->add(ip, name);
3070 void Server::unsetIpBanned(const std::string &ip_or_name)
3072 m_banmanager->remove(ip_or_name);
3075 std::string Server::getBanDescription(const std::string &ip_or_name)
3077 return m_banmanager->getBanDescription(ip_or_name);
3080 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3082 // m_env will be NULL if the server is initializing
3086 if (m_admin_nick == name && !m_admin_nick.empty()) {
3087 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3090 RemotePlayer *player = m_env->getPlayer(name);
3095 if (player->getPeerId() == PEER_ID_INEXISTENT)
3098 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3101 bool Server::showFormspec(const char *playername, const std::string &formspec,
3102 const std::string &formname)
3104 // m_env will be NULL if the server is initializing
3108 RemotePlayer *player = m_env->getPlayer(playername);
3112 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3116 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3121 u32 id = player->addHud(form);
3123 SendHUDAdd(player->getPeerId(), id, form);
3128 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3132 HudElement* todel = player->removeHud(id);
3139 SendHUDRemove(player->getPeerId(), id);
3143 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3148 SendHUDChange(player->getPeerId(), id, stat, data);
3152 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3157 SendHUDSetFlags(player->getPeerId(), flags, mask);
3158 player->hud_flags &= ~mask;
3159 player->hud_flags |= flags;
3161 PlayerSAO* playersao = player->getPlayerSAO();
3166 m_script->player_event(playersao, "hud_changed");
3170 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3175 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3178 player->setHotbarItemcount(hotbar_itemcount);
3179 std::ostringstream os(std::ios::binary);
3180 writeS32(os, hotbar_itemcount);
3181 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3185 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3190 player->setHotbarImage(name);
3191 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3194 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3199 player->setHotbarSelectedImage(name);
3200 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3203 Address Server::getPeerAddress(session_t peer_id)
3205 return m_con->GetPeerAddress(peer_id);
3208 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3209 v2s32 animation_frames[4], f32 frame_speed)
3211 sanity_check(player);
3212 player->setLocalAnimations(animation_frames, frame_speed);
3213 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3216 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3218 sanity_check(player);
3219 player->eye_offset_first = first;
3220 player->eye_offset_third = third;
3221 SendEyeOffset(player->getPeerId(), first, third);
3224 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3225 const std::string &type, const std::vector<std::string> ¶ms,
3228 sanity_check(player);
3229 player->setSky(bgcolor, type, params, clouds);
3230 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3233 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3235 sanity_check(player);
3236 player->setCloudParams(params);
3237 SendCloudParams(player->getPeerId(), params);
3240 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3246 player->overrideDayNightRatio(do_override, ratio);
3247 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3251 void Server::notifyPlayers(const std::wstring &msg)
3253 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3256 void Server::spawnParticle(const std::string &playername, v3f pos,
3257 v3f velocity, v3f acceleration,
3258 float expirationtime, float size, bool
3259 collisiondetection, bool collision_removal, bool object_collision,
3260 bool vertical, const std::string &texture,
3261 const struct TileAnimationParams &animation, u8 glow)
3263 // m_env will be NULL if the server is initializing
3267 session_t peer_id = PEER_ID_INEXISTENT;
3269 if (!playername.empty()) {
3270 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3273 peer_id = player->getPeerId();
3274 proto_ver = player->protocol_version;
3277 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3278 expirationtime, size, collisiondetection, collision_removal,
3279 object_collision, vertical, texture, animation, glow);
3282 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3283 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3284 float minexptime, float maxexptime, float minsize, float maxsize,
3285 bool collisiondetection, bool collision_removal, bool object_collision,
3286 ServerActiveObject *attached, bool vertical, const std::string &texture,
3287 const std::string &playername, const struct TileAnimationParams &animation,
3290 // m_env will be NULL if the server is initializing
3294 session_t peer_id = PEER_ID_INEXISTENT;
3296 if (!playername.empty()) {
3297 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3300 peer_id = player->getPeerId();
3301 proto_ver = player->protocol_version;
3304 u16 attached_id = attached ? attached->getId() : 0;
3307 if (attached_id == 0)
3308 id = m_env->addParticleSpawner(spawntime);
3310 id = m_env->addParticleSpawner(spawntime, attached_id);
3312 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3313 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3314 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3315 collision_removal, object_collision, attached_id, vertical,
3316 texture, id, animation, glow);
3321 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3323 // m_env will be NULL if the server is initializing
3325 throw ServerError("Can't delete particle spawners during initialisation!");
3327 session_t peer_id = PEER_ID_INEXISTENT;
3328 if (!playername.empty()) {
3329 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3332 peer_id = player->getPeerId();
3335 m_env->deleteParticleSpawner(id);
3336 SendDeleteParticleSpawner(peer_id, id);
3339 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3341 if(m_detached_inventories.count(name) > 0){
3342 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3343 delete m_detached_inventories[name];
3345 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3347 Inventory *inv = new Inventory(m_itemdef);
3349 m_detached_inventories[name] = inv;
3350 m_detached_inventories_player[name] = player;
3351 //TODO find a better way to do this
3352 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3356 bool Server::removeDetachedInventory(const std::string &name)
3358 const auto &inv_it = m_detached_inventories.find(name);
3359 if (inv_it == m_detached_inventories.end())
3362 delete inv_it->second;
3363 m_detached_inventories.erase(inv_it);
3365 const auto &player_it = m_detached_inventories_player.find(name);
3366 if (player_it != m_detached_inventories_player.end()) {
3367 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3369 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3370 sendDetachedInventory(name, player->getPeerId());
3372 m_detached_inventories_player.erase(player_it);
3374 // Notify all players about the change
3375 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3380 // actions: time-reversed list
3381 // Return value: success/failure
3382 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3383 std::list<std::string> *log)
3385 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3386 ServerMap *map = (ServerMap*)(&m_env->getMap());
3388 // Fail if no actions to handle
3389 if (actions.empty()) {
3391 log->push_back("Nothing to do.");
3398 for (const RollbackAction &action : actions) {
3400 bool success = action.applyRevert(map, this, this);
3403 std::ostringstream os;
3404 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3405 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3407 log->push_back(os.str());
3409 std::ostringstream os;
3410 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3411 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3413 log->push_back(os.str());
3417 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3418 <<" failed"<<std::endl;
3420 // Call it done if less than half failed
3421 return num_failed <= num_tried/2;
3424 // IGameDef interface
3426 IItemDefManager *Server::getItemDefManager()
3431 const NodeDefManager *Server::getNodeDefManager()
3436 ICraftDefManager *Server::getCraftDefManager()
3441 u16 Server::allocateUnknownNodeId(const std::string &name)
3443 return m_nodedef->allocateDummy(name);
3446 IWritableItemDefManager *Server::getWritableItemDefManager()
3451 NodeDefManager *Server::getWritableNodeDefManager()
3456 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3461 const std::vector<ModSpec> & Server::getMods() const
3463 return m_modmgr->getMods();
3466 const ModSpec *Server::getModSpec(const std::string &modname) const
3468 return m_modmgr->getModSpec(modname);
3471 void Server::getModNames(std::vector<std::string> &modlist)
3473 m_modmgr->getModNames(modlist);
3476 std::string Server::getBuiltinLuaPath()
3478 return porting::path_share + DIR_DELIM + "builtin";
3481 std::string Server::getModStoragePath() const
3483 return m_path_world + DIR_DELIM + "mod_storage";
3486 v3f Server::findSpawnPos()
3488 ServerMap &map = m_env->getServerMap();
3490 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3491 return nodeposf * BS;
3494 bool is_good = false;
3495 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3496 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3498 // Try to find a good place a few times
3499 for(s32 i = 0; i < 4000 && !is_good; i++) {
3500 s32 range = MYMIN(1 + i, range_max);
3501 // We're going to try to throw the player to this position
3502 v2s16 nodepos2d = v2s16(
3503 -range + (myrand() % (range * 2)),
3504 -range + (myrand() % (range * 2)));
3506 // Get spawn level at point
3507 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3508 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3509 // the mapgen to signify an unsuitable spawn position
3510 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3513 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3516 for (s32 i = 0; i < 10; i++) {
3517 v3s16 blockpos = getNodeBlockPos(nodepos);
3518 map.emergeBlock(blockpos, true);
3519 content_t c = map.getNodeNoEx(nodepos).getContent();
3520 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3522 if (air_count >= 2) {
3523 nodeposf = intToFloat(nodepos, BS);
3524 // Don't spawn the player outside map boundaries
3525 if (objectpos_over_limit(nodeposf))
3538 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3540 if (delay == 0.0f) {
3541 // No delay, shutdown immediately
3542 m_shutdown_state.is_requested = true;
3543 // only print to the infostream, a chat message saying
3544 // "Server Shutting Down" is sent when the server destructs.
3545 infostream << "*** Immediate Server shutdown requested." << std::endl;
3546 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3547 // Negative delay, cancel shutdown if requested
3548 m_shutdown_state.reset();
3549 std::wstringstream ws;
3551 ws << L"*** Server shutdown canceled.";
3553 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3554 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3555 // m_shutdown_* are already handled, skip.
3557 } else if (delay > 0.0f) {
3558 // Positive delay, tell the clients when the server will shut down
3559 std::wstringstream ws;
3561 ws << L"*** Server shutting down in "
3562 << duration_to_string(myround(delay)).c_str()
3565 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3566 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3569 m_shutdown_state.trigger(delay, msg, reconnect);
3572 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3575 Try to get an existing player
3577 RemotePlayer *player = m_env->getPlayer(name);
3579 // If player is already connected, cancel
3580 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3581 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3586 If player with the wanted peer_id already exists, cancel.
3588 if (m_env->getPlayer(peer_id)) {
3589 infostream<<"emergePlayer(): Player with wrong name but same"
3590 " peer_id already exists"<<std::endl;
3595 player = new RemotePlayer(name, idef());
3598 bool newplayer = false;
3601 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3603 // Complete init with server parts
3604 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3605 player->protocol_version = proto_version;
3609 m_script->on_newplayer(playersao);
3615 bool Server::registerModStorage(ModMetadata *storage)
3617 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3618 errorstream << "Unable to register same mod storage twice. Storage name: "
3619 << storage->getModName() << std::endl;
3623 m_mod_storages[storage->getModName()] = storage;
3627 void Server::unregisterModStorage(const std::string &name)
3629 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3630 if (it != m_mod_storages.end()) {
3631 // Save unconditionaly on unregistration
3632 it->second->save(getModStoragePath());
3633 m_mod_storages.erase(name);
3637 void dedicated_server_loop(Server &server, bool &kill)
3639 verbosestream<<"dedicated_server_loop()"<<std::endl;
3641 IntervalLimiter m_profiler_interval;
3643 static thread_local const float steplen =
3644 g_settings->getFloat("dedicated_server_step");
3645 static thread_local const float profiler_print_interval =
3646 g_settings->getFloat("profiler_print_interval");
3649 // This is kind of a hack but can be done like this
3650 // because server.step() is very light
3652 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3653 sleep_ms((int)(steplen*1000.0));
3655 server.step(steplen);
3657 if (server.isShutdownRequested() || kill)
3663 if (profiler_print_interval != 0) {
3664 if(m_profiler_interval.step(steplen, profiler_print_interval))
3666 infostream<<"Profiler:"<<std::endl;
3667 g_profiler->print(infostream);
3668 g_profiler->clear();
3673 infostream << "Dedicated server quitting" << std::endl;
3675 if (g_settings->getBool("server_announce"))
3676 ServerList::sendAnnounce(ServerList::AA_DELETE,
3677 server.m_bind_addr.getPort());
3686 bool Server::joinModChannel(const std::string &channel)
3688 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3689 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3692 bool Server::leaveModChannel(const std::string &channel)
3694 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3697 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3699 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3702 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3706 ModChannel* Server::getModChannel(const std::string &channel)
3708 return m_modchannel_mgr->getModChannel(channel);
3711 void Server::broadcastModChannelMessage(const std::string &channel,
3712 const std::string &message, session_t from_peer)
3714 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3718 if (message.size() > STRING_MAX_LEN) {
3719 warningstream << "ModChannel message too long, dropping before sending "
3720 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3721 << channel << ")" << std::endl;
3726 if (from_peer != PEER_ID_SERVER) {
3727 sender = getPlayerName(from_peer);
3730 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3731 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3732 resp_pkt << channel << sender << message;
3733 for (session_t peer_id : peers) {
3735 if (peer_id == from_peer)
3738 Send(peer_id, &resp_pkt);
3741 if (from_peer != PEER_ID_SERVER) {
3742 m_script->on_modchannel_message(channel, sender, message);