3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
142 void Server::ShutdownState::reset()
146 should_reconnect = false;
147 is_requested = false;
150 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
154 should_reconnect = reconnect;
157 void Server::ShutdownState::tick(float dtime, Server *server)
163 static const float shutdown_msg_times[] =
165 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
168 // Automated messages
169 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
170 for (float t : shutdown_msg_times) {
171 // If shutdown timer matches an automessage, shot it
172 if (m_timer > t && m_timer - dtime < t) {
173 std::wstring periodicMsg = getShutdownTimerMessage();
175 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
176 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
183 if (m_timer < 0.0f) {
189 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
191 std::wstringstream ws;
192 ws << L"*** Server shutting down in "
193 << duration_to_string(myround(m_timer)).c_str() << ".";
202 const std::string &path_world,
203 const SubgameSpec &gamespec,
204 bool simple_singleplayer_mode,
209 m_bind_addr(bind_addr),
210 m_path_world(path_world),
211 m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated),
214 m_async_fatal_error(""),
215 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
218 m_bind_addr.isIPv6(),
220 m_itemdef(createItemDefManager()),
221 m_nodedef(createNodeDefManager()),
222 m_craftdef(createCraftDefManager()),
223 m_thread(new ServerThread(this)),
227 m_modchannel_mgr(new ModChannelMgr())
229 m_lag = g_settings->getFloat("dedicated_server_step");
231 if (m_path_world.empty())
232 throw ServerError("Supplied empty world path");
234 if (!gamespec.isValid())
235 throw ServerError("Supplied invalid gamespec");
241 // Send shutdown message
242 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
243 L"*** Server shutting down"));
246 MutexAutoLock envlock(m_env_mutex);
248 infostream << "Server: Saving players" << std::endl;
249 m_env->saveLoadedPlayers();
251 infostream << "Server: Kicking players" << std::endl;
252 std::string kick_msg;
253 bool reconnect = false;
254 if (isShutdownRequested()) {
255 reconnect = m_shutdown_state.should_reconnect;
256 kick_msg = m_shutdown_state.message;
258 if (kick_msg.empty()) {
259 kick_msg = g_settings->get("kick_msg_shutdown");
261 m_env->saveLoadedPlayers(true);
262 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
263 kick_msg, reconnect);
266 actionstream << "Server: Shutting down" << std::endl;
268 // Do this before stopping the server in case mapgen callbacks need to access
269 // server-controlled resources (like ModStorages). Also do them before
270 // shutdown callbacks since they may modify state that is finalized in a
273 m_emerge->stopThreads();
276 MutexAutoLock envlock(m_env_mutex);
278 // Execute script shutdown hooks
279 infostream << "Executing shutdown hooks" << std::endl;
280 m_script->on_shutdown();
282 infostream << "Server: Saving environment metadata" << std::endl;
292 // Delete things in the reverse order of creation
301 // Deinitialize scripting
302 infostream << "Server: Deinitializing scripting" << std::endl;
305 // Delete detached inventories
306 for (auto &detached_inventory : m_detached_inventories) {
307 delete detached_inventory.second;
313 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
314 if (m_simple_singleplayer_mode)
315 infostream << " in simple singleplayer mode" << std::endl;
317 infostream << std::endl;
318 infostream << "- world: " << m_path_world << std::endl;
319 infostream << "- game: " << m_gamespec.path << std::endl;
321 // Create world if it doesn't exist
322 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
323 throw ServerError("Failed to initialize world");
325 // Create emerge manager
326 m_emerge = new EmergeManager(this);
328 // Create ban manager
329 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
330 m_banmanager = new BanManager(ban_path);
332 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
333 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
334 // complain about mods with unsatisfied dependencies
335 if (!m_modmgr->isConsistent()) {
336 m_modmgr->printUnsatisfiedModsError();
340 MutexAutoLock envlock(m_env_mutex);
342 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
343 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
345 // Initialize scripting
346 infostream << "Server: Initializing Lua" << std::endl;
348 m_script = new ServerScripting(this);
350 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
352 m_modmgr->loadMods(m_script);
354 // Read Textures and calculate sha1 sums
357 // Apply item aliases in the node definition manager
358 m_nodedef->updateAliases(m_itemdef);
360 // Apply texture overrides from texturepack/override.txt
361 std::vector<std::string> paths;
362 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
363 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
364 for (const std::string &path : paths)
365 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
367 m_nodedef->setNodeRegistrationStatus(true);
369 // Perform pending node name resolutions
370 m_nodedef->runNodeResolveCallbacks();
372 // unmap node names for connected nodeboxes
373 m_nodedef->mapNodeboxConnections();
375 // init the recipe hashes to speed up crafting
376 m_craftdef->initHashes(this);
378 // Initialize Environment
379 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
381 m_clients.setEnv(m_env);
383 if (!servermap->settings_mgr.makeMapgenParams())
384 FATAL_ERROR("Couldn't create any mapgen type");
386 // Initialize mapgens
387 m_emerge->initMapgens(servermap->getMapgenParams());
389 if (g_settings->getBool("enable_rollback_recording")) {
390 // Create rollback manager
391 m_rollback = new RollbackManager(m_path_world, this);
394 // Give environment reference to scripting api
395 m_script->initializeEnvironment(m_env);
397 // Register us to receive map edit events
398 servermap->addEventReceiver(this);
402 m_liquid_transform_every = g_settings->getFloat("liquid_update");
403 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
404 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
405 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
410 infostream << "Starting server on " << m_bind_addr.serializeString()
411 << "..." << std::endl;
413 // Stop thread if already running
416 // Initialize connection
417 m_con->SetTimeoutMs(30);
418 m_con->Serve(m_bind_addr);
423 // ASCII art for the win!
425 << " .__ __ __ " << std::endl
426 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
427 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
428 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
429 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
430 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
431 actionstream << "World at [" << m_path_world << "]" << std::endl;
432 actionstream << "Server for gameid=\"" << m_gamespec.id
433 << "\" listening on " << m_bind_addr.serializeString() << ":"
434 << m_bind_addr.getPort() << "." << std::endl;
439 infostream<<"Server: Stopping and waiting threads"<<std::endl;
441 // Stop threads (set run=false first so both start stopping)
443 //m_emergethread.setRun(false);
445 //m_emergethread.stop();
447 infostream<<"Server: Threads stopped"<<std::endl;
450 void Server::step(float dtime)
456 MutexAutoLock lock(m_step_dtime_mutex);
457 m_step_dtime += dtime;
459 // Throw if fatal error occurred in thread
460 std::string async_err = m_async_fatal_error.get();
461 if (!async_err.empty()) {
462 if (!m_simple_singleplayer_mode) {
463 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
464 g_settings->get("kick_msg_crash"),
465 g_settings->getBool("ask_reconnect_on_crash"));
467 throw ServerError("AsyncErr: " + async_err);
471 void Server::AsyncRunStep(bool initial_step)
473 g_profiler->add("Server::AsyncRunStep (num)", 1);
477 MutexAutoLock lock1(m_step_dtime_mutex);
478 dtime = m_step_dtime;
482 // Send blocks to clients
486 if((dtime < 0.001) && !initial_step)
489 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
491 //infostream<<"Server steps "<<dtime<<std::endl;
492 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
495 MutexAutoLock lock1(m_step_dtime_mutex);
496 m_step_dtime -= dtime;
503 m_uptime.set(m_uptime.get() + dtime);
509 Update time of day and overall game time
511 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
514 Send to clients at constant intervals
517 m_time_of_day_send_timer -= dtime;
518 if(m_time_of_day_send_timer < 0.0) {
519 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
520 u16 time = m_env->getTimeOfDay();
521 float time_speed = g_settings->getFloat("time_speed");
522 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
526 MutexAutoLock lock(m_env_mutex);
527 // Figure out and report maximum lag to environment
528 float max_lag = m_env->getMaxLagEstimate();
529 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
531 if(dtime > 0.1 && dtime > max_lag * 2.0)
532 infostream<<"Server: Maximum lag peaked to "<<dtime
536 m_env->reportMaxLagEstimate(max_lag);
538 ScopeProfiler sp(g_profiler, "SEnv step");
539 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
543 static const float map_timer_and_unload_dtime = 2.92;
544 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
546 MutexAutoLock lock(m_env_mutex);
547 // Run Map's timers and unload unused data
548 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
549 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
550 g_settings->getFloat("server_unload_unused_data_timeout"),
555 Listen to the admin chat, if available
558 if (!m_admin_chat->command_queue.empty()) {
559 MutexAutoLock lock(m_env_mutex);
560 while (!m_admin_chat->command_queue.empty()) {
561 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
562 handleChatInterfaceEvent(evt);
566 m_admin_chat->outgoing_queue.push_back(
567 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
574 /* Transform liquids */
575 m_liquid_transform_timer += dtime;
576 if(m_liquid_transform_timer >= m_liquid_transform_every)
578 m_liquid_transform_timer -= m_liquid_transform_every;
580 MutexAutoLock lock(m_env_mutex);
582 ScopeProfiler sp(g_profiler, "Server: liquid transform");
584 std::map<v3s16, MapBlock*> modified_blocks;
585 m_env->getMap().transformLiquids(modified_blocks, m_env);
588 Set the modified blocks unsent for all the clients
590 if (!modified_blocks.empty()) {
591 SetBlocksNotSent(modified_blocks);
594 m_clients.step(dtime);
596 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
598 // send masterserver announce
600 float &counter = m_masterserver_timer;
601 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
602 g_settings->getBool("server_announce")) {
603 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
604 ServerList::AA_START,
605 m_bind_addr.getPort(),
606 m_clients.getPlayerNames(),
608 m_env->getGameTime(),
611 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
621 Check added and deleted active objects
624 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
625 MutexAutoLock envlock(m_env_mutex);
628 const RemoteClientMap &clients = m_clients.getClientList();
629 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
631 // Radius inside which objects are active
632 static thread_local const s16 radius =
633 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
635 // Radius inside which players are active
636 static thread_local const bool is_transfer_limited =
637 g_settings->exists("unlimited_player_transfer_distance") &&
638 !g_settings->getBool("unlimited_player_transfer_distance");
639 static thread_local const s16 player_transfer_dist =
640 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
641 s16 player_radius = player_transfer_dist;
642 if (player_radius == 0 && is_transfer_limited)
643 player_radius = radius;
645 for (const auto &client_it : clients) {
646 RemoteClient *client = client_it.second;
648 // If definitions and textures have not been sent, don't
649 // send objects either
650 if (client->getState() < CS_DefinitionsSent)
653 RemotePlayer *player = m_env->getPlayer(client->peer_id);
655 // This can happen if the client timeouts somehow
659 PlayerSAO *playersao = player->getPlayerSAO();
663 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
664 if (my_radius <= 0) my_radius = radius;
665 //infostream << "Server: Active Radius " << my_radius << std::endl;
667 std::queue<u16> removed_objects;
668 std::queue<u16> added_objects;
669 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
670 client->m_known_objects, removed_objects);
671 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
672 client->m_known_objects, added_objects);
674 // Ignore if nothing happened
675 if (removed_objects.empty() && added_objects.empty()) {
679 std::string data_buffer;
683 // Handle removed objects
684 writeU16((u8*)buf, removed_objects.size());
685 data_buffer.append(buf, 2);
686 while (!removed_objects.empty()) {
688 u16 id = removed_objects.front();
689 ServerActiveObject* obj = m_env->getActiveObject(id);
691 // Add to data buffer for sending
692 writeU16((u8*)buf, id);
693 data_buffer.append(buf, 2);
695 // Remove from known objects
696 client->m_known_objects.erase(id);
698 if(obj && obj->m_known_by_count > 0)
699 obj->m_known_by_count--;
700 removed_objects.pop();
703 // Handle added objects
704 writeU16((u8*)buf, added_objects.size());
705 data_buffer.append(buf, 2);
706 while (!added_objects.empty()) {
708 u16 id = added_objects.front();
709 ServerActiveObject* obj = m_env->getActiveObject(id);
712 u8 type = ACTIVEOBJECT_TYPE_INVALID;
714 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
716 type = obj->getSendType();
718 // Add to data buffer for sending
719 writeU16((u8*)buf, id);
720 data_buffer.append(buf, 2);
721 writeU8((u8*)buf, type);
722 data_buffer.append(buf, 1);
725 data_buffer.append(serializeLongString(
726 obj->getClientInitializationData(client->net_proto_version)));
728 data_buffer.append(serializeLongString(""));
730 // Add to known objects
731 client->m_known_objects.insert(id);
734 obj->m_known_by_count++;
739 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
740 verbosestream << "Server: Sent object remove/add: "
741 << removed_objects.size() << " removed, "
742 << added_objects.size() << " added, "
743 << "packet size is " << pktSize << std::endl;
747 m_mod_storage_save_timer -= dtime;
748 if (m_mod_storage_save_timer <= 0.0f) {
749 infostream << "Saving registered mod storages." << std::endl;
750 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
751 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
752 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
753 if (it->second->isModified()) {
754 it->second->save(getModStoragePath());
764 MutexAutoLock envlock(m_env_mutex);
765 ScopeProfiler sp(g_profiler, "Server: sending object messages");
768 // Value = data sent by object
769 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
771 // Get active object messages from environment
773 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
777 std::vector<ActiveObjectMessage>* message_list = nullptr;
778 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
779 n = buffered_messages.find(aom.id);
780 if (n == buffered_messages.end()) {
781 message_list = new std::vector<ActiveObjectMessage>;
782 buffered_messages[aom.id] = message_list;
785 message_list = n->second;
787 message_list->push_back(aom);
791 const RemoteClientMap &clients = m_clients.getClientList();
792 // Route data to every client
793 for (const auto &client_it : clients) {
794 RemoteClient *client = client_it.second;
795 std::string reliable_data;
796 std::string unreliable_data;
797 // Go through all objects in message buffer
798 for (const auto &buffered_message : buffered_messages) {
799 // If object is not known by client, skip it
800 u16 id = buffered_message.first;
801 if (client->m_known_objects.find(id) == client->m_known_objects.end())
804 // Get message list of object
805 std::vector<ActiveObjectMessage>* list = buffered_message.second;
806 // Go through every message
807 for (const ActiveObjectMessage &aom : *list) {
808 // Compose the full new data with header
809 std::string new_data;
812 writeU16((u8*)&buf[0], aom.id);
813 new_data.append(buf, 2);
815 new_data += serializeString(aom.datastring);
816 // Add data to buffer
818 reliable_data += new_data;
820 unreliable_data += new_data;
824 reliable_data and unreliable_data are now ready.
827 if (!reliable_data.empty()) {
828 SendActiveObjectMessages(client->peer_id, reliable_data);
831 if (!unreliable_data.empty()) {
832 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
837 // Clear buffered_messages
838 for (auto &buffered_message : buffered_messages) {
839 delete buffered_message.second;
844 Send queued-for-sending map edit events.
847 // We will be accessing the environment
848 MutexAutoLock lock(m_env_mutex);
850 // Don't send too many at a time
853 // Single change sending is disabled if queue size is not small
854 bool disable_single_change_sending = false;
855 if(m_unsent_map_edit_queue.size() >= 4)
856 disable_single_change_sending = true;
858 int event_count = m_unsent_map_edit_queue.size();
860 // We'll log the amount of each
863 std::list<v3s16> node_meta_updates;
865 while (!m_unsent_map_edit_queue.empty()) {
866 MapEditEvent* event = m_unsent_map_edit_queue.front();
867 m_unsent_map_edit_queue.pop();
869 // Players far away from the change are stored here.
870 // Instead of sending the changes, MapBlocks are set not sent
872 std::unordered_set<u16> far_players;
874 switch (event->type) {
877 prof.add("MEET_ADDNODE", 1);
878 sendAddNode(event->p, event->n, &far_players,
879 disable_single_change_sending ? 5 : 30,
880 event->type == MEET_ADDNODE);
882 case MEET_REMOVENODE:
883 prof.add("MEET_REMOVENODE", 1);
884 sendRemoveNode(event->p, &far_players,
885 disable_single_change_sending ? 5 : 30);
887 case MEET_BLOCK_NODE_METADATA_CHANGED: {
888 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
889 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
890 if (!event->is_private_change) {
891 // Don't send the change yet. Collect them to eliminate dupes.
892 node_meta_updates.remove(event->p);
893 node_meta_updates.push_back(event->p);
896 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
897 getNodeBlockPos(event->p))) {
898 block->raiseModified(MOD_STATE_WRITE_NEEDED,
899 MOD_REASON_REPORT_META_CHANGE);
904 infostream << "Server: MEET_OTHER" << std::endl;
905 prof.add("MEET_OTHER", 1);
906 for (const v3s16 &modified_block : event->modified_blocks) {
907 m_clients.markBlockposAsNotSent(modified_block);
911 prof.add("unknown", 1);
912 warningstream << "Server: Unknown MapEditEvent "
913 << ((u32)event->type) << std::endl;
918 Set blocks not sent to far players
920 if (!far_players.empty()) {
921 // Convert list format to that wanted by SetBlocksNotSent
922 std::map<v3s16, MapBlock*> modified_blocks2;
923 for (const v3s16 &modified_block : event->modified_blocks) {
924 modified_blocks2[modified_block] =
925 m_env->getMap().getBlockNoCreateNoEx(modified_block);
928 // Set blocks not sent
929 for (const u16 far_player : far_players) {
930 if (RemoteClient *client = getClient(far_player))
931 client->SetBlocksNotSent(modified_blocks2);
938 if (event_count >= 5) {
939 infostream << "Server: MapEditEvents:" << std::endl;
940 prof.print(infostream);
941 } else if (event_count != 0) {
942 verbosestream << "Server: MapEditEvents:" << std::endl;
943 prof.print(verbosestream);
946 // Send all metadata updates
947 if (node_meta_updates.size())
948 sendMetadataChanged(node_meta_updates);
952 Trigger emergethread (it somehow gets to a non-triggered but
953 bysy state sometimes)
956 float &counter = m_emergethread_trigger_timer;
958 if (counter >= 2.0) {
961 m_emerge->startThreads();
965 // Save map, players and auth stuff
967 float &counter = m_savemap_timer;
969 static thread_local const float save_interval =
970 g_settings->getFloat("server_map_save_interval");
971 if (counter >= save_interval) {
973 MutexAutoLock lock(m_env_mutex);
975 ScopeProfiler sp(g_profiler, "Server: saving stuff");
978 if (m_banmanager->isModified()) {
979 m_banmanager->save();
982 // Save changed parts of map
983 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
986 m_env->saveLoadedPlayers();
988 // Save environment metadata
993 m_shutdown_state.tick(dtime, this);
996 void Server::Receive()
998 session_t peer_id = 0;
1001 m_con->Receive(&pkt);
1002 peer_id = pkt.getPeerId();
1004 } catch (const con::InvalidIncomingDataException &e) {
1005 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1006 << e.what() << std::endl;
1007 } catch (const SerializationError &e) {
1008 infostream << "Server::Receive(): SerializationError: what()="
1009 << e.what() << std::endl;
1010 } catch (const ClientStateError &e) {
1011 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1012 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1013 L"Try reconnecting or updating your client");
1014 } catch (const con::PeerNotFoundException &e) {
1019 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1021 std::string playername;
1022 PlayerSAO *playersao = NULL;
1025 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1027 playername = client->getName();
1028 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1030 } catch (std::exception &e) {
1036 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1038 // If failed, cancel
1039 if (!playersao || !player) {
1040 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1041 actionstream << "Server: Failed to emerge player \"" << playername
1042 << "\" (player allocated to an another client)" << std::endl;
1043 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1044 L"name. If your client closed unexpectedly, try again in "
1047 errorstream << "Server: " << playername << ": Failed to emerge player"
1049 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1055 Send complete position information
1057 SendMovePlayer(peer_id);
1060 SendPlayerPrivileges(peer_id);
1062 // Send inventory formspec
1063 SendPlayerInventoryFormspec(peer_id);
1066 SendInventory(playersao);
1068 // Send HP or death screen
1069 if (playersao->isDead())
1070 SendDeathscreen(peer_id, false, v3f(0,0,0));
1072 SendPlayerHPOrDie(playersao,
1073 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1076 SendPlayerBreath(playersao);
1078 Address addr = getPeerAddress(player->getPeerId());
1079 std::string ip_str = addr.serializeString();
1080 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1085 const std::vector<std::string> &names = m_clients.getPlayerNames();
1087 actionstream << player->getName() << " joins game. List of players: ";
1089 for (const std::string &name : names) {
1090 actionstream << name << " ";
1093 actionstream << player->getName() <<std::endl;
1098 inline void Server::handleCommand(NetworkPacket* pkt)
1100 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1101 (this->*opHandle.handler)(pkt);
1104 void Server::ProcessData(NetworkPacket *pkt)
1106 // Environment is locked first.
1107 MutexAutoLock envlock(m_env_mutex);
1109 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1110 u32 peer_id = pkt->getPeerId();
1113 Address address = getPeerAddress(peer_id);
1114 std::string addr_s = address.serializeString();
1116 if(m_banmanager->isIpBanned(addr_s)) {
1117 std::string ban_name = m_banmanager->getBanName(addr_s);
1118 infostream << "Server: A banned client tried to connect from "
1119 << addr_s << "; banned name was "
1120 << ban_name << std::endl;
1121 // This actually doesn't seem to transfer to the client
1122 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1123 + utf8_to_wide(ban_name));
1127 catch(con::PeerNotFoundException &e) {
1129 * no peer for this packet found
1130 * most common reason is peer timeout, e.g. peer didn't
1131 * respond for some time, your server was overloaded or
1134 infostream << "Server::ProcessData(): Canceling: peer "
1135 << peer_id << " not found" << std::endl;
1140 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1142 // Command must be handled into ToServerCommandHandler
1143 if (command >= TOSERVER_NUM_MSG_TYPES) {
1144 infostream << "Server: Ignoring unknown command "
1145 << command << std::endl;
1149 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1154 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1156 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1157 errorstream << "Server::ProcessData(): Cancelling: Peer"
1158 " serialization format invalid or not initialized."
1159 " Skipping incoming command=" << command << std::endl;
1163 /* Handle commands related to client startup */
1164 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1169 if (m_clients.getClientState(peer_id) < CS_Active) {
1170 if (command == TOSERVER_PLAYERPOS) return;
1172 errorstream << "Got packet command: " << command << " for peer id "
1173 << peer_id << " but client isn't active yet. Dropping packet "
1179 } catch (SendFailedException &e) {
1180 errorstream << "Server::ProcessData(): SendFailedException: "
1181 << "what=" << e.what()
1183 } catch (PacketError &e) {
1184 actionstream << "Server::ProcessData(): PacketError: "
1185 << "what=" << e.what()
1190 void Server::setTimeOfDay(u32 time)
1192 m_env->setTimeOfDay(time);
1193 m_time_of_day_send_timer = 0;
1196 void Server::onMapEditEvent(MapEditEvent *event)
1198 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1200 MapEditEvent *e = event->clone();
1201 m_unsent_map_edit_queue.push(e);
1204 Inventory* Server::getInventory(const InventoryLocation &loc)
1207 case InventoryLocation::UNDEFINED:
1208 case InventoryLocation::CURRENT_PLAYER:
1210 case InventoryLocation::PLAYER:
1212 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1215 PlayerSAO *playersao = player->getPlayerSAO();
1218 return playersao->getInventory();
1221 case InventoryLocation::NODEMETA:
1223 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1226 return meta->getInventory();
1229 case InventoryLocation::DETACHED:
1231 if(m_detached_inventories.count(loc.name) == 0)
1233 return m_detached_inventories[loc.name];
1237 sanity_check(false); // abort
1243 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1246 case InventoryLocation::UNDEFINED:
1248 case InventoryLocation::PLAYER:
1253 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1258 PlayerSAO *playersao = player->getPlayerSAO();
1262 SendInventory(playersao);
1265 case InventoryLocation::NODEMETA:
1268 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1270 m_env->getMap().dispatchEvent(&event);
1273 case InventoryLocation::DETACHED:
1275 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1279 sanity_check(false); // abort
1284 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1286 std::vector<session_t> clients = m_clients.getClientIDs();
1288 // Set the modified blocks unsent for all the clients
1289 for (const session_t client_id : clients) {
1290 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1291 client->SetBlocksNotSent(block);
1296 void Server::peerAdded(con::Peer *peer)
1298 verbosestream<<"Server::peerAdded(): peer->id="
1299 <<peer->id<<std::endl;
1301 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1304 void Server::deletingPeer(con::Peer *peer, bool timeout)
1306 verbosestream<<"Server::deletingPeer(): peer->id="
1307 <<peer->id<<", timeout="<<timeout<<std::endl;
1309 m_clients.event(peer->id, CSE_Disconnect);
1310 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1313 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1315 *retval = m_con->getPeerStat(peer_id,type);
1316 return *retval != -1;
1319 bool Server::getClientInfo(
1328 std::string* vers_string
1331 *state = m_clients.getClientState(peer_id);
1333 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1340 *uptime = client->uptime();
1341 *ser_vers = client->serialization_version;
1342 *prot_vers = client->net_proto_version;
1344 *major = client->getMajor();
1345 *minor = client->getMinor();
1346 *patch = client->getPatch();
1347 *vers_string = client->getPatch();
1354 void Server::handlePeerChanges()
1356 while(!m_peer_change_queue.empty())
1358 con::PeerChange c = m_peer_change_queue.front();
1359 m_peer_change_queue.pop();
1361 verbosestream<<"Server: Handling peer change: "
1362 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1367 case con::PEER_ADDED:
1368 m_clients.CreateClient(c.peer_id);
1371 case con::PEER_REMOVED:
1372 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1376 FATAL_ERROR("Invalid peer change event received!");
1382 void Server::printToConsoleOnly(const std::string &text)
1385 m_admin_chat->outgoing_queue.push_back(
1386 new ChatEventChat("", utf8_to_wide(text)));
1388 std::cout << text << std::endl;
1392 void Server::Send(NetworkPacket *pkt)
1394 Send(pkt->getPeerId(), pkt);
1397 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1399 m_clients.send(peer_id,
1400 clientCommandFactoryTable[pkt->getCommand()].channel,
1402 clientCommandFactoryTable[pkt->getCommand()].reliable);
1405 void Server::SendMovement(session_t peer_id)
1407 std::ostringstream os(std::ios_base::binary);
1409 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1411 pkt << g_settings->getFloat("movement_acceleration_default");
1412 pkt << g_settings->getFloat("movement_acceleration_air");
1413 pkt << g_settings->getFloat("movement_acceleration_fast");
1414 pkt << g_settings->getFloat("movement_speed_walk");
1415 pkt << g_settings->getFloat("movement_speed_crouch");
1416 pkt << g_settings->getFloat("movement_speed_fast");
1417 pkt << g_settings->getFloat("movement_speed_climb");
1418 pkt << g_settings->getFloat("movement_speed_jump");
1419 pkt << g_settings->getFloat("movement_liquid_fluidity");
1420 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1421 pkt << g_settings->getFloat("movement_liquid_sink");
1422 pkt << g_settings->getFloat("movement_gravity");
1427 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1429 if (!g_settings->getBool("enable_damage"))
1432 session_t peer_id = playersao->getPeerID();
1433 bool is_alive = playersao->getHP() > 0;
1436 SendPlayerHP(peer_id);
1438 DiePlayer(peer_id, reason);
1441 void Server::SendHP(session_t peer_id, u16 hp)
1443 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1448 void Server::SendBreath(session_t peer_id, u16 breath)
1450 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1451 pkt << (u16) breath;
1455 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1456 const std::string &custom_reason, bool reconnect)
1458 assert(reason < SERVER_ACCESSDENIED_MAX);
1460 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1462 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1463 pkt << custom_reason;
1464 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1465 reason == SERVER_ACCESSDENIED_CRASH)
1466 pkt << custom_reason << (u8)reconnect;
1470 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1472 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1477 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1478 v3f camera_point_target)
1480 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1481 pkt << set_camera_point_target << camera_point_target;
1485 void Server::SendItemDef(session_t peer_id,
1486 IItemDefManager *itemdef, u16 protocol_version)
1488 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1492 u32 length of the next item
1493 zlib-compressed serialized ItemDefManager
1495 std::ostringstream tmp_os(std::ios::binary);
1496 itemdef->serialize(tmp_os, protocol_version);
1497 std::ostringstream tmp_os2(std::ios::binary);
1498 compressZlib(tmp_os.str(), tmp_os2);
1499 pkt.putLongString(tmp_os2.str());
1502 verbosestream << "Server: Sending item definitions to id(" << peer_id
1503 << "): size=" << pkt.getSize() << std::endl;
1508 void Server::SendNodeDef(session_t peer_id,
1509 const NodeDefManager *nodedef, u16 protocol_version)
1511 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1515 u32 length of the next item
1516 zlib-compressed serialized NodeDefManager
1518 std::ostringstream tmp_os(std::ios::binary);
1519 nodedef->serialize(tmp_os, protocol_version);
1520 std::ostringstream tmp_os2(std::ios::binary);
1521 compressZlib(tmp_os.str(), tmp_os2);
1523 pkt.putLongString(tmp_os2.str());
1526 verbosestream << "Server: Sending node definitions to id(" << peer_id
1527 << "): size=" << pkt.getSize() << std::endl;
1533 Non-static send methods
1536 void Server::SendInventory(PlayerSAO* playerSAO)
1538 UpdateCrafting(playerSAO->getPlayer());
1544 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1546 std::ostringstream os;
1547 playerSAO->getInventory()->serialize(os);
1549 std::string s = os.str();
1551 pkt.putRawString(s.c_str(), s.size());
1555 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1557 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1559 u8 type = message.type;
1560 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1562 if (peer_id != PEER_ID_INEXISTENT) {
1563 RemotePlayer *player = m_env->getPlayer(peer_id);
1569 m_clients.sendToAll(&pkt);
1573 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1574 const std::string &formname)
1576 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1577 if (formspec.empty()){
1578 //the client should close the formspec
1579 //but make sure there wasn't another one open in meantime
1580 const auto it = m_formspec_state_data.find(peer_id);
1581 if (it != m_formspec_state_data.end() && it->second == formname) {
1582 m_formspec_state_data.erase(peer_id);
1584 pkt.putLongString("");
1586 m_formspec_state_data[peer_id] = formname;
1587 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1594 // Spawns a particle on peer with peer_id
1595 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1596 v3f pos, v3f velocity, v3f acceleration,
1597 float expirationtime, float size, bool collisiondetection,
1598 bool collision_removal, bool object_collision,
1599 bool vertical, const std::string &texture,
1600 const struct TileAnimationParams &animation, u8 glow)
1602 static thread_local const float radius =
1603 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1605 if (peer_id == PEER_ID_INEXISTENT) {
1606 std::vector<session_t> clients = m_clients.getClientIDs();
1608 for (const session_t client_id : clients) {
1609 RemotePlayer *player = m_env->getPlayer(client_id);
1613 PlayerSAO *sao = player->getPlayerSAO();
1617 // Do not send to distant clients
1618 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1621 SendSpawnParticle(client_id, player->protocol_version,
1622 pos, velocity, acceleration,
1623 expirationtime, size, collisiondetection, collision_removal,
1624 object_collision, vertical, texture, animation, glow);
1629 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1631 pkt << pos << velocity << acceleration << expirationtime
1632 << size << collisiondetection;
1633 pkt.putLongString(texture);
1635 pkt << collision_removal;
1636 // This is horrible but required (why are there two ways to serialize pkts?)
1637 std::ostringstream os(std::ios_base::binary);
1638 animation.serialize(os, protocol_version);
1639 pkt.putRawString(os.str());
1641 pkt << object_collision;
1646 // Adds a ParticleSpawner on peer with peer_id
1647 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1648 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1649 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1650 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1651 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1652 const struct TileAnimationParams &animation, u8 glow)
1654 if (peer_id == PEER_ID_INEXISTENT) {
1655 // This sucks and should be replaced:
1656 std::vector<session_t> clients = m_clients.getClientIDs();
1657 for (const session_t client_id : clients) {
1658 RemotePlayer *player = m_env->getPlayer(client_id);
1661 SendAddParticleSpawner(client_id, player->protocol_version,
1662 amount, spawntime, minpos, maxpos,
1663 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1664 minsize, maxsize, collisiondetection, collision_removal,
1665 object_collision, attached_id, vertical, texture, id,
1671 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1673 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1674 << minacc << maxacc << minexptime << maxexptime << minsize
1675 << maxsize << collisiondetection;
1677 pkt.putLongString(texture);
1679 pkt << id << vertical;
1680 pkt << collision_removal;
1682 // This is horrible but required
1683 std::ostringstream os(std::ios_base::binary);
1684 animation.serialize(os, protocol_version);
1685 pkt.putRawString(os.str());
1687 pkt << object_collision;
1692 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1694 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1696 // Ugly error in this packet
1699 if (peer_id != PEER_ID_INEXISTENT)
1702 m_clients.sendToAll(&pkt);
1706 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1708 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1710 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1711 << form->text << form->number << form->item << form->dir
1712 << form->align << form->offset << form->world_pos << form->size;
1717 void Server::SendHUDRemove(session_t peer_id, u32 id)
1719 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1724 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1726 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1727 pkt << id << (u8) stat;
1731 case HUD_STAT_SCALE:
1732 case HUD_STAT_ALIGN:
1733 case HUD_STAT_OFFSET:
1734 pkt << *(v2f *) value;
1738 pkt << *(std::string *) value;
1740 case HUD_STAT_WORLD_POS:
1741 pkt << *(v3f *) value;
1744 pkt << *(v2s32 *) value;
1746 case HUD_STAT_NUMBER:
1750 pkt << *(u32 *) value;
1757 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1759 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1761 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1763 pkt << flags << mask;
1768 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1770 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1771 pkt << param << value;
1775 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1776 const std::string &type, const std::vector<std::string> ¶ms,
1779 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1780 pkt << bgcolor << type << (u16) params.size();
1782 for (const std::string ¶m : params)
1790 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1792 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1793 pkt << params.density << params.color_bright << params.color_ambient
1794 << params.height << params.thickness << params.speed;
1798 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1801 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1804 pkt << do_override << (u16) (ratio * 65535);
1809 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1811 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1812 pkt << time << time_speed;
1814 if (peer_id == PEER_ID_INEXISTENT) {
1815 m_clients.sendToAll(&pkt);
1822 void Server::SendPlayerHP(session_t peer_id)
1824 PlayerSAO *playersao = getPlayerSAO(peer_id);
1825 // In some rare case if the player is disconnected
1826 // while Lua call l_punch, for example, this can be NULL
1830 SendHP(peer_id, playersao->getHP());
1831 m_script->player_event(playersao,"health_changed");
1833 // Send to other clients
1834 std::string str = gob_cmd_punched(playersao->getHP());
1835 ActiveObjectMessage aom(playersao->getId(), true, str);
1836 playersao->m_messages_out.push(aom);
1839 void Server::SendPlayerBreath(PlayerSAO *sao)
1843 m_script->player_event(sao, "breath_changed");
1844 SendBreath(sao->getPeerID(), sao->getBreath());
1847 void Server::SendMovePlayer(session_t peer_id)
1849 RemotePlayer *player = m_env->getPlayer(peer_id);
1851 PlayerSAO *sao = player->getPlayerSAO();
1854 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1855 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1858 v3f pos = sao->getBasePosition();
1859 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1860 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1861 << " pitch=" << sao->getLookPitch()
1862 << " yaw=" << sao->getRotation().Y
1869 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1870 f32 animation_speed)
1872 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1875 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1876 << animation_frames[3] << animation_speed;
1881 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1883 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1884 pkt << first << third;
1888 void Server::SendPlayerPrivileges(session_t peer_id)
1890 RemotePlayer *player = m_env->getPlayer(peer_id);
1892 if(player->getPeerId() == PEER_ID_INEXISTENT)
1895 std::set<std::string> privs;
1896 m_script->getAuth(player->getName(), NULL, &privs);
1898 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1899 pkt << (u16) privs.size();
1901 for (const std::string &priv : privs) {
1908 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1910 RemotePlayer *player = m_env->getPlayer(peer_id);
1912 if (player->getPeerId() == PEER_ID_INEXISTENT)
1915 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1916 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1920 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1922 RemotePlayer *player = m_env->getPlayer(peer_id);
1924 if (player->getPeerId() == PEER_ID_INEXISTENT)
1927 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1928 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1932 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1934 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1935 pkt.putRawString(datas.c_str(), datas.size());
1937 return pkt.getSize();
1940 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1943 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1944 datas.size(), peer_id);
1946 pkt.putRawString(datas.c_str(), datas.size());
1948 m_clients.send(pkt.getPeerId(),
1949 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1953 void Server::SendCSMRestrictionFlags(session_t peer_id)
1955 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1956 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1957 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1961 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<session_t> dst_clients;
1973 if(!params.to_player.empty()) {
1974 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1976 infostream<<"Server::playSound: Player \""<<params.to_player
1977 <<"\" not found"<<std::endl;
1980 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1981 infostream<<"Server::playSound: Player \""<<params.to_player
1982 <<"\" not connected"<<std::endl;
1985 dst_clients.push_back(player->getPeerId());
1987 std::vector<session_t> clients = m_clients.getClientIDs();
1989 for (const session_t client_id : clients) {
1990 RemotePlayer *player = m_env->getPlayer(client_id);
1994 PlayerSAO *sao = player->getPlayerSAO();
1999 if(sao->getBasePosition().getDistanceFrom(pos) >
2000 params.max_hear_distance)
2003 dst_clients.push_back(client_id);
2007 if(dst_clients.empty())
2011 s32 id = m_next_sound_id++;
2012 // The sound will exist as a reference in m_playing_sounds
2013 m_playing_sounds[id] = ServerPlayingSound();
2014 ServerPlayingSound &psound = m_playing_sounds[id];
2015 psound.params = params;
2018 float gain = params.gain * spec.gain;
2019 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2020 pkt << id << spec.name << gain
2021 << (u8) params.type << pos << params.object
2022 << params.loop << params.fade << params.pitch;
2024 // Backwards compability
2025 bool play_sound = gain > 0;
2027 for (const u16 dst_client : dst_clients) {
2028 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2029 psound.clients.insert(dst_client);
2030 m_clients.send(dst_client, 0, &pkt, true);
2035 void Server::stopSound(s32 handle)
2037 // Get sound reference
2038 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2039 m_playing_sounds.find(handle);
2040 if (i == m_playing_sounds.end())
2042 ServerPlayingSound &psound = i->second;
2044 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2047 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2048 si != psound.clients.end(); ++si) {
2050 m_clients.send(*si, 0, &pkt, true);
2052 // Remove sound reference
2053 m_playing_sounds.erase(i);
2056 void Server::fadeSound(s32 handle, float step, float gain)
2058 // Get sound reference
2059 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2060 m_playing_sounds.find(handle);
2061 if (i == m_playing_sounds.end())
2064 ServerPlayingSound &psound = i->second;
2065 psound.params.gain = gain;
2067 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2068 pkt << handle << step << gain;
2070 // Backwards compability
2071 bool play_sound = gain > 0;
2072 ServerPlayingSound compat_psound = psound;
2073 compat_psound.clients.clear();
2075 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2076 compat_pkt << handle;
2078 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2079 it != psound.clients.end();) {
2080 if (m_clients.getProtocolVersion(*it) >= 32) {
2082 m_clients.send(*it, 0, &pkt, true);
2085 compat_psound.clients.insert(*it);
2087 m_clients.send(*it, 0, &compat_pkt, true);
2088 psound.clients.erase(it++);
2092 // Remove sound reference
2093 if (!play_sound || psound.clients.empty())
2094 m_playing_sounds.erase(i);
2096 if (play_sound && !compat_psound.clients.empty()) {
2097 // Play new sound volume on older clients
2098 playSound(compat_psound.spec, compat_psound.params);
2102 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2105 float maxd = far_d_nodes * BS;
2106 v3f p_f = intToFloat(p, BS);
2107 v3s16 block_pos = getNodeBlockPos(p);
2109 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2112 std::vector<session_t> clients = m_clients.getClientIDs();
2115 for (session_t client_id : clients) {
2116 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2120 RemotePlayer *player = m_env->getPlayer(client_id);
2121 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2123 // If player is far away, only set modified blocks not sent
2124 if (!client->isBlockSent(block_pos) || (sao &&
2125 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2127 far_players->emplace(client_id);
2129 client->SetBlockNotSent(block_pos);
2134 m_clients.send(client_id, 0, &pkt, true);
2140 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2141 float far_d_nodes, bool remove_metadata)
2143 float maxd = far_d_nodes * BS;
2144 v3f p_f = intToFloat(p, BS);
2145 v3s16 block_pos = getNodeBlockPos(p);
2147 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2148 pkt << p << n.param0 << n.param1 << n.param2
2149 << (u8) (remove_metadata ? 0 : 1);
2151 std::vector<session_t> clients = m_clients.getClientIDs();
2154 for (session_t client_id : clients) {
2155 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2159 RemotePlayer *player = m_env->getPlayer(client_id);
2160 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2162 // If player is far away, only set modified blocks not sent
2163 if (!client->isBlockSent(block_pos) || (sao &&
2164 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2166 far_players->emplace(client_id);
2168 client->SetBlockNotSent(block_pos);
2173 m_clients.send(client_id, 0, &pkt, true);
2179 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2181 float maxd = far_d_nodes * BS;
2182 NodeMetadataList meta_updates_list(false);
2183 std::vector<session_t> clients = m_clients.getClientIDs();
2187 for (session_t i : clients) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2192 ServerActiveObject *player = m_env->getActiveObject(i);
2193 v3f player_pos = player ? player->getBasePosition() : v3f();
2195 for (const v3s16 &pos : meta_updates) {
2196 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2201 v3s16 block_pos = getNodeBlockPos(pos);
2202 if (!client->isBlockSent(block_pos) || (player &&
2203 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2204 client->SetBlockNotSent(block_pos);
2208 // Add the change to send list
2209 meta_updates_list.set(pos, meta);
2211 if (meta_updates_list.size() == 0)
2214 // Send the meta changes
2215 std::ostringstream os(std::ios::binary);
2216 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2217 std::ostringstream oss(std::ios::binary);
2218 compressZlib(os.str(), oss);
2220 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2221 pkt.putLongString(oss.str());
2222 m_clients.send(i, 0, &pkt, true);
2224 meta_updates_list.clear();
2230 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2231 u16 net_proto_version)
2234 Create a packet with the block in the right format
2237 std::ostringstream os(std::ios_base::binary);
2238 block->serialize(os, ver, false);
2239 block->serializeNetworkSpecific(os);
2240 std::string s = os.str();
2242 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2244 pkt << block->getPos();
2245 pkt.putRawString(s.c_str(), s.size());
2249 void Server::SendBlocks(float dtime)
2251 MutexAutoLock envlock(m_env_mutex);
2252 //TODO check if one big lock could be faster then multiple small ones
2254 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2256 std::vector<PrioritySortedBlockTransfer> queue;
2258 u32 total_sending = 0;
2261 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (const session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2272 total_sending += client->getSendingCount();
2273 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2279 // Lowest priority number comes first.
2280 // Lowest is most important.
2281 std::sort(queue.begin(), queue.end());
2285 // Maximal total count calculation
2286 // The per-client block sends is halved with the maximal online users
2287 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2288 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2290 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2291 if (total_sending >= max_blocks_to_send)
2294 MapBlock *block = nullptr;
2296 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2297 } catch (const InvalidPositionException &e) {
2301 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2306 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2307 client->net_proto_version);
2309 client->SentBlock(block_to_send.pos);
2315 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2317 MapBlock *block = nullptr;
2319 block = m_env->getMap().getBlockNoCreate(blockpos);
2320 } catch (InvalidPositionException &e) {};
2325 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2326 if (!client || client->isBlockSent(blockpos)) {
2330 SendBlockNoLock(peer_id, block, client->serialization_version,
2331 client->net_proto_version);
2337 void Server::fillMediaCache()
2339 infostream<<"Server: Calculating media file checksums"<<std::endl;
2341 // Collect all media file paths
2342 std::vector<std::string> paths;
2343 m_modmgr->getModsMediaPaths(paths);
2344 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2345 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2347 // Collect media file information from paths into cache
2348 for (const std::string &mediapath : paths) {
2349 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2350 for (const fs::DirListNode &dln : dirlist) {
2351 if (dln.dir) // Ignode dirs
2353 std::string filename = dln.name;
2354 // If name contains illegal characters, ignore the file
2355 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2356 infostream<<"Server: ignoring illegal file name: \""
2357 << filename << "\"" << std::endl;
2360 // If name is not in a supported format, ignore it
2361 const char *supported_ext[] = {
2362 ".png", ".jpg", ".bmp", ".tga",
2363 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2365 ".x", ".b3d", ".md2", ".obj",
2366 // Custom translation file format
2370 if (removeStringEnd(filename, supported_ext).empty()){
2371 infostream << "Server: ignoring unsupported file extension: \""
2372 << filename << "\"" << std::endl;
2375 // Ok, attempt to load the file and add to cache
2376 std::string filepath;
2377 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2380 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2382 errorstream << "Server::fillMediaCache(): Could not open \""
2383 << filename << "\" for reading" << std::endl;
2386 std::ostringstream tmp_os(std::ios_base::binary);
2390 fis.read(buf, 1024);
2391 std::streamsize len = fis.gcount();
2392 tmp_os.write(buf, len);
2401 errorstream<<"Server::fillMediaCache(): Failed to read \""
2402 << filename << "\"" << std::endl;
2405 if(tmp_os.str().length() == 0) {
2406 errorstream << "Server::fillMediaCache(): Empty file \""
2407 << filepath << "\"" << std::endl;
2412 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2414 unsigned char *digest = sha1.getDigest();
2415 std::string sha1_base64 = base64_encode(digest, 20);
2416 std::string sha1_hex = hex_encode((char*)digest, 20);
2420 m_media[filename] = MediaInfo(filepath, sha1_base64);
2421 verbosestream << "Server: " << sha1_hex << " is " << filename
2427 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2429 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2433 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2436 std::string lang_suffix;
2437 lang_suffix.append(".").append(lang_code).append(".tr");
2438 for (const auto &i : m_media) {
2439 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2446 for (const auto &i : m_media) {
2447 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2449 pkt << i.first << i.second.sha1_digest;
2452 pkt << g_settings->get("remote_media");
2456 struct SendableMedia
2462 SendableMedia(const std::string &name_="", const std::string &path_="",
2463 const std::string &data_=""):
2470 void Server::sendRequestedMedia(session_t peer_id,
2471 const std::vector<std::string> &tosend)
2473 verbosestream<<"Server::sendRequestedMedia(): "
2474 <<"Sending files to client"<<std::endl;
2478 // Put 5kB in one bunch (this is not accurate)
2479 u32 bytes_per_bunch = 5000;
2481 std::vector< std::vector<SendableMedia> > file_bunches;
2482 file_bunches.emplace_back();
2484 u32 file_size_bunch_total = 0;
2486 for (const std::string &name : tosend) {
2487 if (m_media.find(name) == m_media.end()) {
2488 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2489 <<"unknown file \""<<(name)<<"\""<<std::endl;
2493 //TODO get path + name
2494 std::string tpath = m_media[name].path;
2497 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2499 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2500 <<tpath<<"\" for reading"<<std::endl;
2503 std::ostringstream tmp_os(std::ios_base::binary);
2507 fis.read(buf, 1024);
2508 std::streamsize len = fis.gcount();
2509 tmp_os.write(buf, len);
2510 file_size_bunch_total += len;
2519 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2520 <<name<<"\""<<std::endl;
2523 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2524 <<tname<<"\""<<std::endl;*/
2526 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2528 // Start next bunch if got enough data
2529 if(file_size_bunch_total >= bytes_per_bunch) {
2530 file_bunches.emplace_back();
2531 file_size_bunch_total = 0;
2536 /* Create and send packets */
2538 u16 num_bunches = file_bunches.size();
2539 for (u16 i = 0; i < num_bunches; i++) {
2542 u16 total number of texture bunches
2543 u16 index of this bunch
2544 u32 number of files in this bunch
2553 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2554 pkt << num_bunches << i << (u32) file_bunches[i].size();
2556 for (const SendableMedia &j : file_bunches[i]) {
2558 pkt.putLongString(j.data);
2561 verbosestream << "Server::sendRequestedMedia(): bunch "
2562 << i << "/" << num_bunches
2563 << " files=" << file_bunches[i].size()
2564 << " size=" << pkt.getSize() << std::endl;
2569 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2571 const auto &inv_it = m_detached_inventories.find(name);
2572 const auto &player_it = m_detached_inventories_player.find(name);
2574 if (player_it == m_detached_inventories_player.end() ||
2575 player_it->second.empty()) {
2576 // OK. Send to everyone
2578 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2580 return; // Player is offline
2582 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2583 return; // Caller requested send to a different player, so don't send.
2585 peer_id = p->getPeerId();
2588 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2591 if (inv_it == m_detached_inventories.end()) {
2592 pkt << false; // Remove inventory
2594 pkt << true; // Update inventory
2596 // Serialization & NetworkPacket isn't a love story
2597 std::ostringstream os(std::ios_base::binary);
2598 inv_it->second->serialize(os);
2600 std::string os_str = os.str();
2601 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2602 pkt.putRawString(os_str);
2605 if (peer_id == PEER_ID_INEXISTENT)
2606 m_clients.sendToAll(&pkt);
2611 void Server::sendDetachedInventories(session_t peer_id)
2613 for (const auto &detached_inventory : m_detached_inventories) {
2614 const std::string &name = detached_inventory.first;
2615 //Inventory *inv = i->second;
2616 sendDetachedInventory(name, peer_id);
2624 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2626 PlayerSAO *playersao = getPlayerSAO(peer_id);
2627 // In some rare cases this can be NULL -- if the player is disconnected
2628 // when a Lua function modifies l_punch, for example
2632 infostream << "Server::DiePlayer(): Player "
2633 << playersao->getPlayer()->getName()
2634 << " dies" << std::endl;
2636 playersao->setHP(0, reason);
2637 playersao->clearParentAttachment();
2639 // Trigger scripted stuff
2640 m_script->on_dieplayer(playersao, reason);
2642 SendPlayerHP(peer_id);
2643 SendDeathscreen(peer_id, false, v3f(0,0,0));
2646 void Server::RespawnPlayer(session_t peer_id)
2648 PlayerSAO *playersao = getPlayerSAO(peer_id);
2651 infostream << "Server::RespawnPlayer(): Player "
2652 << playersao->getPlayer()->getName()
2653 << " respawns" << std::endl;
2655 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2656 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2657 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2659 bool repositioned = m_script->on_respawnplayer(playersao);
2660 if (!repositioned) {
2661 // setPos will send the new position to client
2662 playersao->setPos(findSpawnPos());
2665 SendPlayerHP(peer_id);
2669 void Server::DenySudoAccess(session_t peer_id)
2671 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2676 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2677 const std::string &str_reason, bool reconnect)
2679 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2681 m_clients.event(peer_id, CSE_SetDenied);
2682 DisconnectPeer(peer_id);
2686 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2687 const std::string &custom_reason)
2689 SendAccessDenied(peer_id, reason, custom_reason);
2690 m_clients.event(peer_id, CSE_SetDenied);
2691 DisconnectPeer(peer_id);
2694 // 13/03/15: remove this function when protocol version 25 will become
2695 // the minimum version for MT users, maybe in 1 year
2696 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2698 SendAccessDenied_Legacy(peer_id, reason);
2699 m_clients.event(peer_id, CSE_SetDenied);
2700 DisconnectPeer(peer_id);
2703 void Server::DisconnectPeer(session_t peer_id)
2705 m_modchannel_mgr->leaveAllChannels(peer_id);
2706 m_con->DisconnectPeer(peer_id);
2709 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2712 RemoteClient* client = getClient(peer_id, CS_Invalid);
2714 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2716 // Right now, the auth mechs don't change between login and sudo mode.
2717 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2718 client->allowed_sudo_mechs = sudo_auth_mechs;
2720 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2721 << g_settings->getFloat("dedicated_server_step")
2725 m_clients.event(peer_id, CSE_AuthAccept);
2727 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2729 // We only support SRP right now
2730 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2732 resp_pkt << sudo_auth_mechs;
2734 m_clients.event(peer_id, CSE_SudoSuccess);
2738 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2740 std::wstring message;
2743 Clear references to playing sounds
2745 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2746 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2747 ServerPlayingSound &psound = i->second;
2748 psound.clients.erase(peer_id);
2749 if (psound.clients.empty())
2750 m_playing_sounds.erase(i++);
2755 // clear formspec info so the next client can't abuse the current state
2756 m_formspec_state_data.erase(peer_id);
2758 RemotePlayer *player = m_env->getPlayer(peer_id);
2760 /* Run scripts and remove from environment */
2762 PlayerSAO *playersao = player->getPlayerSAO();
2765 playersao->clearChildAttachments();
2766 playersao->clearParentAttachment();
2768 // inform connected clients
2769 const std::string &player_name = player->getName();
2770 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2771 // (u16) 1 + std::string represents a vector serialization representation
2772 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2773 m_clients.sendToAll(¬ice);
2775 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2777 playersao->disconnected();
2784 if (player && reason != CDR_DENY) {
2785 std::ostringstream os(std::ios_base::binary);
2786 std::vector<session_t> clients = m_clients.getClientIDs();
2788 for (const session_t client_id : clients) {
2790 RemotePlayer *player = m_env->getPlayer(client_id);
2794 // Get name of player
2795 os << player->getName() << " ";
2798 std::string name = player->getName();
2799 actionstream << name << " "
2800 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2801 << " List of players: " << os.str() << std::endl;
2803 m_admin_chat->outgoing_queue.push_back(
2804 new ChatEventNick(CET_NICK_REMOVE, name));
2808 MutexAutoLock env_lock(m_env_mutex);
2809 m_clients.DeleteClient(peer_id);
2813 // Send leave chat message to all remaining clients
2814 if (!message.empty()) {
2815 SendChatMessage(PEER_ID_INEXISTENT,
2816 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2820 void Server::UpdateCrafting(RemotePlayer *player)
2822 InventoryList *clist = player->inventory.getList("craft");
2823 if (!clist || clist->getSize() == 0)
2826 // Get a preview for crafting
2828 InventoryLocation loc;
2829 loc.setPlayer(player->getName());
2830 std::vector<ItemStack> output_replacements;
2831 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2832 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2835 InventoryList *plist = player->inventory.getList("craftpreview");
2836 if (plist && plist->getSize() >= 1) {
2837 // Put the new preview in
2838 plist->changeItem(0, preview);
2842 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2844 if (evt->type == CET_NICK_ADD) {
2845 // The terminal informed us of its nick choice
2846 m_admin_nick = ((ChatEventNick *)evt)->nick;
2847 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2848 errorstream << "You haven't set up an account." << std::endl
2849 << "Please log in using the client as '"
2850 << m_admin_nick << "' with a secure password." << std::endl
2851 << "Until then, you can't execute admin tasks via the console," << std::endl
2852 << "and everybody can claim the user account instead of you," << std::endl
2853 << "giving them full control over this server." << std::endl;
2856 assert(evt->type == CET_CHAT);
2857 handleAdminChat((ChatEventChat *)evt);
2861 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2862 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2864 // If something goes wrong, this player is to blame
2865 RollbackScopeActor rollback_scope(m_rollback,
2866 std::string("player:") + name);
2868 if (g_settings->getBool("strip_color_codes"))
2869 wmessage = unescape_enriched(wmessage);
2872 switch (player->canSendChatMessage()) {
2873 case RPLAYER_CHATRESULT_FLOODING: {
2874 std::wstringstream ws;
2875 ws << L"You cannot send more messages. You are limited to "
2876 << g_settings->getFloat("chat_message_limit_per_10sec")
2877 << L" messages per 10 seconds.";
2880 case RPLAYER_CHATRESULT_KICK:
2881 DenyAccess_Legacy(player->getPeerId(),
2882 L"You have been kicked due to message flooding.");
2884 case RPLAYER_CHATRESULT_OK:
2887 FATAL_ERROR("Unhandled chat filtering result found.");
2891 if (m_max_chatmessage_length > 0
2892 && wmessage.length() > m_max_chatmessage_length) {
2893 return L"Your message exceed the maximum chat message limit set on the server. "
2894 L"It was refused. Send a shorter message";
2897 auto message = trim(wide_to_utf8(wmessage));
2898 if (message.find_first_of("\n\r") != std::wstring::npos) {
2899 return L"New lines are not permitted in chat messages";
2902 // Run script hook, exit if script ate the chat message
2903 if (m_script->on_chat_message(name, message))
2908 // Whether to send line to the player that sent the message, or to all players
2909 bool broadcast_line = true;
2911 if (check_shout_priv && !checkPriv(name, "shout")) {
2912 line += L"-!- You don't have permission to shout.";
2913 broadcast_line = false;
2922 Tell calling method to send the message to sender
2924 if (!broadcast_line)
2928 Send the message to others
2930 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2932 std::vector<session_t> clients = m_clients.getClientIDs();
2935 Send the message back to the inital sender
2936 if they are using protocol version >= 29
2939 session_t peer_id_to_avoid_sending =
2940 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2942 if (player && player->protocol_version >= 29)
2943 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2945 for (u16 cid : clients) {
2946 if (cid != peer_id_to_avoid_sending)
2947 SendChatMessage(cid, ChatMessage(line));
2952 void Server::handleAdminChat(const ChatEventChat *evt)
2954 std::string name = evt->nick;
2955 std::wstring wname = utf8_to_wide(name);
2956 std::wstring wmessage = evt->evt_msg;
2958 std::wstring answer = handleChat(name, wname, wmessage);
2960 // If asked to send answer to sender
2961 if (!answer.empty()) {
2962 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2966 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2968 RemoteClient *client = getClientNoEx(peer_id,state_min);
2970 throw ClientNotFoundException("Client not found");
2974 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2976 return m_clients.getClientNoEx(peer_id, state_min);
2979 std::string Server::getPlayerName(session_t peer_id)
2981 RemotePlayer *player = m_env->getPlayer(peer_id);
2983 return "[id="+itos(peer_id)+"]";
2984 return player->getName();
2987 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2989 RemotePlayer *player = m_env->getPlayer(peer_id);
2992 return player->getPlayerSAO();
2995 std::wstring Server::getStatusString()
2997 std::wostringstream os(std::ios_base::binary);
2998 os << L"# Server: ";
3000 os << L"version=" << narrow_to_wide(g_version_string);
3002 os << L", uptime=" << m_uptime.get();
3004 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3006 // Information about clients
3008 os << L", clients={";
3010 std::vector<session_t> clients = m_clients.getClientIDs();
3011 for (session_t client_id : clients) {
3012 RemotePlayer *player = m_env->getPlayer(client_id);
3014 // Get name of player
3015 std::wstring name = L"unknown";
3017 name = narrow_to_wide(player->getName());
3019 // Add name to information string
3030 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3031 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3033 if (!g_settings->get("motd").empty())
3034 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3039 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3041 std::set<std::string> privs;
3042 m_script->getAuth(name, NULL, &privs);
3046 bool Server::checkPriv(const std::string &name, const std::string &priv)
3048 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3049 return (privs.count(priv) != 0);
3052 void Server::reportPrivsModified(const std::string &name)
3055 std::vector<session_t> clients = m_clients.getClientIDs();
3056 for (const session_t client_id : clients) {
3057 RemotePlayer *player = m_env->getPlayer(client_id);
3058 reportPrivsModified(player->getName());
3061 RemotePlayer *player = m_env->getPlayer(name.c_str());
3064 SendPlayerPrivileges(player->getPeerId());
3065 PlayerSAO *sao = player->getPlayerSAO();
3068 sao->updatePrivileges(
3069 getPlayerEffectivePrivs(name),
3074 void Server::reportInventoryFormspecModified(const std::string &name)
3076 RemotePlayer *player = m_env->getPlayer(name.c_str());
3079 SendPlayerInventoryFormspec(player->getPeerId());
3082 void Server::reportFormspecPrependModified(const std::string &name)
3084 RemotePlayer *player = m_env->getPlayer(name.c_str());
3087 SendPlayerFormspecPrepend(player->getPeerId());
3090 void Server::setIpBanned(const std::string &ip, const std::string &name)
3092 m_banmanager->add(ip, name);
3095 void Server::unsetIpBanned(const std::string &ip_or_name)
3097 m_banmanager->remove(ip_or_name);
3100 std::string Server::getBanDescription(const std::string &ip_or_name)
3102 return m_banmanager->getBanDescription(ip_or_name);
3105 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3107 // m_env will be NULL if the server is initializing
3111 if (m_admin_nick == name && !m_admin_nick.empty()) {
3112 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3115 RemotePlayer *player = m_env->getPlayer(name);
3120 if (player->getPeerId() == PEER_ID_INEXISTENT)
3123 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3126 bool Server::showFormspec(const char *playername, const std::string &formspec,
3127 const std::string &formname)
3129 // m_env will be NULL if the server is initializing
3133 RemotePlayer *player = m_env->getPlayer(playername);
3137 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3141 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3146 u32 id = player->addHud(form);
3148 SendHUDAdd(player->getPeerId(), id, form);
3153 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3157 HudElement* todel = player->removeHud(id);
3164 SendHUDRemove(player->getPeerId(), id);
3168 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3173 SendHUDChange(player->getPeerId(), id, stat, data);
3177 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3182 SendHUDSetFlags(player->getPeerId(), flags, mask);
3183 player->hud_flags &= ~mask;
3184 player->hud_flags |= flags;
3186 PlayerSAO* playersao = player->getPlayerSAO();
3191 m_script->player_event(playersao, "hud_changed");
3195 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3200 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3203 player->setHotbarItemcount(hotbar_itemcount);
3204 std::ostringstream os(std::ios::binary);
3205 writeS32(os, hotbar_itemcount);
3206 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3210 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3215 player->setHotbarImage(name);
3216 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3219 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3224 player->setHotbarSelectedImage(name);
3225 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3228 Address Server::getPeerAddress(session_t peer_id)
3230 return m_con->GetPeerAddress(peer_id);
3233 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3234 v2s32 animation_frames[4], f32 frame_speed)
3236 sanity_check(player);
3237 player->setLocalAnimations(animation_frames, frame_speed);
3238 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3241 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3243 sanity_check(player);
3244 player->eye_offset_first = first;
3245 player->eye_offset_third = third;
3246 SendEyeOffset(player->getPeerId(), first, third);
3249 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3250 const std::string &type, const std::vector<std::string> ¶ms,
3253 sanity_check(player);
3254 player->setSky(bgcolor, type, params, clouds);
3255 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3258 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3260 sanity_check(player);
3261 player->setCloudParams(params);
3262 SendCloudParams(player->getPeerId(), params);
3265 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3271 player->overrideDayNightRatio(do_override, ratio);
3272 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3276 void Server::notifyPlayers(const std::wstring &msg)
3278 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3281 void Server::spawnParticle(const std::string &playername, v3f pos,
3282 v3f velocity, v3f acceleration,
3283 float expirationtime, float size, bool
3284 collisiondetection, bool collision_removal, bool object_collision,
3285 bool vertical, const std::string &texture,
3286 const struct TileAnimationParams &animation, u8 glow)
3288 // m_env will be NULL if the server is initializing
3292 session_t peer_id = PEER_ID_INEXISTENT;
3294 if (!playername.empty()) {
3295 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3298 peer_id = player->getPeerId();
3299 proto_ver = player->protocol_version;
3302 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3303 expirationtime, size, collisiondetection, collision_removal,
3304 object_collision, vertical, texture, animation, glow);
3307 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3308 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3309 float minexptime, float maxexptime, float minsize, float maxsize,
3310 bool collisiondetection, bool collision_removal, bool object_collision,
3311 ServerActiveObject *attached, bool vertical, const std::string &texture,
3312 const std::string &playername, const struct TileAnimationParams &animation,
3315 // m_env will be NULL if the server is initializing
3319 session_t peer_id = PEER_ID_INEXISTENT;
3321 if (!playername.empty()) {
3322 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3325 peer_id = player->getPeerId();
3326 proto_ver = player->protocol_version;
3329 u16 attached_id = attached ? attached->getId() : 0;
3332 if (attached_id == 0)
3333 id = m_env->addParticleSpawner(spawntime);
3335 id = m_env->addParticleSpawner(spawntime, attached_id);
3337 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3338 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3339 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3340 collision_removal, object_collision, attached_id, vertical,
3341 texture, id, animation, glow);
3346 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3348 // m_env will be NULL if the server is initializing
3350 throw ServerError("Can't delete particle spawners during initialisation!");
3352 session_t peer_id = PEER_ID_INEXISTENT;
3353 if (!playername.empty()) {
3354 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3357 peer_id = player->getPeerId();
3360 m_env->deleteParticleSpawner(id);
3361 SendDeleteParticleSpawner(peer_id, id);
3364 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3366 if(m_detached_inventories.count(name) > 0){
3367 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3368 delete m_detached_inventories[name];
3370 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3372 Inventory *inv = new Inventory(m_itemdef);
3374 m_detached_inventories[name] = inv;
3375 m_detached_inventories_player[name] = player;
3376 //TODO find a better way to do this
3377 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3381 bool Server::removeDetachedInventory(const std::string &name)
3383 const auto &inv_it = m_detached_inventories.find(name);
3384 if (inv_it == m_detached_inventories.end())
3387 delete inv_it->second;
3388 m_detached_inventories.erase(inv_it);
3390 const auto &player_it = m_detached_inventories_player.find(name);
3391 if (player_it != m_detached_inventories_player.end()) {
3392 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3394 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3395 sendDetachedInventory(name, player->getPeerId());
3397 m_detached_inventories_player.erase(player_it);
3399 // Notify all players about the change
3400 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3405 // actions: time-reversed list
3406 // Return value: success/failure
3407 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3408 std::list<std::string> *log)
3410 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3411 ServerMap *map = (ServerMap*)(&m_env->getMap());
3413 // Fail if no actions to handle
3414 if (actions.empty()) {
3416 log->push_back("Nothing to do.");
3423 for (const RollbackAction &action : actions) {
3425 bool success = action.applyRevert(map, this, this);
3428 std::ostringstream os;
3429 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3430 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3432 log->push_back(os.str());
3434 std::ostringstream os;
3435 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3436 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3438 log->push_back(os.str());
3442 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3443 <<" failed"<<std::endl;
3445 // Call it done if less than half failed
3446 return num_failed <= num_tried/2;
3449 // IGameDef interface
3451 IItemDefManager *Server::getItemDefManager()
3456 const NodeDefManager *Server::getNodeDefManager()
3461 ICraftDefManager *Server::getCraftDefManager()
3466 u16 Server::allocateUnknownNodeId(const std::string &name)
3468 return m_nodedef->allocateDummy(name);
3471 IWritableItemDefManager *Server::getWritableItemDefManager()
3476 NodeDefManager *Server::getWritableNodeDefManager()
3481 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3486 const std::vector<ModSpec> & Server::getMods() const
3488 return m_modmgr->getMods();
3491 const ModSpec *Server::getModSpec(const std::string &modname) const
3493 return m_modmgr->getModSpec(modname);
3496 void Server::getModNames(std::vector<std::string> &modlist)
3498 m_modmgr->getModNames(modlist);
3501 std::string Server::getBuiltinLuaPath()
3503 return porting::path_share + DIR_DELIM + "builtin";
3506 std::string Server::getModStoragePath() const
3508 return m_path_world + DIR_DELIM + "mod_storage";
3511 v3f Server::findSpawnPos()
3513 ServerMap &map = m_env->getServerMap();
3515 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3516 return nodeposf * BS;
3519 bool is_good = false;
3520 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3521 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3523 // Try to find a good place a few times
3524 for(s32 i = 0; i < 4000 && !is_good; i++) {
3525 s32 range = MYMIN(1 + i, range_max);
3526 // We're going to try to throw the player to this position
3527 v2s16 nodepos2d = v2s16(
3528 -range + (myrand() % (range * 2)),
3529 -range + (myrand() % (range * 2)));
3531 // Get spawn level at point
3532 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3533 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3534 // the mapgen to signify an unsuitable spawn position
3535 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3538 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3541 for (s32 i = 0; i < 10; i++) {
3542 v3s16 blockpos = getNodeBlockPos(nodepos);
3543 map.emergeBlock(blockpos, true);
3544 content_t c = map.getNodeNoEx(nodepos).getContent();
3545 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3547 if (air_count >= 2) {
3548 nodeposf = intToFloat(nodepos, BS);
3549 // Don't spawn the player outside map boundaries
3550 if (objectpos_over_limit(nodeposf))
3563 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3565 if (delay == 0.0f) {
3566 // No delay, shutdown immediately
3567 m_shutdown_state.is_requested = true;
3568 // only print to the infostream, a chat message saying
3569 // "Server Shutting Down" is sent when the server destructs.
3570 infostream << "*** Immediate Server shutdown requested." << std::endl;
3571 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3572 // Negative delay, cancel shutdown if requested
3573 m_shutdown_state.reset();
3574 std::wstringstream ws;
3576 ws << L"*** Server shutdown canceled.";
3578 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3579 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3580 // m_shutdown_* are already handled, skip.
3582 } else if (delay > 0.0f) {
3583 // Positive delay, tell the clients when the server will shut down
3584 std::wstringstream ws;
3586 ws << L"*** Server shutting down in "
3587 << duration_to_string(myround(delay)).c_str()
3590 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3591 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3594 m_shutdown_state.trigger(delay, msg, reconnect);
3597 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3600 Try to get an existing player
3602 RemotePlayer *player = m_env->getPlayer(name);
3604 // If player is already connected, cancel
3605 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3606 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3611 If player with the wanted peer_id already exists, cancel.
3613 if (m_env->getPlayer(peer_id)) {
3614 infostream<<"emergePlayer(): Player with wrong name but same"
3615 " peer_id already exists"<<std::endl;
3620 player = new RemotePlayer(name, idef());
3623 bool newplayer = false;
3626 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3628 // Complete init with server parts
3629 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3630 player->protocol_version = proto_version;
3634 m_script->on_newplayer(playersao);
3640 bool Server::registerModStorage(ModMetadata *storage)
3642 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3643 errorstream << "Unable to register same mod storage twice. Storage name: "
3644 << storage->getModName() << std::endl;
3648 m_mod_storages[storage->getModName()] = storage;
3652 void Server::unregisterModStorage(const std::string &name)
3654 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3655 if (it != m_mod_storages.end()) {
3656 // Save unconditionaly on unregistration
3657 it->second->save(getModStoragePath());
3658 m_mod_storages.erase(name);
3662 void dedicated_server_loop(Server &server, bool &kill)
3664 verbosestream<<"dedicated_server_loop()"<<std::endl;
3666 IntervalLimiter m_profiler_interval;
3668 static thread_local const float steplen =
3669 g_settings->getFloat("dedicated_server_step");
3670 static thread_local const float profiler_print_interval =
3671 g_settings->getFloat("profiler_print_interval");
3674 // This is kind of a hack but can be done like this
3675 // because server.step() is very light
3677 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3678 sleep_ms((int)(steplen*1000.0));
3680 server.step(steplen);
3682 if (server.isShutdownRequested() || kill)
3688 if (profiler_print_interval != 0) {
3689 if(m_profiler_interval.step(steplen, profiler_print_interval))
3691 infostream<<"Profiler:"<<std::endl;
3692 g_profiler->print(infostream);
3693 g_profiler->clear();
3698 infostream << "Dedicated server quitting" << std::endl;
3700 if (g_settings->getBool("server_announce"))
3701 ServerList::sendAnnounce(ServerList::AA_DELETE,
3702 server.m_bind_addr.getPort());
3711 bool Server::joinModChannel(const std::string &channel)
3713 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3714 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3717 bool Server::leaveModChannel(const std::string &channel)
3719 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3722 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3724 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3727 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3731 ModChannel* Server::getModChannel(const std::string &channel)
3733 return m_modchannel_mgr->getModChannel(channel);
3736 void Server::broadcastModChannelMessage(const std::string &channel,
3737 const std::string &message, session_t from_peer)
3739 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3743 if (message.size() > STRING_MAX_LEN) {
3744 warningstream << "ModChannel message too long, dropping before sending "
3745 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3746 << channel << ")" << std::endl;
3751 if (from_peer != PEER_ID_SERVER) {
3752 sender = getPlayerName(from_peer);
3755 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3756 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3757 resp_pkt << channel << sender << message;
3758 for (session_t peer_id : peers) {
3760 if (peer_id == from_peer)
3763 Send(peer_id, &resp_pkt);
3766 if (from_peer != PEER_ID_SERVER) {
3767 m_script->on_modchannel_message(channel, sender, message);