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/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_server.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_sao.h"
52 #include "event_manager.h"
53 #include "serverlist.h"
54 #include "util/string.h"
56 #include "util/serialize.h"
57 #include "util/thread.h"
58 #include "defaultsettings.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public Thread
79 ServerThread(Server *server):
90 void *ServerThread::run()
92 DSTACK(FUNCTION_NAME);
93 BEGIN_DEBUG_EXCEPTION_HANDLER
95 m_server->AsyncRunStep(true);
97 while (!stopRequested()) {
99 m_server->AsyncRunStep();
103 } catch (con::NoIncomingDataException &e) {
104 } catch (con::PeerNotFoundException &e) {
105 infostream<<"Server: PeerNotFoundException"<<std::endl;
106 } catch (ClientNotFoundException &e) {
107 } catch (con::ConnectionBindFailed &e) {
108 m_server->setAsyncFatalError(e.what());
109 } catch (LuaError &e) {
110 m_server->setAsyncFatalError(
111 "ServerThread::run Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
155 m_path_world(path_world),
156 m_gamespec(gamespec),
157 m_simple_singleplayer_mode(simple_singleplayer_mode),
158 m_dedicated(dedicated),
159 m_async_fatal_error(""),
165 m_itemdef(createItemDefManager()),
166 m_nodedef(createNodeDefManager()),
167 m_craftdef(createCraftDefManager()),
168 m_event(new EventManager()),
173 m_lag = g_settings->getFloat("dedicated_server_step");
175 if (path_world.empty())
176 throw ServerError("Supplied empty world path");
178 if(!gamespec.isValid())
179 throw ServerError("Supplied invalid gamespec");
181 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
182 if(m_simple_singleplayer_mode)
183 infostream<<" in simple singleplayer mode"<<std::endl;
185 infostream<<std::endl;
186 infostream<<"- world: "<<m_path_world<<std::endl;
187 infostream<<"- game: "<<m_gamespec.path<<std::endl;
189 // Create world if it doesn't exist
190 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
191 throw ServerError("Failed to initialize world");
193 // Create server thread
194 m_thread = new ServerThread(this);
196 // Create emerge manager
197 m_emerge = new EmergeManager(this);
199 // Create ban manager
200 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
201 m_banmanager = new BanManager(ban_path);
203 ServerModConfiguration modconf(m_path_world);
204 m_mods = modconf.getMods();
205 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
206 // complain about mods with unsatisfied dependencies
207 if (!modconf.isConsistent()) {
208 modconf.printUnsatisfiedModsError();
212 MutexAutoLock envlock(m_env_mutex);
214 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
215 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
217 // Initialize scripting
218 infostream<<"Server: Initializing Lua"<<std::endl;
220 m_script = new ServerScripting(this);
222 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
225 infostream << "Server: Loading mods: ";
226 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
227 i != m_mods.end(); ++i) {
228 infostream << (*i).name << " ";
230 infostream << std::endl;
231 // Load and run "mod" scripts
232 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
233 it != m_mods.end(); ++it) {
234 const ModSpec &mod = *it;
235 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
236 throw ModError("Error loading mod \"" + mod.name +
237 "\": Mod name does not follow naming conventions: "
238 "Only characters [a-z0-9_] are allowed.");
240 std::string script_path = mod.path + DIR_DELIM + "init.lua";
241 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
242 << script_path << "\"]" << std::endl;
243 m_script->loadMod(script_path, mod.name);
246 // Read Textures and calculate sha1 sums
249 // Apply item aliases in the node definition manager
250 m_nodedef->updateAliases(m_itemdef);
252 // Apply texture overrides from texturepack/override.txt
253 std::string texture_path = g_settings->get("texture_path");
254 if (!texture_path.empty() && fs::IsDir(texture_path))
255 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
257 m_nodedef->setNodeRegistrationStatus(true);
259 // Perform pending node name resolutions
260 m_nodedef->runNodeResolveCallbacks();
262 // unmap node names for connected nodeboxes
263 m_nodedef->mapNodeboxConnections();
265 // init the recipe hashes to speed up crafting
266 m_craftdef->initHashes(this);
268 // Initialize Environment
269 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
271 m_clients.setEnv(m_env);
273 if (!servermap->settings_mgr.makeMapgenParams())
274 FATAL_ERROR("Couldn't create any mapgen type");
276 // Initialize mapgens
277 m_emerge->initMapgens(servermap->getMapgenParams());
279 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
280 if (m_enable_rollback_recording) {
281 // Create rollback manager
282 m_rollback = new RollbackManager(m_path_world, this);
285 // Give environment reference to scripting api
286 m_script->initializeEnvironment(m_env);
288 // Register us to receive map edit events
289 servermap->addEventReceiver(this);
291 // If file exists, load environment metadata
292 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
293 infostream << "Server: Loading environment metadata" << std::endl;
296 m_env->loadDefaultMeta();
299 m_liquid_transform_every = g_settings->getFloat("liquid_update");
300 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
301 m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
302 m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
307 infostream<<"Server destructing"<<std::endl;
309 // Send shutdown message
310 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
311 L"*** Server shutting down"));
314 MutexAutoLock envlock(m_env_mutex);
316 // Execute script shutdown hooks
317 m_script->on_shutdown();
319 infostream << "Server: Saving players" << std::endl;
320 m_env->saveLoadedPlayers();
322 infostream << "Server: Kicking players" << std::endl;
323 std::string kick_msg;
324 bool reconnect = false;
325 if (getShutdownRequested()) {
326 reconnect = m_shutdown_ask_reconnect;
327 kick_msg = m_shutdown_msg;
329 if (kick_msg.empty()) {
330 kick_msg = g_settings->get("kick_msg_shutdown");
332 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
333 kick_msg, reconnect);
335 infostream << "Server: Saving environment metadata" << std::endl;
343 // stop all emerge threads before deleting players that may have
344 // requested blocks to be emerged
345 m_emerge->stopThreads();
347 // Delete things in the reverse order of creation
357 // Deinitialize scripting
358 infostream<<"Server: Deinitializing scripting"<<std::endl;
361 // Delete detached inventories
362 for (std::map<std::string, Inventory*>::iterator
363 i = m_detached_inventories.begin();
364 i != m_detached_inventories.end(); ++i) {
369 void Server::start(Address bind_addr)
371 DSTACK(FUNCTION_NAME);
373 m_bind_addr = bind_addr;
375 infostream<<"Starting server on "
376 << bind_addr.serializeString() <<"..."<<std::endl;
378 // Stop thread if already running
381 // Initialize connection
382 m_con.SetTimeoutMs(30);
383 m_con.Serve(bind_addr);
388 // ASCII art for the win!
390 <<" .__ __ __ "<<std::endl
391 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
392 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
393 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
394 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
395 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
396 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
397 actionstream<<"Server for gameid=\""<<m_gamespec.id
398 <<"\" listening on "<<bind_addr.serializeString()<<":"
399 <<bind_addr.getPort() << "."<<std::endl;
404 DSTACK(FUNCTION_NAME);
406 infostream<<"Server: Stopping and waiting threads"<<std::endl;
408 // Stop threads (set run=false first so both start stopping)
410 //m_emergethread.setRun(false);
412 //m_emergethread.stop();
414 infostream<<"Server: Threads stopped"<<std::endl;
417 void Server::step(float dtime)
419 DSTACK(FUNCTION_NAME);
424 MutexAutoLock lock(m_step_dtime_mutex);
425 m_step_dtime += dtime;
427 // Throw if fatal error occurred in thread
428 std::string async_err = m_async_fatal_error.get();
429 if (!async_err.empty()) {
430 if (!m_simple_singleplayer_mode) {
431 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
432 g_settings->get("kick_msg_crash"),
433 g_settings->getBool("ask_reconnect_on_crash"));
435 throw ServerError("AsyncErr: " + async_err);
439 void Server::AsyncRunStep(bool initial_step)
441 DSTACK(FUNCTION_NAME);
443 g_profiler->add("Server::AsyncRunStep (num)", 1);
447 MutexAutoLock lock1(m_step_dtime_mutex);
448 dtime = m_step_dtime;
452 // Send blocks to clients
456 if((dtime < 0.001) && !initial_step)
459 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
461 //infostream<<"Server steps "<<dtime<<std::endl;
462 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
465 MutexAutoLock lock1(m_step_dtime_mutex);
466 m_step_dtime -= dtime;
473 m_uptime.set(m_uptime.get() + dtime);
479 Update time of day and overall game time
481 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
484 Send to clients at constant intervals
487 m_time_of_day_send_timer -= dtime;
488 if(m_time_of_day_send_timer < 0.0) {
489 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
490 u16 time = m_env->getTimeOfDay();
491 float time_speed = g_settings->getFloat("time_speed");
492 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
496 MutexAutoLock lock(m_env_mutex);
497 // Figure out and report maximum lag to environment
498 float max_lag = m_env->getMaxLagEstimate();
499 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
501 if(dtime > 0.1 && dtime > max_lag * 2.0)
502 infostream<<"Server: Maximum lag peaked to "<<dtime
506 m_env->reportMaxLagEstimate(max_lag);
508 ScopeProfiler sp(g_profiler, "SEnv step");
509 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
513 static const float map_timer_and_unload_dtime = 2.92;
514 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
516 MutexAutoLock lock(m_env_mutex);
517 // Run Map's timers and unload unused data
518 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
519 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
520 g_settings->getFloat("server_unload_unused_data_timeout"),
525 Listen to the admin chat, if available
528 if (!m_admin_chat->command_queue.empty()) {
529 MutexAutoLock lock(m_env_mutex);
530 while (!m_admin_chat->command_queue.empty()) {
531 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
532 handleChatInterfaceEvent(evt);
536 m_admin_chat->outgoing_queue.push_back(
537 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
544 /* Transform liquids */
545 m_liquid_transform_timer += dtime;
546 if(m_liquid_transform_timer >= m_liquid_transform_every)
548 m_liquid_transform_timer -= m_liquid_transform_every;
550 MutexAutoLock lock(m_env_mutex);
552 ScopeProfiler sp(g_profiler, "Server: liquid transform");
554 std::map<v3s16, MapBlock*> modified_blocks;
555 m_env->getMap().transformLiquids(modified_blocks, m_env);
558 Set the modified blocks unsent for all the clients
560 if(!modified_blocks.empty())
562 SetBlocksNotSent(modified_blocks);
565 m_clients.step(dtime);
567 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
569 // send masterserver announce
571 float &counter = m_masterserver_timer;
572 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
573 g_settings->getBool("server_announce")) {
574 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
575 ServerList::AA_START,
576 m_bind_addr.getPort(),
577 m_clients.getPlayerNames(),
579 m_env->getGameTime(),
582 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
592 Check added and deleted active objects
595 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
596 MutexAutoLock envlock(m_env_mutex);
599 const RemoteClientMap &clients = m_clients.getClientList();
600 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
602 // Radius inside which objects are active
603 static thread_local const s16 radius =
604 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
606 // Radius inside which players are active
607 static thread_local const bool is_transfer_limited =
608 g_settings->exists("unlimited_player_transfer_distance") &&
609 !g_settings->getBool("unlimited_player_transfer_distance");
610 static thread_local const s16 player_transfer_dist =
611 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
612 s16 player_radius = player_transfer_dist;
613 if (player_radius == 0 && is_transfer_limited)
614 player_radius = radius;
616 for (const auto &client_it : clients) {
617 RemoteClient *client = client_it.second;
619 // If definitions and textures have not been sent, don't
620 // send objects either
621 if (client->getState() < CS_DefinitionsSent)
624 RemotePlayer *player = m_env->getPlayer(client->peer_id);
626 // This can happen if the client timeouts somehow
630 PlayerSAO *playersao = player->getPlayerSAO();
634 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
635 if (my_radius <= 0) my_radius = radius;
636 //infostream << "Server: Active Radius " << my_radius << std::endl;
638 std::queue<u16> removed_objects;
639 std::queue<u16> added_objects;
640 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
641 client->m_known_objects, removed_objects);
642 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
643 client->m_known_objects, added_objects);
645 // Ignore if nothing happened
646 if (removed_objects.empty() && added_objects.empty()) {
650 std::string data_buffer;
654 // Handle removed objects
655 writeU16((u8*)buf, removed_objects.size());
656 data_buffer.append(buf, 2);
657 while (!removed_objects.empty()) {
659 u16 id = removed_objects.front();
660 ServerActiveObject* obj = m_env->getActiveObject(id);
662 // Add to data buffer for sending
663 writeU16((u8*)buf, id);
664 data_buffer.append(buf, 2);
666 // Remove from known objects
667 client->m_known_objects.erase(id);
669 if(obj && obj->m_known_by_count > 0)
670 obj->m_known_by_count--;
671 removed_objects.pop();
674 // Handle added objects
675 writeU16((u8*)buf, added_objects.size());
676 data_buffer.append(buf, 2);
677 while (!added_objects.empty()) {
679 u16 id = added_objects.front();
680 ServerActiveObject* obj = m_env->getActiveObject(id);
683 u8 type = ACTIVEOBJECT_TYPE_INVALID;
685 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
687 type = obj->getSendType();
689 // Add to data buffer for sending
690 writeU16((u8*)buf, id);
691 data_buffer.append(buf, 2);
692 writeU8((u8*)buf, type);
693 data_buffer.append(buf, 1);
696 data_buffer.append(serializeLongString(
697 obj->getClientInitializationData(client->net_proto_version)));
699 data_buffer.append(serializeLongString(""));
701 // Add to known objects
702 client->m_known_objects.insert(id);
705 obj->m_known_by_count++;
710 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
711 verbosestream << "Server: Sent object remove/add: "
712 << removed_objects.size() << " removed, "
713 << added_objects.size() << " added, "
714 << "packet size is " << pktSize << std::endl;
718 m_mod_storage_save_timer -= dtime;
719 if (m_mod_storage_save_timer <= 0.0f) {
720 infostream << "Saving registered mod storages." << std::endl;
721 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
722 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
723 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
724 if (it->second->isModified()) {
725 it->second->save(getModStoragePath());
735 MutexAutoLock envlock(m_env_mutex);
736 ScopeProfiler sp(g_profiler, "Server: sending object messages");
739 // Value = data sent by object
740 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
742 // Get active object messages from environment
744 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
748 std::vector<ActiveObjectMessage>* message_list = nullptr;
749 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
750 n = buffered_messages.find(aom.id);
751 if (n == buffered_messages.end()) {
752 message_list = new std::vector<ActiveObjectMessage>;
753 buffered_messages[aom.id] = message_list;
756 message_list = n->second;
758 message_list->push_back(aom);
762 const RemoteClientMap &clients = m_clients.getClientList();
763 // Route data to every client
764 for (const auto &client_it : clients) {
765 RemoteClient *client = client_it.second;
766 std::string reliable_data;
767 std::string unreliable_data;
768 // Go through all objects in message buffer
769 for (const auto &buffered_message : buffered_messages) {
770 // If object is not known by client, skip it
771 u16 id = buffered_message.first;
772 if (client->m_known_objects.find(id) == client->m_known_objects.end())
775 // Get message list of object
776 std::vector<ActiveObjectMessage>* list = buffered_message.second;
777 // Go through every message
778 for (const ActiveObjectMessage &aom : *list) {
779 // Compose the full new data with header
780 std::string new_data;
783 writeU16((u8*)&buf[0], aom.id);
784 new_data.append(buf, 2);
786 new_data += serializeString(aom.datastring);
787 // Add data to buffer
789 reliable_data += new_data;
791 unreliable_data += new_data;
795 reliable_data and unreliable_data are now ready.
798 if (!reliable_data.empty()) {
799 SendActiveObjectMessages(client->peer_id, reliable_data);
802 if (!unreliable_data.empty()) {
803 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
808 // Clear buffered_messages
809 for (auto &buffered_message : buffered_messages) {
810 delete buffered_message.second;
815 Send queued-for-sending map edit events.
818 // We will be accessing the environment
819 MutexAutoLock lock(m_env_mutex);
821 // Don't send too many at a time
824 // Single change sending is disabled if queue size is not small
825 bool disable_single_change_sending = false;
826 if(m_unsent_map_edit_queue.size() >= 4)
827 disable_single_change_sending = true;
829 int event_count = m_unsent_map_edit_queue.size();
831 // We'll log the amount of each
834 while (!m_unsent_map_edit_queue.empty()) {
835 MapEditEvent* event = m_unsent_map_edit_queue.front();
836 m_unsent_map_edit_queue.pop();
838 // Players far away from the change are stored here.
839 // Instead of sending the changes, MapBlocks are set not sent
841 std::vector<u16> far_players;
843 switch (event->type) {
846 prof.add("MEET_ADDNODE", 1);
847 sendAddNode(event->p, event->n, event->already_known_by_peer,
848 &far_players, disable_single_change_sending ? 5 : 30,
849 event->type == MEET_ADDNODE);
851 case MEET_REMOVENODE:
852 prof.add("MEET_REMOVENODE", 1);
853 sendRemoveNode(event->p, event->already_known_by_peer,
854 &far_players, disable_single_change_sending ? 5 : 30);
856 case MEET_BLOCK_NODE_METADATA_CHANGED:
857 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
858 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
859 setBlockNotSent(event->p);
862 infostream << "Server: MEET_OTHER" << std::endl;
863 prof.add("MEET_OTHER", 1);
864 for (const v3s16 &modified_block : event->modified_blocks) {
865 setBlockNotSent(modified_block);
869 prof.add("unknown", 1);
870 warningstream << "Server: Unknown MapEditEvent "
871 << ((u32)event->type) << std::endl;
876 Set blocks not sent to far players
878 if (!far_players.empty()) {
879 // Convert list format to that wanted by SetBlocksNotSent
880 std::map<v3s16, MapBlock*> modified_blocks2;
881 for (const v3s16 &modified_block : event->modified_blocks) {
882 modified_blocks2[modified_block] =
883 m_env->getMap().getBlockNoCreateNoEx(modified_block);
886 // Set blocks not sent
887 for (const u16 far_player : far_players) {
888 if (RemoteClient *client = getClient(far_player))
889 client->SetBlocksNotSent(modified_blocks2);
896 if (event_count >= 5) {
897 infostream << "Server: MapEditEvents:" << std::endl;
898 prof.print(infostream);
899 } else if (event_count != 0) {
900 verbosestream << "Server: MapEditEvents:" << std::endl;
901 prof.print(verbosestream);
907 Trigger emergethread (it somehow gets to a non-triggered but
908 bysy state sometimes)
911 float &counter = m_emergethread_trigger_timer;
913 if (counter >= 2.0) {
916 m_emerge->startThreads();
920 // Save map, players and auth stuff
922 float &counter = m_savemap_timer;
924 static thread_local const float save_interval =
925 g_settings->getFloat("server_map_save_interval");
926 if (counter >= save_interval) {
928 MutexAutoLock lock(m_env_mutex);
930 ScopeProfiler sp(g_profiler, "Server: saving stuff");
933 if (m_banmanager->isModified()) {
934 m_banmanager->save();
937 // Save changed parts of map
938 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
941 m_env->saveLoadedPlayers();
943 // Save environment metadata
949 static const float shutdown_msg_times[] =
951 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
954 if (m_shutdown_timer > 0.0f) {
955 // Automated messages
956 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
957 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
958 // If shutdown timer matches an automessage, shot it
959 if (m_shutdown_timer > shutdown_msg_times[i] &&
960 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
961 std::wstringstream ws;
963 ws << L"*** Server shutting down in "
964 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
967 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
968 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
974 m_shutdown_timer -= dtime;
975 if (m_shutdown_timer < 0.0f) {
976 m_shutdown_timer = 0.0f;
977 m_shutdown_requested = true;
982 void Server::Receive()
984 DSTACK(FUNCTION_NAME);
989 peer_id = pkt.getPeerId();
991 } catch (const con::InvalidIncomingDataException &e) {
992 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
993 << e.what() << std::endl;
994 } catch (const SerializationError &e) {
995 infostream << "Server::Receive(): SerializationError: what()="
996 << e.what() << std::endl;
997 } catch (const ClientStateError &e) {
998 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
999 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1000 L"Try reconnecting or updating your client");
1001 } catch (const con::PeerNotFoundException &e) {
1006 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1008 std::string playername;
1009 PlayerSAO *playersao = NULL;
1012 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1014 playername = client->getName();
1015 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1017 } catch (std::exception &e) {
1023 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1025 // If failed, cancel
1026 if (!playersao || !player) {
1027 if (player && player->peer_id != 0) {
1028 actionstream << "Server: Failed to emerge player \"" << playername
1029 << "\" (player allocated to an another client)" << std::endl;
1030 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1031 L"name. If your client closed unexpectedly, try again in "
1034 errorstream << "Server: " << playername << ": Failed to emerge player"
1036 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1042 Send complete position information
1044 SendMovePlayer(peer_id);
1047 SendPlayerPrivileges(peer_id);
1049 // Send inventory formspec
1050 SendPlayerInventoryFormspec(peer_id);
1053 SendInventory(playersao);
1055 // Send HP or death screen
1056 if (playersao->isDead())
1057 SendDeathscreen(peer_id, false, v3f(0,0,0));
1059 SendPlayerHPOrDie(playersao);
1062 SendPlayerBreath(playersao);
1064 // Note things in chat if not in simple singleplayer mode
1065 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1066 // Send information about server to player in chat
1067 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1069 Address addr = getPeerAddress(player->peer_id);
1070 std::string ip_str = addr.serializeString();
1071 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1076 const std::vector<std::string> &names = m_clients.getPlayerNames();
1078 actionstream << player->getName() << " joins game. List of players: ";
1080 for (const std::string &name : names) {
1081 actionstream << name << " ";
1084 actionstream << player->getName() <<std::endl;
1089 inline void Server::handleCommand(NetworkPacket* pkt)
1091 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1092 (this->*opHandle.handler)(pkt);
1095 void Server::ProcessData(NetworkPacket *pkt)
1097 DSTACK(FUNCTION_NAME);
1098 // Environment is locked first.
1099 MutexAutoLock envlock(m_env_mutex);
1101 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1102 u32 peer_id = pkt->getPeerId();
1105 Address address = getPeerAddress(peer_id);
1106 std::string addr_s = address.serializeString();
1108 if(m_banmanager->isIpBanned(addr_s)) {
1109 std::string ban_name = m_banmanager->getBanName(addr_s);
1110 infostream << "Server: A banned client tried to connect from "
1111 << addr_s << "; banned name was "
1112 << ban_name << std::endl;
1113 // This actually doesn't seem to transfer to the client
1114 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1115 + utf8_to_wide(ban_name));
1119 catch(con::PeerNotFoundException &e) {
1121 * no peer for this packet found
1122 * most common reason is peer timeout, e.g. peer didn't
1123 * respond for some time, your server was overloaded or
1126 infostream << "Server::ProcessData(): Canceling: peer "
1127 << peer_id << " not found" << std::endl;
1132 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1134 // Command must be handled into ToServerCommandHandler
1135 if (command >= TOSERVER_NUM_MSG_TYPES) {
1136 infostream << "Server: Ignoring unknown command "
1137 << command << std::endl;
1141 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1146 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1148 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1149 errorstream << "Server::ProcessData(): Cancelling: Peer"
1150 " serialization format invalid or not initialized."
1151 " Skipping incoming command=" << command << std::endl;
1155 /* Handle commands related to client startup */
1156 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1161 if (m_clients.getClientState(peer_id) < CS_Active) {
1162 if (command == TOSERVER_PLAYERPOS) return;
1164 errorstream << "Got packet command: " << command << " for peer id "
1165 << peer_id << " but client isn't active yet. Dropping packet "
1171 } catch (SendFailedException &e) {
1172 errorstream << "Server::ProcessData(): SendFailedException: "
1173 << "what=" << e.what()
1175 } catch (PacketError &e) {
1176 actionstream << "Server::ProcessData(): PacketError: "
1177 << "what=" << e.what()
1182 void Server::setTimeOfDay(u32 time)
1184 m_env->setTimeOfDay(time);
1185 m_time_of_day_send_timer = 0;
1188 void Server::onMapEditEvent(MapEditEvent *event)
1190 if(m_ignore_map_edit_events)
1192 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1194 MapEditEvent *e = event->clone();
1195 m_unsent_map_edit_queue.push(e);
1198 Inventory* Server::getInventory(const InventoryLocation &loc)
1201 case InventoryLocation::UNDEFINED:
1202 case InventoryLocation::CURRENT_PLAYER:
1204 case InventoryLocation::PLAYER:
1206 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1209 PlayerSAO *playersao = player->getPlayerSAO();
1212 return playersao->getInventory();
1215 case InventoryLocation::NODEMETA:
1217 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1220 return meta->getInventory();
1223 case InventoryLocation::DETACHED:
1225 if(m_detached_inventories.count(loc.name) == 0)
1227 return m_detached_inventories[loc.name];
1231 sanity_check(false); // abort
1236 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1239 case InventoryLocation::UNDEFINED:
1241 case InventoryLocation::PLAYER:
1246 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1251 PlayerSAO *playersao = player->getPlayerSAO();
1255 SendInventory(playersao);
1258 case InventoryLocation::NODEMETA:
1260 v3s16 blockpos = getNodeBlockPos(loc.p);
1262 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1264 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1266 setBlockNotSent(blockpos);
1269 case InventoryLocation::DETACHED:
1271 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1275 sanity_check(false); // abort
1280 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1282 std::vector<u16> clients = m_clients.getClientIDs();
1284 // Set the modified blocks unsent for all the clients
1285 for (const u16 client_id : clients) {
1286 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1287 client->SetBlocksNotSent(block);
1292 void Server::peerAdded(con::Peer *peer)
1294 DSTACK(FUNCTION_NAME);
1295 verbosestream<<"Server::peerAdded(): peer->id="
1296 <<peer->id<<std::endl;
1298 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1301 void Server::deletingPeer(con::Peer *peer, bool timeout)
1303 DSTACK(FUNCTION_NAME);
1304 verbosestream<<"Server::deletingPeer(): peer->id="
1305 <<peer->id<<", timeout="<<timeout<<std::endl;
1307 m_clients.event(peer->id, CSE_Disconnect);
1308 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1311 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1313 *retval = m_con.getPeerStat(peer_id,type);
1314 return *retval != -1;
1317 bool Server::getClientInfo(
1326 std::string* vers_string
1329 *state = m_clients.getClientState(peer_id);
1331 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1338 *uptime = client->uptime();
1339 *ser_vers = client->serialization_version;
1340 *prot_vers = client->net_proto_version;
1342 *major = client->getMajor();
1343 *minor = client->getMinor();
1344 *patch = client->getPatch();
1345 *vers_string = client->getPatch();
1352 void Server::handlePeerChanges()
1354 while(!m_peer_change_queue.empty())
1356 con::PeerChange c = m_peer_change_queue.front();
1357 m_peer_change_queue.pop();
1359 verbosestream<<"Server: Handling peer change: "
1360 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1365 case con::PEER_ADDED:
1366 m_clients.CreateClient(c.peer_id);
1369 case con::PEER_REMOVED:
1370 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1374 FATAL_ERROR("Invalid peer change event received!");
1380 void Server::printToConsoleOnly(const std::string &text)
1383 m_admin_chat->outgoing_queue.push_back(
1384 new ChatEventChat("", utf8_to_wide(text)));
1386 std::cout << text << std::endl;
1390 void Server::Send(NetworkPacket* pkt)
1392 m_clients.send(pkt->getPeerId(),
1393 clientCommandFactoryTable[pkt->getCommand()].channel,
1395 clientCommandFactoryTable[pkt->getCommand()].reliable);
1398 void Server::SendMovement(u16 peer_id)
1400 DSTACK(FUNCTION_NAME);
1401 std::ostringstream os(std::ios_base::binary);
1403 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1405 pkt << g_settings->getFloat("movement_acceleration_default");
1406 pkt << g_settings->getFloat("movement_acceleration_air");
1407 pkt << g_settings->getFloat("movement_acceleration_fast");
1408 pkt << g_settings->getFloat("movement_speed_walk");
1409 pkt << g_settings->getFloat("movement_speed_crouch");
1410 pkt << g_settings->getFloat("movement_speed_fast");
1411 pkt << g_settings->getFloat("movement_speed_climb");
1412 pkt << g_settings->getFloat("movement_speed_jump");
1413 pkt << g_settings->getFloat("movement_liquid_fluidity");
1414 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1415 pkt << g_settings->getFloat("movement_liquid_sink");
1416 pkt << g_settings->getFloat("movement_gravity");
1421 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1423 if (!g_settings->getBool("enable_damage"))
1426 u16 peer_id = playersao->getPeerID();
1427 bool is_alive = playersao->getHP() > 0;
1430 SendPlayerHP(peer_id);
1435 void Server::SendHP(u16 peer_id, u8 hp)
1437 DSTACK(FUNCTION_NAME);
1439 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1444 void Server::SendBreath(u16 peer_id, u16 breath)
1446 DSTACK(FUNCTION_NAME);
1448 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1449 pkt << (u16) breath;
1453 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1454 const std::string &custom_reason, bool reconnect)
1456 assert(reason < SERVER_ACCESSDENIED_MAX);
1458 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1460 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1461 pkt << custom_reason;
1462 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1463 reason == SERVER_ACCESSDENIED_CRASH)
1464 pkt << custom_reason << (u8)reconnect;
1468 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1470 DSTACK(FUNCTION_NAME);
1472 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1477 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1478 v3f camera_point_target)
1480 DSTACK(FUNCTION_NAME);
1482 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1483 pkt << set_camera_point_target << camera_point_target;
1487 void Server::SendItemDef(u16 peer_id,
1488 IItemDefManager *itemdef, u16 protocol_version)
1490 DSTACK(FUNCTION_NAME);
1492 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1496 u32 length of the next item
1497 zlib-compressed serialized ItemDefManager
1499 std::ostringstream tmp_os(std::ios::binary);
1500 itemdef->serialize(tmp_os, protocol_version);
1501 std::ostringstream tmp_os2(std::ios::binary);
1502 compressZlib(tmp_os.str(), tmp_os2);
1503 pkt.putLongString(tmp_os2.str());
1506 verbosestream << "Server: Sending item definitions to id(" << peer_id
1507 << "): size=" << pkt.getSize() << std::endl;
1512 void Server::SendNodeDef(u16 peer_id,
1513 INodeDefManager *nodedef, u16 protocol_version)
1515 DSTACK(FUNCTION_NAME);
1517 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1521 u32 length of the next item
1522 zlib-compressed serialized NodeDefManager
1524 std::ostringstream tmp_os(std::ios::binary);
1525 nodedef->serialize(tmp_os, protocol_version);
1526 std::ostringstream tmp_os2(std::ios::binary);
1527 compressZlib(tmp_os.str(), tmp_os2);
1529 pkt.putLongString(tmp_os2.str());
1532 verbosestream << "Server: Sending node definitions to id(" << peer_id
1533 << "): size=" << pkt.getSize() << std::endl;
1539 Non-static send methods
1542 void Server::SendInventory(PlayerSAO* playerSAO)
1544 DSTACK(FUNCTION_NAME);
1546 UpdateCrafting(playerSAO->getPlayer());
1552 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1554 std::ostringstream os;
1555 playerSAO->getInventory()->serialize(os);
1557 std::string s = os.str();
1559 pkt.putRawString(s.c_str(), s.size());
1563 void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
1565 DSTACK(FUNCTION_NAME);
1567 NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
1568 legacypkt << message.message;
1570 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1572 u8 type = message.type;
1573 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1575 if (peer_id != PEER_ID_INEXISTENT) {
1576 RemotePlayer *player = m_env->getPlayer(peer_id);
1580 if (player->protocol_version < 35)
1585 m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
1589 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1590 const std::string &formname)
1592 DSTACK(FUNCTION_NAME);
1594 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1595 if (formspec.empty()){
1596 //the client should close the formspec
1597 pkt.putLongString("");
1599 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1606 // Spawns a particle on peer with peer_id
1607 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1608 v3f pos, v3f velocity, v3f acceleration,
1609 float expirationtime, float size, bool collisiondetection,
1610 bool collision_removal,
1611 bool vertical, const std::string &texture,
1612 const struct TileAnimationParams &animation, u8 glow)
1614 DSTACK(FUNCTION_NAME);
1615 static thread_local const float radius =
1616 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1618 if (peer_id == PEER_ID_INEXISTENT) {
1619 std::vector<u16> clients = m_clients.getClientIDs();
1621 for (const u16 client_id : clients) {
1622 RemotePlayer *player = m_env->getPlayer(client_id);
1626 PlayerSAO *sao = player->getPlayerSAO();
1630 // Do not send to distant clients
1631 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1634 SendSpawnParticle(client_id, player->protocol_version,
1635 pos, velocity, acceleration,
1636 expirationtime, size, collisiondetection,
1637 collision_removal, vertical, texture, animation, glow);
1642 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1644 pkt << pos << velocity << acceleration << expirationtime
1645 << size << collisiondetection;
1646 pkt.putLongString(texture);
1648 pkt << collision_removal;
1649 // This is horrible but required (why are there two ways to serialize pkts?)
1650 std::ostringstream os(std::ios_base::binary);
1651 animation.serialize(os, protocol_version);
1652 pkt.putRawString(os.str());
1658 // Adds a ParticleSpawner on peer with peer_id
1659 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1660 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1661 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1662 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1663 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1664 const struct TileAnimationParams &animation, u8 glow)
1666 DSTACK(FUNCTION_NAME);
1667 if (peer_id == PEER_ID_INEXISTENT) {
1668 // This sucks and should be replaced:
1669 std::vector<u16> clients = m_clients.getClientIDs();
1670 for (const u16 client_id : clients) {
1671 RemotePlayer *player = m_env->getPlayer(client_id);
1674 SendAddParticleSpawner(client_id, player->protocol_version,
1675 amount, spawntime, minpos, maxpos,
1676 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1677 minsize, maxsize, collisiondetection, collision_removal,
1678 attached_id, vertical, texture, id, animation, glow);
1683 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1685 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1686 << minacc << maxacc << minexptime << maxexptime << minsize
1687 << maxsize << collisiondetection;
1689 pkt.putLongString(texture);
1691 pkt << id << vertical;
1692 pkt << collision_removal;
1694 // This is horrible but required
1695 std::ostringstream os(std::ios_base::binary);
1696 animation.serialize(os, protocol_version);
1697 pkt.putRawString(os.str());
1703 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1705 DSTACK(FUNCTION_NAME);
1707 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1709 // Ugly error in this packet
1712 if (peer_id != PEER_ID_INEXISTENT) {
1716 m_clients.sendToAll(&pkt);
1721 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1723 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1725 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1726 << form->text << form->number << form->item << form->dir
1727 << form->align << form->offset << form->world_pos << form->size;
1732 void Server::SendHUDRemove(u16 peer_id, u32 id)
1734 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1739 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1741 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1742 pkt << id << (u8) stat;
1746 case HUD_STAT_SCALE:
1747 case HUD_STAT_ALIGN:
1748 case HUD_STAT_OFFSET:
1749 pkt << *(v2f *) value;
1753 pkt << *(std::string *) value;
1755 case HUD_STAT_WORLD_POS:
1756 pkt << *(v3f *) value;
1759 pkt << *(v2s32 *) value;
1761 case HUD_STAT_NUMBER:
1765 pkt << *(u32 *) value;
1772 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1774 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1776 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1778 pkt << flags << mask;
1783 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1785 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1786 pkt << param << value;
1790 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1791 const std::string &type, const std::vector<std::string> ¶ms,
1794 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1795 pkt << bgcolor << type << (u16) params.size();
1797 for (const std::string ¶m : params)
1805 void Server::SendCloudParams(u16 peer_id, float density,
1806 const video::SColor &color_bright,
1807 const video::SColor &color_ambient,
1812 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1813 pkt << density << color_bright << color_ambient
1814 << height << thickness << speed;
1819 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1822 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1825 pkt << do_override << (u16) (ratio * 65535);
1830 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1832 DSTACK(FUNCTION_NAME);
1834 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1835 pkt << time << time_speed;
1837 if (peer_id == PEER_ID_INEXISTENT) {
1838 m_clients.sendToAll(&pkt);
1845 void Server::SendPlayerHP(u16 peer_id)
1847 DSTACK(FUNCTION_NAME);
1848 PlayerSAO *playersao = getPlayerSAO(peer_id);
1849 // In some rare case if the player is disconnected
1850 // while Lua call l_punch, for example, this can be NULL
1854 SendHP(peer_id, playersao->getHP());
1855 m_script->player_event(playersao,"health_changed");
1857 // Send to other clients
1858 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1859 ActiveObjectMessage aom(playersao->getId(), true, str);
1860 playersao->m_messages_out.push(aom);
1863 void Server::SendPlayerBreath(PlayerSAO *sao)
1865 DSTACK(FUNCTION_NAME);
1868 m_script->player_event(sao, "breath_changed");
1869 SendBreath(sao->getPeerID(), sao->getBreath());
1872 void Server::SendMovePlayer(u16 peer_id)
1874 DSTACK(FUNCTION_NAME);
1875 RemotePlayer *player = m_env->getPlayer(peer_id);
1877 PlayerSAO *sao = player->getPlayerSAO();
1880 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1881 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1884 v3f pos = sao->getBasePosition();
1885 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1886 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1887 << " pitch=" << sao->getPitch()
1888 << " yaw=" << sao->getYaw()
1895 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1897 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1900 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1901 << animation_frames[3] << animation_speed;
1906 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1908 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1909 pkt << first << third;
1912 void Server::SendPlayerPrivileges(u16 peer_id)
1914 RemotePlayer *player = m_env->getPlayer(peer_id);
1916 if(player->peer_id == PEER_ID_INEXISTENT)
1919 std::set<std::string> privs;
1920 m_script->getAuth(player->getName(), NULL, &privs);
1922 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1923 pkt << (u16) privs.size();
1925 for (const std::string &priv : privs) {
1932 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1934 RemotePlayer *player = m_env->getPlayer(peer_id);
1936 if(player->peer_id == PEER_ID_INEXISTENT)
1939 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1940 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1944 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1946 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1947 pkt.putRawString(datas.c_str(), datas.size());
1949 return pkt.getSize();
1952 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1954 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1955 datas.size(), peer_id);
1957 pkt.putRawString(datas.c_str(), datas.size());
1959 m_clients.send(pkt.getPeerId(),
1960 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1964 void Server::SendCSMFlavourLimits(u16 peer_id)
1966 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
1967 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
1968 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
1972 s32 Server::playSound(const SimpleSoundSpec &spec,
1973 const ServerSoundParams ¶ms)
1975 // Find out initial position of sound
1976 bool pos_exists = false;
1977 v3f pos = params.getPos(m_env, &pos_exists);
1978 // If position is not found while it should be, cancel sound
1979 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1982 // Filter destination clients
1983 std::vector<u16> dst_clients;
1984 if(!params.to_player.empty()) {
1985 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1987 infostream<<"Server::playSound: Player \""<<params.to_player
1988 <<"\" not found"<<std::endl;
1991 if(player->peer_id == PEER_ID_INEXISTENT){
1992 infostream<<"Server::playSound: Player \""<<params.to_player
1993 <<"\" not connected"<<std::endl;
1996 dst_clients.push_back(player->peer_id);
1998 std::vector<u16> clients = m_clients.getClientIDs();
2000 for (const u16 client_id : clients) {
2001 RemotePlayer *player = m_env->getPlayer(client_id);
2005 PlayerSAO *sao = player->getPlayerSAO();
2010 if(sao->getBasePosition().getDistanceFrom(pos) >
2011 params.max_hear_distance)
2014 dst_clients.push_back(client_id);
2018 if(dst_clients.empty())
2022 s32 id = m_next_sound_id++;
2023 // The sound will exist as a reference in m_playing_sounds
2024 m_playing_sounds[id] = ServerPlayingSound();
2025 ServerPlayingSound &psound = m_playing_sounds[id];
2026 psound.params = params;
2029 float gain = params.gain * spec.gain;
2030 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2031 pkt << id << spec.name << gain
2032 << (u8) params.type << pos << params.object
2033 << params.loop << params.fade << params.pitch;
2035 // Backwards compability
2036 bool play_sound = gain > 0;
2038 for (const u16 dst_client : dst_clients) {
2039 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2040 psound.clients.insert(dst_client);
2041 m_clients.send(dst_client, 0, &pkt, true);
2046 void Server::stopSound(s32 handle)
2048 // Get sound reference
2049 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2050 m_playing_sounds.find(handle);
2051 if (i == m_playing_sounds.end())
2053 ServerPlayingSound &psound = i->second;
2055 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2058 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2059 si != psound.clients.end(); ++si) {
2061 m_clients.send(*si, 0, &pkt, true);
2063 // Remove sound reference
2064 m_playing_sounds.erase(i);
2067 void Server::fadeSound(s32 handle, float step, float gain)
2069 // Get sound reference
2070 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2071 m_playing_sounds.find(handle);
2072 if (i == m_playing_sounds.end())
2075 ServerPlayingSound &psound = i->second;
2076 psound.params.gain = gain;
2078 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2079 pkt << handle << step << gain;
2081 // Backwards compability
2082 bool play_sound = gain > 0;
2083 ServerPlayingSound compat_psound = psound;
2084 compat_psound.clients.clear();
2086 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2087 compat_pkt << handle;
2089 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2090 it != psound.clients.end();) {
2091 if (m_clients.getProtocolVersion(*it) >= 32) {
2093 m_clients.send(*it, 0, &pkt, true);
2096 compat_psound.clients.insert(*it);
2098 m_clients.send(*it, 0, &compat_pkt, true);
2099 psound.clients.erase(it++);
2103 // Remove sound reference
2104 if (!play_sound || psound.clients.empty())
2105 m_playing_sounds.erase(i);
2107 if (play_sound && !compat_psound.clients.empty()) {
2108 // Play new sound volume on older clients
2109 playSound(compat_psound.spec, compat_psound.params);
2113 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2114 std::vector<u16> *far_players, float far_d_nodes)
2116 float maxd = far_d_nodes*BS;
2117 v3f p_f = intToFloat(p, BS);
2119 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2122 std::vector<u16> clients = m_clients.getClientIDs();
2123 for (u16 client_id : clients) {
2126 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2127 PlayerSAO *sao = player->getPlayerSAO();
2131 // If player is far away, only set modified blocks not sent
2132 v3f player_pos = sao->getBasePosition();
2133 if (player_pos.getDistanceFrom(p_f) > maxd) {
2134 far_players->push_back(client_id);
2141 m_clients.send(client_id, 0, &pkt, true);
2145 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2146 std::vector<u16> *far_players, float far_d_nodes,
2147 bool remove_metadata)
2149 float maxd = far_d_nodes*BS;
2150 v3f p_f = intToFloat(p, BS);
2152 std::vector<u16> clients = m_clients.getClientIDs();
2153 for (const u16 client_id : clients) {
2156 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2157 PlayerSAO *sao = player->getPlayerSAO();
2161 // If player is far away, only set modified blocks not sent
2162 v3f player_pos = sao->getBasePosition();
2163 if(player_pos.getDistanceFrom(p_f) > maxd) {
2164 far_players->push_back(client_id);
2170 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2172 RemoteClient* client = m_clients.lockedGetClientNoEx(client_id);
2174 pkt << p << n.param0 << n.param1 << n.param2
2175 << (u8) (remove_metadata ? 0 : 1);
2180 if (pkt.getSize() > 0)
2181 m_clients.send(client_id, 0, &pkt, true);
2185 void Server::setBlockNotSent(v3s16 p)
2187 std::vector<u16> clients = m_clients.getClientIDs();
2189 for (const u16 i : clients) {
2190 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2191 client->SetBlockNotSent(p);
2196 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2198 DSTACK(FUNCTION_NAME);
2200 v3s16 p = block->getPos();
2203 Create a packet with the block in the right format
2206 std::ostringstream os(std::ios_base::binary);
2207 block->serialize(os, ver, false);
2208 block->serializeNetworkSpecific(os);
2209 std::string s = os.str();
2211 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2214 pkt.putRawString(s.c_str(), s.size());
2218 void Server::SendBlocks(float dtime)
2220 DSTACK(FUNCTION_NAME);
2222 MutexAutoLock envlock(m_env_mutex);
2223 //TODO check if one big lock could be faster then multiple small ones
2225 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2227 std::vector<PrioritySortedBlockTransfer> queue;
2229 s32 total_sending = 0;
2232 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2234 std::vector<u16> clients = m_clients.getClientIDs();
2237 for (const u16 client_id : clients) {
2238 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2243 total_sending += client->SendingCount();
2244 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2250 // Lowest priority number comes first.
2251 // Lowest is most important.
2252 std::sort(queue.begin(), queue.end());
2255 s32 max_blocks_to_send =
2256 g_settings->getS32("max_simultaneous_block_sends_server_total");
2258 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2259 //TODO: Calculate limit dynamically
2260 if (total_sending >= max_blocks_to_send)
2263 MapBlock *block = nullptr;
2265 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2266 } catch (const InvalidPositionException &e) {
2270 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2275 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2276 client->net_proto_version);
2278 client->SentBlock(block_to_send.pos);
2284 void Server::fillMediaCache()
2286 DSTACK(FUNCTION_NAME);
2288 infostream<<"Server: Calculating media file checksums"<<std::endl;
2290 // Collect all media file paths
2291 std::vector<std::string> paths;
2292 for (const ModSpec &mod : m_mods) {
2293 paths.push_back(mod.path + DIR_DELIM + "textures");
2294 paths.push_back(mod.path + DIR_DELIM + "sounds");
2295 paths.push_back(mod.path + DIR_DELIM + "media");
2296 paths.push_back(mod.path + DIR_DELIM + "models");
2298 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2300 // Collect media file information from paths into cache
2301 for(std::vector<std::string>::iterator i = paths.begin();
2302 i != paths.end(); ++i) {
2303 std::string mediapath = *i;
2304 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2305 for (u32 j = 0; j < dirlist.size(); j++) {
2306 if (dirlist[j].dir) // Ignode dirs
2308 std::string filename = dirlist[j].name;
2309 // If name contains illegal characters, ignore the file
2310 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2311 infostream<<"Server: ignoring illegal file name: \""
2312 << filename << "\"" << std::endl;
2315 // If name is not in a supported format, ignore it
2316 const char *supported_ext[] = {
2317 ".png", ".jpg", ".bmp", ".tga",
2318 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2320 ".x", ".b3d", ".md2", ".obj",
2323 if (removeStringEnd(filename, supported_ext).empty()){
2324 infostream << "Server: ignoring unsupported file extension: \""
2325 << filename << "\"" << std::endl;
2328 // Ok, attempt to load the file and add to cache
2329 std::string filepath = mediapath + DIR_DELIM + filename;
2331 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2333 errorstream << "Server::fillMediaCache(): Could not open \""
2334 << filename << "\" for reading" << std::endl;
2337 std::ostringstream tmp_os(std::ios_base::binary);
2341 fis.read(buf, 1024);
2342 std::streamsize len = fis.gcount();
2343 tmp_os.write(buf, len);
2352 errorstream<<"Server::fillMediaCache(): Failed to read \""
2353 << filename << "\"" << std::endl;
2356 if(tmp_os.str().length() == 0) {
2357 errorstream << "Server::fillMediaCache(): Empty file \""
2358 << filepath << "\"" << std::endl;
2363 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2365 unsigned char *digest = sha1.getDigest();
2366 std::string sha1_base64 = base64_encode(digest, 20);
2367 std::string sha1_hex = hex_encode((char*)digest, 20);
2371 m_media[filename] = MediaInfo(filepath, sha1_base64);
2372 verbosestream << "Server: " << sha1_hex << " is " << filename
2378 void Server::sendMediaAnnouncement(u16 peer_id)
2380 DSTACK(FUNCTION_NAME);
2382 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2386 std::ostringstream os(std::ios_base::binary);
2388 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2389 pkt << (u16) m_media.size();
2391 for (const auto &i : m_media) {
2392 pkt << i.first << i.second.sha1_digest;
2395 pkt << g_settings->get("remote_media");
2399 struct SendableMedia
2405 SendableMedia(const std::string &name_="", const std::string &path_="",
2406 const std::string &data_=""):
2413 void Server::sendRequestedMedia(u16 peer_id,
2414 const std::vector<std::string> &tosend)
2416 DSTACK(FUNCTION_NAME);
2418 verbosestream<<"Server::sendRequestedMedia(): "
2419 <<"Sending files to client"<<std::endl;
2423 // Put 5kB in one bunch (this is not accurate)
2424 u32 bytes_per_bunch = 5000;
2426 std::vector< std::vector<SendableMedia> > file_bunches;
2427 file_bunches.emplace_back();
2429 u32 file_size_bunch_total = 0;
2431 for (const std::string &name : tosend) {
2432 if (m_media.find(name) == m_media.end()) {
2433 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2434 <<"unknown file \""<<(name)<<"\""<<std::endl;
2438 //TODO get path + name
2439 std::string tpath = m_media[name].path;
2442 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2444 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2445 <<tpath<<"\" for reading"<<std::endl;
2448 std::ostringstream tmp_os(std::ios_base::binary);
2452 fis.read(buf, 1024);
2453 std::streamsize len = fis.gcount();
2454 tmp_os.write(buf, len);
2455 file_size_bunch_total += len;
2464 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2465 <<name<<"\""<<std::endl;
2468 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2469 <<tname<<"\""<<std::endl;*/
2471 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2473 // Start next bunch if got enough data
2474 if(file_size_bunch_total >= bytes_per_bunch) {
2475 file_bunches.emplace_back();
2476 file_size_bunch_total = 0;
2481 /* Create and send packets */
2483 u16 num_bunches = file_bunches.size();
2484 for (u16 i = 0; i < num_bunches; i++) {
2487 u16 total number of texture bunches
2488 u16 index of this bunch
2489 u32 number of files in this bunch
2498 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2499 pkt << num_bunches << i << (u32) file_bunches[i].size();
2501 for (const SendableMedia &j : file_bunches[i]) {
2503 pkt.putLongString(j.data);
2506 verbosestream << "Server::sendRequestedMedia(): bunch "
2507 << i << "/" << num_bunches
2508 << " files=" << file_bunches[i].size()
2509 << " size=" << pkt.getSize() << std::endl;
2514 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2516 if(m_detached_inventories.count(name) == 0) {
2517 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2520 Inventory *inv = m_detached_inventories[name];
2521 std::ostringstream os(std::ios_base::binary);
2523 os << serializeString(name);
2527 std::string s = os.str();
2529 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2530 pkt.putRawString(s.c_str(), s.size());
2532 const std::string &check = m_detached_inventories_player[name];
2533 if (peer_id == PEER_ID_INEXISTENT) {
2535 return m_clients.sendToAll(&pkt);
2536 RemotePlayer *p = m_env->getPlayer(check.c_str());
2538 m_clients.send(p->peer_id, 0, &pkt, true);
2540 if (check.empty() || getPlayerName(peer_id) == check)
2545 void Server::sendDetachedInventories(u16 peer_id)
2547 DSTACK(FUNCTION_NAME);
2549 for (const auto &detached_inventory : m_detached_inventories) {
2550 const std::string &name = detached_inventory.first;
2551 //Inventory *inv = i->second;
2552 sendDetachedInventory(name, peer_id);
2560 void Server::DiePlayer(u16 peer_id)
2562 DSTACK(FUNCTION_NAME);
2563 PlayerSAO *playersao = getPlayerSAO(peer_id);
2564 // In some rare cases this can be NULL -- if the player is disconnected
2565 // when a Lua function modifies l_punch, for example
2569 infostream << "Server::DiePlayer(): Player "
2570 << playersao->getPlayer()->getName()
2571 << " dies" << std::endl;
2573 playersao->setHP(0);
2575 // Trigger scripted stuff
2576 m_script->on_dieplayer(playersao);
2578 SendPlayerHP(peer_id);
2579 SendDeathscreen(peer_id, false, v3f(0,0,0));
2582 void Server::RespawnPlayer(u16 peer_id)
2584 DSTACK(FUNCTION_NAME);
2586 PlayerSAO *playersao = getPlayerSAO(peer_id);
2589 infostream << "Server::RespawnPlayer(): Player "
2590 << playersao->getPlayer()->getName()
2591 << " respawns" << std::endl;
2593 playersao->setHP(PLAYER_MAX_HP);
2594 playersao->setBreath(PLAYER_MAX_BREATH);
2596 bool repositioned = m_script->on_respawnplayer(playersao);
2597 if (!repositioned) {
2598 // setPos will send the new position to client
2599 playersao->setPos(findSpawnPos());
2602 SendPlayerHP(peer_id);
2606 void Server::DenySudoAccess(u16 peer_id)
2608 DSTACK(FUNCTION_NAME);
2610 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2615 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2616 const std::string &str_reason, bool reconnect)
2618 if (proto_ver >= 25) {
2619 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2621 std::wstring wreason = utf8_to_wide(
2622 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2623 accessDeniedStrings[(u8)reason]);
2624 SendAccessDenied_Legacy(peer_id, wreason);
2627 m_clients.event(peer_id, CSE_SetDenied);
2628 m_con.DisconnectPeer(peer_id);
2632 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2634 DSTACK(FUNCTION_NAME);
2636 SendAccessDenied(peer_id, reason, custom_reason);
2637 m_clients.event(peer_id, CSE_SetDenied);
2638 m_con.DisconnectPeer(peer_id);
2641 // 13/03/15: remove this function when protocol version 25 will become
2642 // the minimum version for MT users, maybe in 1 year
2643 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2645 DSTACK(FUNCTION_NAME);
2647 SendAccessDenied_Legacy(peer_id, reason);
2648 m_clients.event(peer_id, CSE_SetDenied);
2649 m_con.DisconnectPeer(peer_id);
2652 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2654 DSTACK(FUNCTION_NAME);
2657 RemoteClient* client = getClient(peer_id, CS_Invalid);
2659 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2661 // Right now, the auth mechs don't change between login and sudo mode.
2662 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2663 client->allowed_sudo_mechs = sudo_auth_mechs;
2665 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2666 << g_settings->getFloat("dedicated_server_step")
2670 m_clients.event(peer_id, CSE_AuthAccept);
2672 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2674 // We only support SRP right now
2675 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2677 resp_pkt << sudo_auth_mechs;
2679 m_clients.event(peer_id, CSE_SudoSuccess);
2683 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2685 DSTACK(FUNCTION_NAME);
2686 std::wstring message;
2689 Clear references to playing sounds
2691 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2692 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2693 ServerPlayingSound &psound = i->second;
2694 psound.clients.erase(peer_id);
2695 if (psound.clients.empty())
2696 m_playing_sounds.erase(i++);
2701 RemotePlayer *player = m_env->getPlayer(peer_id);
2703 /* Run scripts and remove from environment */
2705 PlayerSAO *playersao = player->getPlayerSAO();
2708 // inform connected clients
2709 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2710 // (u16) 1 + std::string represents a vector serialization representation
2711 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2712 m_clients.sendToAll(¬ice);
2714 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2716 playersao->disconnected();
2723 if (player && reason != CDR_DENY) {
2724 std::ostringstream os(std::ios_base::binary);
2725 std::vector<u16> clients = m_clients.getClientIDs();
2727 for (const u16 client_id : clients) {
2729 RemotePlayer *player = m_env->getPlayer(client_id);
2733 // Get name of player
2734 os << player->getName() << " ";
2737 std::string name = player->getName();
2738 actionstream << name << " "
2739 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2740 << " List of players: " << os.str() << std::endl;
2742 m_admin_chat->outgoing_queue.push_back(
2743 new ChatEventNick(CET_NICK_REMOVE, name));
2747 MutexAutoLock env_lock(m_env_mutex);
2748 m_clients.DeleteClient(peer_id);
2752 // Send leave chat message to all remaining clients
2753 if (!message.empty()) {
2754 SendChatMessage(PEER_ID_INEXISTENT,
2755 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2759 void Server::UpdateCrafting(RemotePlayer *player)
2761 DSTACK(FUNCTION_NAME);
2763 // Get a preview for crafting
2765 InventoryLocation loc;
2766 loc.setPlayer(player->getName());
2767 std::vector<ItemStack> output_replacements;
2768 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2769 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2770 (&player->inventory)->getList("craft"), loc);
2772 // Put the new preview in
2773 InventoryList *plist = player->inventory.getList("craftpreview");
2774 sanity_check(plist);
2775 sanity_check(plist->getSize() >= 1);
2776 plist->changeItem(0, preview);
2779 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2781 if (evt->type == CET_NICK_ADD) {
2782 // The terminal informed us of its nick choice
2783 m_admin_nick = ((ChatEventNick *)evt)->nick;
2784 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2785 errorstream << "You haven't set up an account." << std::endl
2786 << "Please log in using the client as '"
2787 << m_admin_nick << "' with a secure password." << std::endl
2788 << "Until then, you can't execute admin tasks via the console," << std::endl
2789 << "and everybody can claim the user account instead of you," << std::endl
2790 << "giving them full control over this server." << std::endl;
2793 assert(evt->type == CET_CHAT);
2794 handleAdminChat((ChatEventChat *)evt);
2798 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2799 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2801 // If something goes wrong, this player is to blame
2802 RollbackScopeActor rollback_scope(m_rollback,
2803 std::string("player:") + name);
2805 if (g_settings->getBool("strip_color_codes"))
2806 wmessage = unescape_enriched(wmessage);
2809 switch (player->canSendChatMessage()) {
2810 case RPLAYER_CHATRESULT_FLOODING: {
2811 std::wstringstream ws;
2812 ws << L"You cannot send more messages. You are limited to "
2813 << g_settings->getFloat("chat_message_limit_per_10sec")
2814 << L" messages per 10 seconds.";
2817 case RPLAYER_CHATRESULT_KICK:
2818 DenyAccess_Legacy(player->peer_id,
2819 L"You have been kicked due to message flooding.");
2821 case RPLAYER_CHATRESULT_OK:
2824 FATAL_ERROR("Unhandled chat filtering result found.");
2828 if (m_max_chatmessage_length > 0
2829 && wmessage.length() > m_max_chatmessage_length) {
2830 return L"Your message exceed the maximum chat message limit set on the server. "
2831 L"It was refused. Send a shorter message";
2834 // Run script hook, exit if script ate the chat message
2835 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2840 // Whether to send line to the player that sent the message, or to all players
2841 bool broadcast_line = true;
2843 if (check_shout_priv && !checkPriv(name, "shout")) {
2844 line += L"-!- You don't have permission to shout.";
2845 broadcast_line = false;
2854 Tell calling method to send the message to sender
2856 if (!broadcast_line)
2860 Send the message to others
2862 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2864 std::vector<u16> clients = m_clients.getClientIDs();
2867 Send the message back to the inital sender
2868 if they are using protocol version >= 29
2871 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2872 if (player && player->protocol_version >= 29)
2873 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2875 for (u16 cid : clients) {
2876 if (cid != peer_id_to_avoid_sending)
2877 SendChatMessage(cid, ChatMessage(line));
2882 void Server::handleAdminChat(const ChatEventChat *evt)
2884 std::string name = evt->nick;
2885 std::wstring wname = utf8_to_wide(name);
2886 std::wstring wmessage = evt->evt_msg;
2888 std::wstring answer = handleChat(name, wname, wmessage);
2890 // If asked to send answer to sender
2891 if (!answer.empty()) {
2892 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2896 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2898 RemoteClient *client = getClientNoEx(peer_id,state_min);
2900 throw ClientNotFoundException("Client not found");
2904 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2906 return m_clients.getClientNoEx(peer_id, state_min);
2909 std::string Server::getPlayerName(u16 peer_id)
2911 RemotePlayer *player = m_env->getPlayer(peer_id);
2913 return "[id="+itos(peer_id)+"]";
2914 return player->getName();
2917 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2919 RemotePlayer *player = m_env->getPlayer(peer_id);
2922 return player->getPlayerSAO();
2925 std::wstring Server::getStatusString()
2927 std::wostringstream os(std::ios_base::binary);
2930 os<<L"version="<<narrow_to_wide(g_version_string);
2932 os<<L", uptime="<<m_uptime.get();
2934 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2935 // Information about clients
2938 std::vector<u16> clients = m_clients.getClientIDs();
2939 for (u16 client_id : clients) {
2941 RemotePlayer *player = m_env->getPlayer(client_id);
2942 // Get name of player
2943 std::wstring name = L"unknown";
2945 name = narrow_to_wide(player->getName());
2946 // Add name to information string
2955 if (!((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
2956 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2958 if (!g_settings->get("motd").empty())
2959 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2963 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2965 std::set<std::string> privs;
2966 m_script->getAuth(name, NULL, &privs);
2970 bool Server::checkPriv(const std::string &name, const std::string &priv)
2972 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2973 return (privs.count(priv) != 0);
2976 void Server::reportPrivsModified(const std::string &name)
2979 std::vector<u16> clients = m_clients.getClientIDs();
2980 for (const u16 client_id : clients) {
2981 RemotePlayer *player = m_env->getPlayer(client_id);
2982 reportPrivsModified(player->getName());
2985 RemotePlayer *player = m_env->getPlayer(name.c_str());
2988 SendPlayerPrivileges(player->peer_id);
2989 PlayerSAO *sao = player->getPlayerSAO();
2992 sao->updatePrivileges(
2993 getPlayerEffectivePrivs(name),
2998 void Server::reportInventoryFormspecModified(const std::string &name)
3000 RemotePlayer *player = m_env->getPlayer(name.c_str());
3003 SendPlayerInventoryFormspec(player->peer_id);
3006 void Server::setIpBanned(const std::string &ip, const std::string &name)
3008 m_banmanager->add(ip, name);
3011 void Server::unsetIpBanned(const std::string &ip_or_name)
3013 m_banmanager->remove(ip_or_name);
3016 std::string Server::getBanDescription(const std::string &ip_or_name)
3018 return m_banmanager->getBanDescription(ip_or_name);
3021 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3023 // m_env will be NULL if the server is initializing
3027 if (m_admin_nick == name && !m_admin_nick.empty()) {
3028 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3031 RemotePlayer *player = m_env->getPlayer(name);
3036 if (player->peer_id == PEER_ID_INEXISTENT)
3039 SendChatMessage(player->peer_id, ChatMessage(msg));
3042 bool Server::showFormspec(const char *playername, const std::string &formspec,
3043 const std::string &formname)
3045 // m_env will be NULL if the server is initializing
3049 RemotePlayer *player = m_env->getPlayer(playername);
3053 SendShowFormspecMessage(player->peer_id, formspec, formname);
3057 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3062 u32 id = player->addHud(form);
3064 SendHUDAdd(player->peer_id, id, form);
3069 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3073 HudElement* todel = player->removeHud(id);
3080 SendHUDRemove(player->peer_id, id);
3084 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3089 SendHUDChange(player->peer_id, id, stat, data);
3093 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3098 SendHUDSetFlags(player->peer_id, flags, mask);
3099 player->hud_flags &= ~mask;
3100 player->hud_flags |= flags;
3102 PlayerSAO* playersao = player->getPlayerSAO();
3107 m_script->player_event(playersao, "hud_changed");
3111 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3116 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3119 player->setHotbarItemcount(hotbar_itemcount);
3120 std::ostringstream os(std::ios::binary);
3121 writeS32(os, hotbar_itemcount);
3122 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3126 s32 Server::hudGetHotbarItemcount(RemotePlayer *player) const
3128 return player->getHotbarItemcount();
3131 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3136 player->setHotbarImage(name);
3137 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3140 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3144 return player->getHotbarImage();
3147 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3152 player->setHotbarSelectedImage(name);
3153 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3156 const std::string& Server::hudGetHotbarSelectedImage(RemotePlayer *player) const
3158 return player->getHotbarSelectedImage();
3161 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3162 v2s32 animation_frames[4], f32 frame_speed)
3167 player->setLocalAnimations(animation_frames, frame_speed);
3168 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3172 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3177 player->eye_offset_first = first;
3178 player->eye_offset_third = third;
3179 SendEyeOffset(player->peer_id, first, third);
3183 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3184 const std::string &type, const std::vector<std::string> ¶ms,
3190 player->setSky(bgcolor, type, params, clouds);
3191 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3195 bool Server::setClouds(RemotePlayer *player, float density,
3196 const video::SColor &color_bright,
3197 const video::SColor &color_ambient,
3205 SendCloudParams(player->peer_id, density,
3206 color_bright, color_ambient, height,
3211 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3217 player->overrideDayNightRatio(do_override, ratio);
3218 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3222 void Server::notifyPlayers(const std::wstring &msg)
3224 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3227 void Server::spawnParticle(const std::string &playername, v3f pos,
3228 v3f velocity, v3f acceleration,
3229 float expirationtime, float size, bool
3230 collisiondetection, bool collision_removal,
3231 bool vertical, const std::string &texture,
3232 const struct TileAnimationParams &animation, u8 glow)
3234 // m_env will be NULL if the server is initializing
3238 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3239 if (!playername.empty()) {
3240 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3243 peer_id = player->peer_id;
3244 proto_ver = player->protocol_version;
3247 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3248 expirationtime, size, collisiondetection,
3249 collision_removal, vertical, texture, animation, glow);
3252 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3253 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3254 float minexptime, float maxexptime, float minsize, float maxsize,
3255 bool collisiondetection, bool collision_removal,
3256 ServerActiveObject *attached, bool vertical, const std::string &texture,
3257 const std::string &playername, const struct TileAnimationParams &animation,
3260 // m_env will be NULL if the server is initializing
3264 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3265 if (!playername.empty()) {
3266 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3269 peer_id = player->peer_id;
3270 proto_ver = player->protocol_version;
3273 u16 attached_id = attached ? attached->getId() : 0;
3276 if (attached_id == 0)
3277 id = m_env->addParticleSpawner(spawntime);
3279 id = m_env->addParticleSpawner(spawntime, attached_id);
3281 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3282 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3283 minexptime, maxexptime, minsize, maxsize,
3284 collisiondetection, collision_removal, attached_id, vertical,
3285 texture, id, animation, glow);
3290 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3292 // m_env will be NULL if the server is initializing
3294 throw ServerError("Can't delete particle spawners during initialisation!");
3296 u16 peer_id = PEER_ID_INEXISTENT;
3297 if (!playername.empty()) {
3298 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3301 peer_id = player->peer_id;
3304 m_env->deleteParticleSpawner(id);
3305 SendDeleteParticleSpawner(peer_id, id);
3308 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3310 if(m_detached_inventories.count(name) > 0){
3311 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3312 delete m_detached_inventories[name];
3314 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3316 Inventory *inv = new Inventory(m_itemdef);
3318 m_detached_inventories[name] = inv;
3319 m_detached_inventories_player[name] = player;
3320 //TODO find a better way to do this
3321 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3325 // actions: time-reversed list
3326 // Return value: success/failure
3327 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3328 std::list<std::string> *log)
3330 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3331 ServerMap *map = (ServerMap*)(&m_env->getMap());
3333 // Fail if no actions to handle
3334 if(actions.empty()){
3335 log->push_back("Nothing to do.");
3342 for (const RollbackAction &action : actions) {
3344 bool success = action.applyRevert(map, this, this);
3347 std::ostringstream os;
3348 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3349 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3351 log->push_back(os.str());
3353 std::ostringstream os;
3354 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3355 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3357 log->push_back(os.str());
3361 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3362 <<" failed"<<std::endl;
3364 // Call it done if less than half failed
3365 return num_failed <= num_tried/2;
3368 // IGameDef interface
3370 IItemDefManager *Server::getItemDefManager()
3375 INodeDefManager *Server::getNodeDefManager()
3380 ICraftDefManager *Server::getCraftDefManager()
3385 u16 Server::allocateUnknownNodeId(const std::string &name)
3387 return m_nodedef->allocateDummy(name);
3390 MtEventManager *Server::getEventManager()
3395 IWritableItemDefManager *Server::getWritableItemDefManager()
3400 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3405 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3410 const ModSpec *Server::getModSpec(const std::string &modname) const
3412 std::vector<ModSpec>::const_iterator it;
3413 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3414 const ModSpec &mod = *it;
3415 if (mod.name == modname)
3421 void Server::getModNames(std::vector<std::string> &modlist)
3423 std::vector<ModSpec>::iterator it;
3424 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3425 modlist.push_back(it->name);
3428 std::string Server::getBuiltinLuaPath()
3430 return porting::path_share + DIR_DELIM + "builtin";
3433 std::string Server::getModStoragePath() const
3435 return m_path_world + DIR_DELIM + "mod_storage";
3438 v3f Server::findSpawnPos()
3440 ServerMap &map = m_env->getServerMap();
3442 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3443 return nodeposf * BS;
3446 bool is_good = false;
3447 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3448 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3450 // Try to find a good place a few times
3451 for(s32 i = 0; i < 4000 && !is_good; i++) {
3452 s32 range = MYMIN(1 + i, range_max);
3453 // We're going to try to throw the player to this position
3454 v2s16 nodepos2d = v2s16(
3455 -range + (myrand() % (range * 2)),
3456 -range + (myrand() % (range * 2)));
3458 // Get spawn level at point
3459 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3460 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3461 // the mapgen to signify an unsuitable spawn position
3462 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3465 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3468 for (s32 i = 0; i < 10; i++) {
3469 v3s16 blockpos = getNodeBlockPos(nodepos);
3470 map.emergeBlock(blockpos, true);
3471 content_t c = map.getNodeNoEx(nodepos).getContent();
3472 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3474 if (air_count >= 2) {
3475 nodeposf = intToFloat(nodepos, BS);
3476 // Don't spawn the player outside map boundaries
3477 if (objectpos_over_limit(nodeposf))
3490 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3492 m_shutdown_timer = delay;
3493 m_shutdown_msg = msg;
3494 m_shutdown_ask_reconnect = reconnect;
3496 if (delay == 0.0f) {
3497 // No delay, shutdown immediately
3498 m_shutdown_requested = true;
3499 // only print to the infostream, a chat message saying
3500 // "Server Shutting Down" is sent when the server destructs.
3501 infostream << "*** Immediate Server shutdown requested." << std::endl;
3502 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3503 // Negative delay, cancel shutdown if requested
3504 m_shutdown_timer = 0.0f;
3505 m_shutdown_msg = "";
3506 m_shutdown_ask_reconnect = false;
3507 m_shutdown_requested = false;
3508 std::wstringstream ws;
3510 ws << L"*** Server shutdown canceled.";
3512 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3513 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3514 } else if (delay > 0.0f) {
3515 // Positive delay, tell the clients when the server will shut down
3516 std::wstringstream ws;
3518 ws << L"*** Server shutting down in "
3519 << duration_to_string(myround(m_shutdown_timer)).c_str()
3522 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3523 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3527 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3530 Try to get an existing player
3532 RemotePlayer *player = m_env->getPlayer(name);
3534 // If player is already connected, cancel
3535 if (player && player->peer_id != 0) {
3536 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3541 If player with the wanted peer_id already exists, cancel.
3543 if (m_env->getPlayer(peer_id)) {
3544 infostream<<"emergePlayer(): Player with wrong name but same"
3545 " peer_id already exists"<<std::endl;
3550 player = new RemotePlayer(name, idef());
3553 bool newplayer = false;
3556 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3558 // Complete init with server parts
3559 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3560 player->protocol_version = proto_version;
3564 m_script->on_newplayer(playersao);
3570 bool Server::registerModStorage(ModMetadata *storage)
3572 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3573 errorstream << "Unable to register same mod storage twice. Storage name: "
3574 << storage->getModName() << std::endl;
3578 m_mod_storages[storage->getModName()] = storage;
3582 void Server::unregisterModStorage(const std::string &name)
3584 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3585 if (it != m_mod_storages.end()) {
3586 // Save unconditionaly on unregistration
3587 it->second->save(getModStoragePath());
3588 m_mod_storages.erase(name);
3592 void dedicated_server_loop(Server &server, bool &kill)
3594 DSTACK(FUNCTION_NAME);
3596 verbosestream<<"dedicated_server_loop()"<<std::endl;
3598 IntervalLimiter m_profiler_interval;
3600 static thread_local const float steplen =
3601 g_settings->getFloat("dedicated_server_step");
3602 static thread_local const float profiler_print_interval =
3603 g_settings->getFloat("profiler_print_interval");
3606 // This is kind of a hack but can be done like this
3607 // because server.step() is very light
3609 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3610 sleep_ms((int)(steplen*1000.0));
3612 server.step(steplen);
3614 if (server.getShutdownRequested() || kill)
3620 if (profiler_print_interval != 0) {
3621 if(m_profiler_interval.step(steplen, profiler_print_interval))
3623 infostream<<"Profiler:"<<std::endl;
3624 g_profiler->print(infostream);
3625 g_profiler->clear();
3630 infostream << "Dedicated server quitting" << std::endl;
3632 if (g_settings->getBool("server_announce"))
3633 ServerList::sendAnnounce(ServerList::AA_DELETE,
3634 server.m_bind_addr.getPort());