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"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
53 #include "event_manager.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 "util/base64.h"
61 #include "util/sha1.h"
64 #include "chatmessage.h"
65 #include "chat_interface.h"
66 #include "remoteplayer.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public Thread
80 ServerThread(Server *server):
91 void *ServerThread::run()
93 DSTACK(FUNCTION_NAME);
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(); }
149 const std::string &path_world,
150 const SubgameSpec &gamespec,
151 bool simple_singleplayer_mode,
156 m_path_world(path_world),
157 m_gamespec(gamespec),
158 m_simple_singleplayer_mode(simple_singleplayer_mode),
159 m_dedicated(dedicated),
160 m_async_fatal_error(""),
161 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
166 m_itemdef(createItemDefManager()),
167 m_nodedef(createNodeDefManager()),
168 m_craftdef(createCraftDefManager()),
169 m_event(new EventManager()),
174 m_lag = g_settings->getFloat("dedicated_server_step");
176 if (path_world.empty())
177 throw ServerError("Supplied empty world path");
179 if(!gamespec.isValid())
180 throw ServerError("Supplied invalid gamespec");
182 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
183 if(m_simple_singleplayer_mode)
184 infostream<<" in simple singleplayer mode"<<std::endl;
186 infostream<<std::endl;
187 infostream<<"- world: "<<m_path_world<<std::endl;
188 infostream<<"- game: "<<m_gamespec.path<<std::endl;
190 // Create world if it doesn't exist
191 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
192 throw ServerError("Failed to initialize world");
194 // Create server thread
195 m_thread = new ServerThread(this);
197 // Create emerge manager
198 m_emerge = new EmergeManager(this);
200 // Create ban manager
201 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
202 m_banmanager = new BanManager(ban_path);
204 ServerModConfiguration modconf(m_path_world);
205 m_mods = modconf.getMods();
206 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
207 // complain about mods with unsatisfied dependencies
208 if (!modconf.isConsistent()) {
209 modconf.printUnsatisfiedModsError();
213 MutexAutoLock envlock(m_env_mutex);
215 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
216 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
218 // Initialize scripting
219 infostream<<"Server: Initializing Lua"<<std::endl;
221 m_script = new ServerScripting(this);
223 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
226 infostream << "Server: Loading mods: ";
227 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
228 i != m_mods.end(); ++i) {
229 infostream << (*i).name << " ";
231 infostream << std::endl;
232 // Load and run "mod" scripts
233 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
234 it != m_mods.end(); ++it) {
235 const ModSpec &mod = *it;
236 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
237 throw ModError("Error loading mod \"" + mod.name +
238 "\": Mod name does not follow naming conventions: "
239 "Only characters [a-z0-9_] are allowed.");
241 std::string script_path = mod.path + DIR_DELIM + "init.lua";
242 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
243 << script_path << "\"]" << std::endl;
244 m_script->loadMod(script_path, mod.name);
247 // Read Textures and calculate sha1 sums
250 // Apply item aliases in the node definition manager
251 m_nodedef->updateAliases(m_itemdef);
253 // Apply texture overrides from texturepack/override.txt
254 std::string texture_path = g_settings->get("texture_path");
255 if (!texture_path.empty() && fs::IsDir(texture_path))
256 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
258 m_nodedef->setNodeRegistrationStatus(true);
260 // Perform pending node name resolutions
261 m_nodedef->runNodeResolveCallbacks();
263 // unmap node names for connected nodeboxes
264 m_nodedef->mapNodeboxConnections();
266 // init the recipe hashes to speed up crafting
267 m_craftdef->initHashes(this);
269 // Initialize Environment
270 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
272 m_clients.setEnv(m_env);
274 if (!servermap->settings_mgr.makeMapgenParams())
275 FATAL_ERROR("Couldn't create any mapgen type");
277 // Initialize mapgens
278 m_emerge->initMapgens(servermap->getMapgenParams());
280 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
281 if (m_enable_rollback_recording) {
282 // Create rollback manager
283 m_rollback = new RollbackManager(m_path_world, this);
286 // Give environment reference to scripting api
287 m_script->initializeEnvironment(m_env);
289 // Register us to receive map edit events
290 servermap->addEventReceiver(this);
292 // If file exists, load environment metadata
293 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
294 infostream << "Server: Loading environment metadata" << std::endl;
297 m_env->loadDefaultMeta();
300 m_liquid_transform_every = g_settings->getFloat("liquid_update");
301 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
302 m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
303 m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
308 infostream<<"Server destructing"<<std::endl;
310 // Send shutdown message
311 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
312 L"*** Server shutting down"));
315 MutexAutoLock envlock(m_env_mutex);
317 // Execute script shutdown hooks
318 m_script->on_shutdown();
320 infostream << "Server: Saving players" << std::endl;
321 m_env->saveLoadedPlayers();
323 infostream << "Server: Kicking players" << std::endl;
324 std::string kick_msg;
325 bool reconnect = false;
326 if (getShutdownRequested()) {
327 reconnect = m_shutdown_ask_reconnect;
328 kick_msg = m_shutdown_msg;
330 if (kick_msg.empty()) {
331 kick_msg = g_settings->get("kick_msg_shutdown");
333 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
334 kick_msg, reconnect);
336 infostream << "Server: Saving environment metadata" << std::endl;
344 // stop all emerge threads before deleting players that may have
345 // requested blocks to be emerged
346 m_emerge->stopThreads();
348 // Delete things in the reverse order of creation
358 // Deinitialize scripting
359 infostream<<"Server: Deinitializing scripting"<<std::endl;
362 // Delete detached inventories
363 for (auto &detached_inventory : m_detached_inventories) {
364 delete detached_inventory.second;
368 void Server::start(Address bind_addr)
370 DSTACK(FUNCTION_NAME);
372 m_bind_addr = bind_addr;
374 infostream<<"Starting server on "
375 << bind_addr.serializeString() <<"..."<<std::endl;
377 // Stop thread if already running
380 // Initialize connection
381 m_con->SetTimeoutMs(30);
382 m_con->Serve(bind_addr);
387 // ASCII art for the win!
389 <<" .__ __ __ "<<std::endl
390 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
391 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
392 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
393 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
394 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
395 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
396 actionstream<<"Server for gameid=\""<<m_gamespec.id
397 <<"\" listening on "<<bind_addr.serializeString()<<":"
398 <<bind_addr.getPort() << "."<<std::endl;
403 DSTACK(FUNCTION_NAME);
405 infostream<<"Server: Stopping and waiting threads"<<std::endl;
407 // Stop threads (set run=false first so both start stopping)
409 //m_emergethread.setRun(false);
411 //m_emergethread.stop();
413 infostream<<"Server: Threads stopped"<<std::endl;
416 void Server::step(float dtime)
418 DSTACK(FUNCTION_NAME);
423 MutexAutoLock lock(m_step_dtime_mutex);
424 m_step_dtime += dtime;
426 // Throw if fatal error occurred in thread
427 std::string async_err = m_async_fatal_error.get();
428 if (!async_err.empty()) {
429 if (!m_simple_singleplayer_mode) {
430 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
431 g_settings->get("kick_msg_crash"),
432 g_settings->getBool("ask_reconnect_on_crash"));
434 throw ServerError("AsyncErr: " + async_err);
438 void Server::AsyncRunStep(bool initial_step)
440 DSTACK(FUNCTION_NAME);
442 g_profiler->add("Server::AsyncRunStep (num)", 1);
446 MutexAutoLock lock1(m_step_dtime_mutex);
447 dtime = m_step_dtime;
451 // Send blocks to clients
455 if((dtime < 0.001) && !initial_step)
458 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
460 //infostream<<"Server steps "<<dtime<<std::endl;
461 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
464 MutexAutoLock lock1(m_step_dtime_mutex);
465 m_step_dtime -= dtime;
472 m_uptime.set(m_uptime.get() + dtime);
478 Update time of day and overall game time
480 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
483 Send to clients at constant intervals
486 m_time_of_day_send_timer -= dtime;
487 if(m_time_of_day_send_timer < 0.0) {
488 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
489 u16 time = m_env->getTimeOfDay();
490 float time_speed = g_settings->getFloat("time_speed");
491 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
495 MutexAutoLock lock(m_env_mutex);
496 // Figure out and report maximum lag to environment
497 float max_lag = m_env->getMaxLagEstimate();
498 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
500 if(dtime > 0.1 && dtime > max_lag * 2.0)
501 infostream<<"Server: Maximum lag peaked to "<<dtime
505 m_env->reportMaxLagEstimate(max_lag);
507 ScopeProfiler sp(g_profiler, "SEnv step");
508 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
512 static const float map_timer_and_unload_dtime = 2.92;
513 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
515 MutexAutoLock lock(m_env_mutex);
516 // Run Map's timers and unload unused data
517 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
518 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
519 g_settings->getFloat("server_unload_unused_data_timeout"),
524 Listen to the admin chat, if available
527 if (!m_admin_chat->command_queue.empty()) {
528 MutexAutoLock lock(m_env_mutex);
529 while (!m_admin_chat->command_queue.empty()) {
530 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
531 handleChatInterfaceEvent(evt);
535 m_admin_chat->outgoing_queue.push_back(
536 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
543 /* Transform liquids */
544 m_liquid_transform_timer += dtime;
545 if(m_liquid_transform_timer >= m_liquid_transform_every)
547 m_liquid_transform_timer -= m_liquid_transform_every;
549 MutexAutoLock lock(m_env_mutex);
551 ScopeProfiler sp(g_profiler, "Server: liquid transform");
553 std::map<v3s16, MapBlock*> modified_blocks;
554 m_env->getMap().transformLiquids(modified_blocks, m_env);
557 Set the modified blocks unsent for all the clients
559 if(!modified_blocks.empty())
561 SetBlocksNotSent(modified_blocks);
564 m_clients.step(dtime);
566 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
568 // send masterserver announce
570 float &counter = m_masterserver_timer;
571 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
572 g_settings->getBool("server_announce")) {
573 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
574 ServerList::AA_START,
575 m_bind_addr.getPort(),
576 m_clients.getPlayerNames(),
578 m_env->getGameTime(),
581 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
591 Check added and deleted active objects
594 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
595 MutexAutoLock envlock(m_env_mutex);
598 const RemoteClientMap &clients = m_clients.getClientList();
599 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
601 // Radius inside which objects are active
602 static thread_local const s16 radius =
603 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
605 // Radius inside which players are active
606 static thread_local const bool is_transfer_limited =
607 g_settings->exists("unlimited_player_transfer_distance") &&
608 !g_settings->getBool("unlimited_player_transfer_distance");
609 static thread_local const s16 player_transfer_dist =
610 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
611 s16 player_radius = player_transfer_dist;
612 if (player_radius == 0 && is_transfer_limited)
613 player_radius = radius;
615 for (const auto &client_it : clients) {
616 RemoteClient *client = client_it.second;
618 // If definitions and textures have not been sent, don't
619 // send objects either
620 if (client->getState() < CS_DefinitionsSent)
623 RemotePlayer *player = m_env->getPlayer(client->peer_id);
625 // This can happen if the client timeouts somehow
629 PlayerSAO *playersao = player->getPlayerSAO();
633 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
634 if (my_radius <= 0) my_radius = radius;
635 //infostream << "Server: Active Radius " << my_radius << std::endl;
637 std::queue<u16> removed_objects;
638 std::queue<u16> added_objects;
639 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
640 client->m_known_objects, removed_objects);
641 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
642 client->m_known_objects, added_objects);
644 // Ignore if nothing happened
645 if (removed_objects.empty() && added_objects.empty()) {
649 std::string data_buffer;
653 // Handle removed objects
654 writeU16((u8*)buf, removed_objects.size());
655 data_buffer.append(buf, 2);
656 while (!removed_objects.empty()) {
658 u16 id = removed_objects.front();
659 ServerActiveObject* obj = m_env->getActiveObject(id);
661 // Add to data buffer for sending
662 writeU16((u8*)buf, id);
663 data_buffer.append(buf, 2);
665 // Remove from known objects
666 client->m_known_objects.erase(id);
668 if(obj && obj->m_known_by_count > 0)
669 obj->m_known_by_count--;
670 removed_objects.pop();
673 // Handle added objects
674 writeU16((u8*)buf, added_objects.size());
675 data_buffer.append(buf, 2);
676 while (!added_objects.empty()) {
678 u16 id = added_objects.front();
679 ServerActiveObject* obj = m_env->getActiveObject(id);
682 u8 type = ACTIVEOBJECT_TYPE_INVALID;
684 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
686 type = obj->getSendType();
688 // Add to data buffer for sending
689 writeU16((u8*)buf, id);
690 data_buffer.append(buf, 2);
691 writeU8((u8*)buf, type);
692 data_buffer.append(buf, 1);
695 data_buffer.append(serializeLongString(
696 obj->getClientInitializationData(client->net_proto_version)));
698 data_buffer.append(serializeLongString(""));
700 // Add to known objects
701 client->m_known_objects.insert(id);
704 obj->m_known_by_count++;
709 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
710 verbosestream << "Server: Sent object remove/add: "
711 << removed_objects.size() << " removed, "
712 << added_objects.size() << " added, "
713 << "packet size is " << pktSize << std::endl;
717 m_mod_storage_save_timer -= dtime;
718 if (m_mod_storage_save_timer <= 0.0f) {
719 infostream << "Saving registered mod storages." << std::endl;
720 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
721 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
722 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
723 if (it->second->isModified()) {
724 it->second->save(getModStoragePath());
734 MutexAutoLock envlock(m_env_mutex);
735 ScopeProfiler sp(g_profiler, "Server: sending object messages");
738 // Value = data sent by object
739 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
741 // Get active object messages from environment
743 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
747 std::vector<ActiveObjectMessage>* message_list = nullptr;
748 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
749 n = buffered_messages.find(aom.id);
750 if (n == buffered_messages.end()) {
751 message_list = new std::vector<ActiveObjectMessage>;
752 buffered_messages[aom.id] = message_list;
755 message_list = n->second;
757 message_list->push_back(aom);
761 const RemoteClientMap &clients = m_clients.getClientList();
762 // Route data to every client
763 for (const auto &client_it : clients) {
764 RemoteClient *client = client_it.second;
765 std::string reliable_data;
766 std::string unreliable_data;
767 // Go through all objects in message buffer
768 for (const auto &buffered_message : buffered_messages) {
769 // If object is not known by client, skip it
770 u16 id = buffered_message.first;
771 if (client->m_known_objects.find(id) == client->m_known_objects.end())
774 // Get message list of object
775 std::vector<ActiveObjectMessage>* list = buffered_message.second;
776 // Go through every message
777 for (const ActiveObjectMessage &aom : *list) {
778 // Compose the full new data with header
779 std::string new_data;
782 writeU16((u8*)&buf[0], aom.id);
783 new_data.append(buf, 2);
785 new_data += serializeString(aom.datastring);
786 // Add data to buffer
788 reliable_data += new_data;
790 unreliable_data += new_data;
794 reliable_data and unreliable_data are now ready.
797 if (!reliable_data.empty()) {
798 SendActiveObjectMessages(client->peer_id, reliable_data);
801 if (!unreliable_data.empty()) {
802 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
807 // Clear buffered_messages
808 for (auto &buffered_message : buffered_messages) {
809 delete buffered_message.second;
814 Send queued-for-sending map edit events.
817 // We will be accessing the environment
818 MutexAutoLock lock(m_env_mutex);
820 // Don't send too many at a time
823 // Single change sending is disabled if queue size is not small
824 bool disable_single_change_sending = false;
825 if(m_unsent_map_edit_queue.size() >= 4)
826 disable_single_change_sending = true;
828 int event_count = m_unsent_map_edit_queue.size();
830 // We'll log the amount of each
833 while (!m_unsent_map_edit_queue.empty()) {
834 MapEditEvent* event = m_unsent_map_edit_queue.front();
835 m_unsent_map_edit_queue.pop();
837 // Players far away from the change are stored here.
838 // Instead of sending the changes, MapBlocks are set not sent
840 std::vector<u16> far_players;
842 switch (event->type) {
845 prof.add("MEET_ADDNODE", 1);
846 sendAddNode(event->p, event->n, event->already_known_by_peer,
847 &far_players, disable_single_change_sending ? 5 : 30,
848 event->type == MEET_ADDNODE);
850 case MEET_REMOVENODE:
851 prof.add("MEET_REMOVENODE", 1);
852 sendRemoveNode(event->p, event->already_known_by_peer,
853 &far_players, disable_single_change_sending ? 5 : 30);
855 case MEET_BLOCK_NODE_METADATA_CHANGED:
856 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
857 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
858 setBlockNotSent(event->p);
861 infostream << "Server: MEET_OTHER" << std::endl;
862 prof.add("MEET_OTHER", 1);
863 for (const v3s16 &modified_block : event->modified_blocks) {
864 setBlockNotSent(modified_block);
868 prof.add("unknown", 1);
869 warningstream << "Server: Unknown MapEditEvent "
870 << ((u32)event->type) << std::endl;
875 Set blocks not sent to far players
877 if (!far_players.empty()) {
878 // Convert list format to that wanted by SetBlocksNotSent
879 std::map<v3s16, MapBlock*> modified_blocks2;
880 for (const v3s16 &modified_block : event->modified_blocks) {
881 modified_blocks2[modified_block] =
882 m_env->getMap().getBlockNoCreateNoEx(modified_block);
885 // Set blocks not sent
886 for (const u16 far_player : far_players) {
887 if (RemoteClient *client = getClient(far_player))
888 client->SetBlocksNotSent(modified_blocks2);
895 if (event_count >= 5) {
896 infostream << "Server: MapEditEvents:" << std::endl;
897 prof.print(infostream);
898 } else if (event_count != 0) {
899 verbosestream << "Server: MapEditEvents:" << std::endl;
900 prof.print(verbosestream);
906 Trigger emergethread (it somehow gets to a non-triggered but
907 bysy state sometimes)
910 float &counter = m_emergethread_trigger_timer;
912 if (counter >= 2.0) {
915 m_emerge->startThreads();
919 // Save map, players and auth stuff
921 float &counter = m_savemap_timer;
923 static thread_local const float save_interval =
924 g_settings->getFloat("server_map_save_interval");
925 if (counter >= save_interval) {
927 MutexAutoLock lock(m_env_mutex);
929 ScopeProfiler sp(g_profiler, "Server: saving stuff");
932 if (m_banmanager->isModified()) {
933 m_banmanager->save();
936 // Save changed parts of map
937 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
940 m_env->saveLoadedPlayers();
942 // Save environment metadata
948 static const float shutdown_msg_times[] =
950 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
953 if (m_shutdown_timer > 0.0f) {
954 // Automated messages
955 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
956 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
957 // If shutdown timer matches an automessage, shot it
958 if (m_shutdown_timer > shutdown_msg_times[i] &&
959 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
960 std::wstringstream ws;
962 ws << L"*** Server shutting down in "
963 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
966 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
967 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
973 m_shutdown_timer -= dtime;
974 if (m_shutdown_timer < 0.0f) {
975 m_shutdown_timer = 0.0f;
976 m_shutdown_requested = true;
981 void Server::Receive()
983 DSTACK(FUNCTION_NAME);
987 m_con->Receive(&pkt);
988 peer_id = pkt.getPeerId();
990 } catch (const con::InvalidIncomingDataException &e) {
991 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
992 << e.what() << std::endl;
993 } catch (const SerializationError &e) {
994 infostream << "Server::Receive(): SerializationError: what()="
995 << e.what() << std::endl;
996 } catch (const ClientStateError &e) {
997 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
998 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
999 L"Try reconnecting or updating your client");
1000 } catch (const con::PeerNotFoundException &e) {
1005 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1007 std::string playername;
1008 PlayerSAO *playersao = NULL;
1011 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1013 playername = client->getName();
1014 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1016 } catch (std::exception &e) {
1022 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1024 // If failed, cancel
1025 if (!playersao || !player) {
1026 if (player && player->peer_id != 0) {
1027 actionstream << "Server: Failed to emerge player \"" << playername
1028 << "\" (player allocated to an another client)" << std::endl;
1029 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1030 L"name. If your client closed unexpectedly, try again in "
1033 errorstream << "Server: " << playername << ": Failed to emerge player"
1035 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1041 Send complete position information
1043 SendMovePlayer(peer_id);
1046 SendPlayerPrivileges(peer_id);
1048 // Send inventory formspec
1049 SendPlayerInventoryFormspec(peer_id);
1052 SendInventory(playersao);
1054 // Send HP or death screen
1055 if (playersao->isDead())
1056 SendDeathscreen(peer_id, false, v3f(0,0,0));
1058 SendPlayerHPOrDie(playersao);
1061 SendPlayerBreath(playersao);
1063 // Note things in chat if not in simple singleplayer mode
1064 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1065 // Send information about server to player in chat
1066 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1068 Address addr = getPeerAddress(player->peer_id);
1069 std::string ip_str = addr.serializeString();
1070 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1075 const std::vector<std::string> &names = m_clients.getPlayerNames();
1077 actionstream << player->getName() << " joins game. List of players: ";
1079 for (const std::string &name : names) {
1080 actionstream << name << " ";
1083 actionstream << player->getName() <<std::endl;
1088 inline void Server::handleCommand(NetworkPacket* pkt)
1090 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1091 (this->*opHandle.handler)(pkt);
1094 void Server::ProcessData(NetworkPacket *pkt)
1096 DSTACK(FUNCTION_NAME);
1097 // Environment is locked first.
1098 MutexAutoLock envlock(m_env_mutex);
1100 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1101 u32 peer_id = pkt->getPeerId();
1104 Address address = getPeerAddress(peer_id);
1105 std::string addr_s = address.serializeString();
1107 if(m_banmanager->isIpBanned(addr_s)) {
1108 std::string ban_name = m_banmanager->getBanName(addr_s);
1109 infostream << "Server: A banned client tried to connect from "
1110 << addr_s << "; banned name was "
1111 << ban_name << std::endl;
1112 // This actually doesn't seem to transfer to the client
1113 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1114 + utf8_to_wide(ban_name));
1118 catch(con::PeerNotFoundException &e) {
1120 * no peer for this packet found
1121 * most common reason is peer timeout, e.g. peer didn't
1122 * respond for some time, your server was overloaded or
1125 infostream << "Server::ProcessData(): Canceling: peer "
1126 << peer_id << " not found" << std::endl;
1131 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1133 // Command must be handled into ToServerCommandHandler
1134 if (command >= TOSERVER_NUM_MSG_TYPES) {
1135 infostream << "Server: Ignoring unknown command "
1136 << command << std::endl;
1140 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1145 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1147 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1148 errorstream << "Server::ProcessData(): Cancelling: Peer"
1149 " serialization format invalid or not initialized."
1150 " Skipping incoming command=" << command << std::endl;
1154 /* Handle commands related to client startup */
1155 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1160 if (m_clients.getClientState(peer_id) < CS_Active) {
1161 if (command == TOSERVER_PLAYERPOS) return;
1163 errorstream << "Got packet command: " << command << " for peer id "
1164 << peer_id << " but client isn't active yet. Dropping packet "
1170 } catch (SendFailedException &e) {
1171 errorstream << "Server::ProcessData(): SendFailedException: "
1172 << "what=" << e.what()
1174 } catch (PacketError &e) {
1175 actionstream << "Server::ProcessData(): PacketError: "
1176 << "what=" << e.what()
1181 void Server::setTimeOfDay(u32 time)
1183 m_env->setTimeOfDay(time);
1184 m_time_of_day_send_timer = 0;
1187 void Server::onMapEditEvent(MapEditEvent *event)
1189 if(m_ignore_map_edit_events)
1191 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1193 MapEditEvent *e = event->clone();
1194 m_unsent_map_edit_queue.push(e);
1197 Inventory* Server::getInventory(const InventoryLocation &loc)
1200 case InventoryLocation::UNDEFINED:
1201 case InventoryLocation::CURRENT_PLAYER:
1203 case InventoryLocation::PLAYER:
1205 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1208 PlayerSAO *playersao = player->getPlayerSAO();
1211 return playersao->getInventory();
1214 case InventoryLocation::NODEMETA:
1216 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1219 return meta->getInventory();
1222 case InventoryLocation::DETACHED:
1224 if(m_detached_inventories.count(loc.name) == 0)
1226 return m_detached_inventories[loc.name];
1230 sanity_check(false); // abort
1235 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1238 case InventoryLocation::UNDEFINED:
1240 case InventoryLocation::PLAYER:
1245 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1250 PlayerSAO *playersao = player->getPlayerSAO();
1254 SendInventory(playersao);
1257 case InventoryLocation::NODEMETA:
1259 v3s16 blockpos = getNodeBlockPos(loc.p);
1261 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1263 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1265 setBlockNotSent(blockpos);
1268 case InventoryLocation::DETACHED:
1270 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1274 sanity_check(false); // abort
1279 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1281 std::vector<u16> clients = m_clients.getClientIDs();
1283 // Set the modified blocks unsent for all the clients
1284 for (const u16 client_id : clients) {
1285 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1286 client->SetBlocksNotSent(block);
1291 void Server::peerAdded(con::Peer *peer)
1293 DSTACK(FUNCTION_NAME);
1294 verbosestream<<"Server::peerAdded(): peer->id="
1295 <<peer->id<<std::endl;
1297 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1300 void Server::deletingPeer(con::Peer *peer, bool timeout)
1302 DSTACK(FUNCTION_NAME);
1303 verbosestream<<"Server::deletingPeer(): peer->id="
1304 <<peer->id<<", timeout="<<timeout<<std::endl;
1306 m_clients.event(peer->id, CSE_Disconnect);
1307 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1310 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1312 *retval = m_con->getPeerStat(peer_id,type);
1313 return *retval != -1;
1316 bool Server::getClientInfo(
1325 std::string* vers_string
1328 *state = m_clients.getClientState(peer_id);
1330 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1337 *uptime = client->uptime();
1338 *ser_vers = client->serialization_version;
1339 *prot_vers = client->net_proto_version;
1341 *major = client->getMajor();
1342 *minor = client->getMinor();
1343 *patch = client->getPatch();
1344 *vers_string = client->getPatch();
1351 void Server::handlePeerChanges()
1353 while(!m_peer_change_queue.empty())
1355 con::PeerChange c = m_peer_change_queue.front();
1356 m_peer_change_queue.pop();
1358 verbosestream<<"Server: Handling peer change: "
1359 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1364 case con::PEER_ADDED:
1365 m_clients.CreateClient(c.peer_id);
1368 case con::PEER_REMOVED:
1369 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1373 FATAL_ERROR("Invalid peer change event received!");
1379 void Server::printToConsoleOnly(const std::string &text)
1382 m_admin_chat->outgoing_queue.push_back(
1383 new ChatEventChat("", utf8_to_wide(text)));
1385 std::cout << text << std::endl;
1389 void Server::Send(NetworkPacket* pkt)
1391 m_clients.send(pkt->getPeerId(),
1392 clientCommandFactoryTable[pkt->getCommand()].channel,
1394 clientCommandFactoryTable[pkt->getCommand()].reliable);
1397 void Server::SendMovement(u16 peer_id)
1399 DSTACK(FUNCTION_NAME);
1400 std::ostringstream os(std::ios_base::binary);
1402 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1404 pkt << g_settings->getFloat("movement_acceleration_default");
1405 pkt << g_settings->getFloat("movement_acceleration_air");
1406 pkt << g_settings->getFloat("movement_acceleration_fast");
1407 pkt << g_settings->getFloat("movement_speed_walk");
1408 pkt << g_settings->getFloat("movement_speed_crouch");
1409 pkt << g_settings->getFloat("movement_speed_fast");
1410 pkt << g_settings->getFloat("movement_speed_climb");
1411 pkt << g_settings->getFloat("movement_speed_jump");
1412 pkt << g_settings->getFloat("movement_liquid_fluidity");
1413 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1414 pkt << g_settings->getFloat("movement_liquid_sink");
1415 pkt << g_settings->getFloat("movement_gravity");
1420 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1422 if (!g_settings->getBool("enable_damage"))
1425 u16 peer_id = playersao->getPeerID();
1426 bool is_alive = playersao->getHP() > 0;
1429 SendPlayerHP(peer_id);
1434 void Server::SendHP(u16 peer_id, u8 hp)
1436 DSTACK(FUNCTION_NAME);
1438 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1443 void Server::SendBreath(u16 peer_id, u16 breath)
1445 DSTACK(FUNCTION_NAME);
1447 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1448 pkt << (u16) breath;
1452 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1453 const std::string &custom_reason, bool reconnect)
1455 assert(reason < SERVER_ACCESSDENIED_MAX);
1457 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1459 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1460 pkt << custom_reason;
1461 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1462 reason == SERVER_ACCESSDENIED_CRASH)
1463 pkt << custom_reason << (u8)reconnect;
1467 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1469 DSTACK(FUNCTION_NAME);
1471 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1476 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1477 v3f camera_point_target)
1479 DSTACK(FUNCTION_NAME);
1481 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1482 pkt << set_camera_point_target << camera_point_target;
1486 void Server::SendItemDef(u16 peer_id,
1487 IItemDefManager *itemdef, u16 protocol_version)
1489 DSTACK(FUNCTION_NAME);
1491 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1495 u32 length of the next item
1496 zlib-compressed serialized ItemDefManager
1498 std::ostringstream tmp_os(std::ios::binary);
1499 itemdef->serialize(tmp_os, protocol_version);
1500 std::ostringstream tmp_os2(std::ios::binary);
1501 compressZlib(tmp_os.str(), tmp_os2);
1502 pkt.putLongString(tmp_os2.str());
1505 verbosestream << "Server: Sending item definitions to id(" << peer_id
1506 << "): size=" << pkt.getSize() << std::endl;
1511 void Server::SendNodeDef(u16 peer_id,
1512 INodeDefManager *nodedef, u16 protocol_version)
1514 DSTACK(FUNCTION_NAME);
1516 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1520 u32 length of the next item
1521 zlib-compressed serialized NodeDefManager
1523 std::ostringstream tmp_os(std::ios::binary);
1524 nodedef->serialize(tmp_os, protocol_version);
1525 std::ostringstream tmp_os2(std::ios::binary);
1526 compressZlib(tmp_os.str(), tmp_os2);
1528 pkt.putLongString(tmp_os2.str());
1531 verbosestream << "Server: Sending node definitions to id(" << peer_id
1532 << "): size=" << pkt.getSize() << std::endl;
1538 Non-static send methods
1541 void Server::SendInventory(PlayerSAO* playerSAO)
1543 DSTACK(FUNCTION_NAME);
1545 UpdateCrafting(playerSAO->getPlayer());
1551 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1553 std::ostringstream os;
1554 playerSAO->getInventory()->serialize(os);
1556 std::string s = os.str();
1558 pkt.putRawString(s.c_str(), s.size());
1562 void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
1564 DSTACK(FUNCTION_NAME);
1566 NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
1567 legacypkt << message.message;
1569 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1571 u8 type = message.type;
1572 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1574 if (peer_id != PEER_ID_INEXISTENT) {
1575 RemotePlayer *player = m_env->getPlayer(peer_id);
1579 if (player->protocol_version < 35)
1584 m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
1588 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1589 const std::string &formname)
1591 DSTACK(FUNCTION_NAME);
1593 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1594 if (formspec.empty()){
1595 //the client should close the formspec
1596 pkt.putLongString("");
1598 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1605 // Spawns a particle on peer with peer_id
1606 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1607 v3f pos, v3f velocity, v3f acceleration,
1608 float expirationtime, float size, bool collisiondetection,
1609 bool collision_removal,
1610 bool vertical, const std::string &texture,
1611 const struct TileAnimationParams &animation, u8 glow)
1613 DSTACK(FUNCTION_NAME);
1614 static thread_local const float radius =
1615 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1617 if (peer_id == PEER_ID_INEXISTENT) {
1618 std::vector<u16> clients = m_clients.getClientIDs();
1620 for (const u16 client_id : clients) {
1621 RemotePlayer *player = m_env->getPlayer(client_id);
1625 PlayerSAO *sao = player->getPlayerSAO();
1629 // Do not send to distant clients
1630 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1633 SendSpawnParticle(client_id, player->protocol_version,
1634 pos, velocity, acceleration,
1635 expirationtime, size, collisiondetection,
1636 collision_removal, vertical, texture, animation, glow);
1641 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1643 pkt << pos << velocity << acceleration << expirationtime
1644 << size << collisiondetection;
1645 pkt.putLongString(texture);
1647 pkt << collision_removal;
1648 // This is horrible but required (why are there two ways to serialize pkts?)
1649 std::ostringstream os(std::ios_base::binary);
1650 animation.serialize(os, protocol_version);
1651 pkt.putRawString(os.str());
1657 // Adds a ParticleSpawner on peer with peer_id
1658 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1659 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1660 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1661 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1662 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1663 const struct TileAnimationParams &animation, u8 glow)
1665 DSTACK(FUNCTION_NAME);
1666 if (peer_id == PEER_ID_INEXISTENT) {
1667 // This sucks and should be replaced:
1668 std::vector<u16> clients = m_clients.getClientIDs();
1669 for (const u16 client_id : clients) {
1670 RemotePlayer *player = m_env->getPlayer(client_id);
1673 SendAddParticleSpawner(client_id, player->protocol_version,
1674 amount, spawntime, minpos, maxpos,
1675 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1676 minsize, maxsize, collisiondetection, collision_removal,
1677 attached_id, vertical, texture, id, animation, glow);
1682 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1684 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1685 << minacc << maxacc << minexptime << maxexptime << minsize
1686 << maxsize << collisiondetection;
1688 pkt.putLongString(texture);
1690 pkt << id << vertical;
1691 pkt << collision_removal;
1693 // This is horrible but required
1694 std::ostringstream os(std::ios_base::binary);
1695 animation.serialize(os, protocol_version);
1696 pkt.putRawString(os.str());
1702 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1704 DSTACK(FUNCTION_NAME);
1706 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1708 // Ugly error in this packet
1711 if (peer_id != PEER_ID_INEXISTENT) {
1715 m_clients.sendToAll(&pkt);
1720 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1722 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1724 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1725 << form->text << form->number << form->item << form->dir
1726 << form->align << form->offset << form->world_pos << form->size;
1731 void Server::SendHUDRemove(u16 peer_id, u32 id)
1733 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1738 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1740 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1741 pkt << id << (u8) stat;
1745 case HUD_STAT_SCALE:
1746 case HUD_STAT_ALIGN:
1747 case HUD_STAT_OFFSET:
1748 pkt << *(v2f *) value;
1752 pkt << *(std::string *) value;
1754 case HUD_STAT_WORLD_POS:
1755 pkt << *(v3f *) value;
1758 pkt << *(v2s32 *) value;
1760 case HUD_STAT_NUMBER:
1764 pkt << *(u32 *) value;
1771 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1773 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1775 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1777 pkt << flags << mask;
1782 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1784 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1785 pkt << param << value;
1789 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1790 const std::string &type, const std::vector<std::string> ¶ms,
1793 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1794 pkt << bgcolor << type << (u16) params.size();
1796 for (const std::string ¶m : params)
1804 void Server::SendCloudParams(u16 peer_id, float density,
1805 const video::SColor &color_bright,
1806 const video::SColor &color_ambient,
1811 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1812 pkt << density << color_bright << color_ambient
1813 << height << thickness << speed;
1818 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1821 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1824 pkt << do_override << (u16) (ratio * 65535);
1829 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1831 DSTACK(FUNCTION_NAME);
1833 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1834 pkt << time << time_speed;
1836 if (peer_id == PEER_ID_INEXISTENT) {
1837 m_clients.sendToAll(&pkt);
1844 void Server::SendPlayerHP(u16 peer_id)
1846 DSTACK(FUNCTION_NAME);
1847 PlayerSAO *playersao = getPlayerSAO(peer_id);
1848 // In some rare case if the player is disconnected
1849 // while Lua call l_punch, for example, this can be NULL
1853 SendHP(peer_id, playersao->getHP());
1854 m_script->player_event(playersao,"health_changed");
1856 // Send to other clients
1857 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1858 ActiveObjectMessage aom(playersao->getId(), true, str);
1859 playersao->m_messages_out.push(aom);
1862 void Server::SendPlayerBreath(PlayerSAO *sao)
1864 DSTACK(FUNCTION_NAME);
1867 m_script->player_event(sao, "breath_changed");
1868 SendBreath(sao->getPeerID(), sao->getBreath());
1871 void Server::SendMovePlayer(u16 peer_id)
1873 DSTACK(FUNCTION_NAME);
1874 RemotePlayer *player = m_env->getPlayer(peer_id);
1876 PlayerSAO *sao = player->getPlayerSAO();
1879 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1880 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1883 v3f pos = sao->getBasePosition();
1884 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1885 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1886 << " pitch=" << sao->getPitch()
1887 << " yaw=" << sao->getYaw()
1894 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1896 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1899 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1900 << animation_frames[3] << animation_speed;
1905 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1907 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1908 pkt << first << third;
1911 void Server::SendPlayerPrivileges(u16 peer_id)
1913 RemotePlayer *player = m_env->getPlayer(peer_id);
1915 if(player->peer_id == PEER_ID_INEXISTENT)
1918 std::set<std::string> privs;
1919 m_script->getAuth(player->getName(), NULL, &privs);
1921 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1922 pkt << (u16) privs.size();
1924 for (const std::string &priv : privs) {
1931 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1933 RemotePlayer *player = m_env->getPlayer(peer_id);
1935 if(player->peer_id == PEER_ID_INEXISTENT)
1938 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1939 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1943 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1945 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1946 pkt.putRawString(datas.c_str(), datas.size());
1948 return pkt.getSize();
1951 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1953 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1954 datas.size(), peer_id);
1956 pkt.putRawString(datas.c_str(), datas.size());
1958 m_clients.send(pkt.getPeerId(),
1959 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1963 void Server::SendCSMFlavourLimits(u16 peer_id)
1965 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
1966 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
1967 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
1971 s32 Server::playSound(const SimpleSoundSpec &spec,
1972 const ServerSoundParams ¶ms)
1974 // Find out initial position of sound
1975 bool pos_exists = false;
1976 v3f pos = params.getPos(m_env, &pos_exists);
1977 // If position is not found while it should be, cancel sound
1978 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1981 // Filter destination clients
1982 std::vector<u16> dst_clients;
1983 if(!params.to_player.empty()) {
1984 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1986 infostream<<"Server::playSound: Player \""<<params.to_player
1987 <<"\" not found"<<std::endl;
1990 if(player->peer_id == PEER_ID_INEXISTENT){
1991 infostream<<"Server::playSound: Player \""<<params.to_player
1992 <<"\" not connected"<<std::endl;
1995 dst_clients.push_back(player->peer_id);
1997 std::vector<u16> clients = m_clients.getClientIDs();
1999 for (const u16 client_id : clients) {
2000 RemotePlayer *player = m_env->getPlayer(client_id);
2004 PlayerSAO *sao = player->getPlayerSAO();
2009 if(sao->getBasePosition().getDistanceFrom(pos) >
2010 params.max_hear_distance)
2013 dst_clients.push_back(client_id);
2017 if(dst_clients.empty())
2021 s32 id = m_next_sound_id++;
2022 // The sound will exist as a reference in m_playing_sounds
2023 m_playing_sounds[id] = ServerPlayingSound();
2024 ServerPlayingSound &psound = m_playing_sounds[id];
2025 psound.params = params;
2028 float gain = params.gain * spec.gain;
2029 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2030 pkt << id << spec.name << gain
2031 << (u8) params.type << pos << params.object
2032 << params.loop << params.fade << params.pitch;
2034 // Backwards compability
2035 bool play_sound = gain > 0;
2037 for (const u16 dst_client : dst_clients) {
2038 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2039 psound.clients.insert(dst_client);
2040 m_clients.send(dst_client, 0, &pkt, true);
2045 void Server::stopSound(s32 handle)
2047 // Get sound reference
2048 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2049 m_playing_sounds.find(handle);
2050 if (i == m_playing_sounds.end())
2052 ServerPlayingSound &psound = i->second;
2054 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2057 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2058 si != psound.clients.end(); ++si) {
2060 m_clients.send(*si, 0, &pkt, true);
2062 // Remove sound reference
2063 m_playing_sounds.erase(i);
2066 void Server::fadeSound(s32 handle, float step, float gain)
2068 // Get sound reference
2069 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2070 m_playing_sounds.find(handle);
2071 if (i == m_playing_sounds.end())
2074 ServerPlayingSound &psound = i->second;
2075 psound.params.gain = gain;
2077 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2078 pkt << handle << step << gain;
2080 // Backwards compability
2081 bool play_sound = gain > 0;
2082 ServerPlayingSound compat_psound = psound;
2083 compat_psound.clients.clear();
2085 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2086 compat_pkt << handle;
2088 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2089 it != psound.clients.end();) {
2090 if (m_clients.getProtocolVersion(*it) >= 32) {
2092 m_clients.send(*it, 0, &pkt, true);
2095 compat_psound.clients.insert(*it);
2097 m_clients.send(*it, 0, &compat_pkt, true);
2098 psound.clients.erase(it++);
2102 // Remove sound reference
2103 if (!play_sound || psound.clients.empty())
2104 m_playing_sounds.erase(i);
2106 if (play_sound && !compat_psound.clients.empty()) {
2107 // Play new sound volume on older clients
2108 playSound(compat_psound.spec, compat_psound.params);
2112 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2113 std::vector<u16> *far_players, float far_d_nodes)
2115 float maxd = far_d_nodes*BS;
2116 v3f p_f = intToFloat(p, BS);
2118 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2121 std::vector<u16> clients = m_clients.getClientIDs();
2122 for (u16 client_id : clients) {
2125 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2126 PlayerSAO *sao = player->getPlayerSAO();
2130 // If player is far away, only set modified blocks not sent
2131 v3f player_pos = sao->getBasePosition();
2132 if (player_pos.getDistanceFrom(p_f) > maxd) {
2133 far_players->push_back(client_id);
2140 m_clients.send(client_id, 0, &pkt, true);
2144 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2145 std::vector<u16> *far_players, float far_d_nodes,
2146 bool remove_metadata)
2148 float maxd = far_d_nodes*BS;
2149 v3f p_f = intToFloat(p, BS);
2151 std::vector<u16> clients = m_clients.getClientIDs();
2152 for (const u16 client_id : clients) {
2155 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2156 PlayerSAO *sao = player->getPlayerSAO();
2160 // If player is far away, only set modified blocks not sent
2161 v3f player_pos = sao->getBasePosition();
2162 if(player_pos.getDistanceFrom(p_f) > maxd) {
2163 far_players->push_back(client_id);
2169 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2171 RemoteClient* client = m_clients.lockedGetClientNoEx(client_id);
2173 pkt << p << n.param0 << n.param1 << n.param2
2174 << (u8) (remove_metadata ? 0 : 1);
2179 if (pkt.getSize() > 0)
2180 m_clients.send(client_id, 0, &pkt, true);
2184 void Server::setBlockNotSent(v3s16 p)
2186 std::vector<u16> clients = m_clients.getClientIDs();
2188 for (const u16 i : clients) {
2189 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2190 client->SetBlockNotSent(p);
2195 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2197 DSTACK(FUNCTION_NAME);
2199 v3s16 p = block->getPos();
2202 Create a packet with the block in the right format
2205 std::ostringstream os(std::ios_base::binary);
2206 block->serialize(os, ver, false);
2207 block->serializeNetworkSpecific(os);
2208 std::string s = os.str();
2210 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2213 pkt.putRawString(s.c_str(), s.size());
2217 void Server::SendBlocks(float dtime)
2219 DSTACK(FUNCTION_NAME);
2221 MutexAutoLock envlock(m_env_mutex);
2222 //TODO check if one big lock could be faster then multiple small ones
2224 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2226 std::vector<PrioritySortedBlockTransfer> queue;
2228 s32 total_sending = 0;
2231 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2233 std::vector<u16> clients = m_clients.getClientIDs();
2236 for (const u16 client_id : clients) {
2237 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2242 total_sending += client->SendingCount();
2243 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2249 // Lowest priority number comes first.
2250 // Lowest is most important.
2251 std::sort(queue.begin(), queue.end());
2254 s32 max_blocks_to_send =
2255 g_settings->getS32("max_simultaneous_block_sends_server_total");
2257 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2258 //TODO: Calculate limit dynamically
2259 if (total_sending >= max_blocks_to_send)
2262 MapBlock *block = nullptr;
2264 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2265 } catch (const InvalidPositionException &e) {
2269 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2274 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2275 client->net_proto_version);
2277 client->SentBlock(block_to_send.pos);
2283 void Server::fillMediaCache()
2285 DSTACK(FUNCTION_NAME);
2287 infostream<<"Server: Calculating media file checksums"<<std::endl;
2289 // Collect all media file paths
2290 std::vector<std::string> paths;
2291 for (const ModSpec &mod : m_mods) {
2292 paths.push_back(mod.path + DIR_DELIM + "textures");
2293 paths.push_back(mod.path + DIR_DELIM + "sounds");
2294 paths.push_back(mod.path + DIR_DELIM + "media");
2295 paths.push_back(mod.path + DIR_DELIM + "models");
2297 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2299 // Collect media file information from paths into cache
2300 for (const std::string &mediapath : paths) {
2301 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2302 for (const fs::DirListNode &dln : dirlist) {
2303 if (dln.dir) // Ignode dirs
2305 std::string filename = dln.name;
2306 // If name contains illegal characters, ignore the file
2307 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2308 infostream<<"Server: ignoring illegal file name: \""
2309 << filename << "\"" << std::endl;
2312 // If name is not in a supported format, ignore it
2313 const char *supported_ext[] = {
2314 ".png", ".jpg", ".bmp", ".tga",
2315 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2317 ".x", ".b3d", ".md2", ".obj",
2320 if (removeStringEnd(filename, supported_ext).empty()){
2321 infostream << "Server: ignoring unsupported file extension: \""
2322 << filename << "\"" << std::endl;
2325 // Ok, attempt to load the file and add to cache
2326 std::string filepath;
2327 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2330 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2332 errorstream << "Server::fillMediaCache(): Could not open \""
2333 << filename << "\" for reading" << std::endl;
2336 std::ostringstream tmp_os(std::ios_base::binary);
2340 fis.read(buf, 1024);
2341 std::streamsize len = fis.gcount();
2342 tmp_os.write(buf, len);
2351 errorstream<<"Server::fillMediaCache(): Failed to read \""
2352 << filename << "\"" << std::endl;
2355 if(tmp_os.str().length() == 0) {
2356 errorstream << "Server::fillMediaCache(): Empty file \""
2357 << filepath << "\"" << std::endl;
2362 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2364 unsigned char *digest = sha1.getDigest();
2365 std::string sha1_base64 = base64_encode(digest, 20);
2366 std::string sha1_hex = hex_encode((char*)digest, 20);
2370 m_media[filename] = MediaInfo(filepath, sha1_base64);
2371 verbosestream << "Server: " << sha1_hex << " is " << filename
2377 void Server::sendMediaAnnouncement(u16 peer_id)
2379 DSTACK(FUNCTION_NAME);
2381 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2385 std::ostringstream os(std::ios_base::binary);
2387 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2388 pkt << (u16) m_media.size();
2390 for (const auto &i : m_media) {
2391 pkt << i.first << i.second.sha1_digest;
2394 pkt << g_settings->get("remote_media");
2398 struct SendableMedia
2404 SendableMedia(const std::string &name_="", const std::string &path_="",
2405 const std::string &data_=""):
2412 void Server::sendRequestedMedia(u16 peer_id,
2413 const std::vector<std::string> &tosend)
2415 DSTACK(FUNCTION_NAME);
2417 verbosestream<<"Server::sendRequestedMedia(): "
2418 <<"Sending files to client"<<std::endl;
2422 // Put 5kB in one bunch (this is not accurate)
2423 u32 bytes_per_bunch = 5000;
2425 std::vector< std::vector<SendableMedia> > file_bunches;
2426 file_bunches.emplace_back();
2428 u32 file_size_bunch_total = 0;
2430 for (const std::string &name : tosend) {
2431 if (m_media.find(name) == m_media.end()) {
2432 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2433 <<"unknown file \""<<(name)<<"\""<<std::endl;
2437 //TODO get path + name
2438 std::string tpath = m_media[name].path;
2441 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2443 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2444 <<tpath<<"\" for reading"<<std::endl;
2447 std::ostringstream tmp_os(std::ios_base::binary);
2451 fis.read(buf, 1024);
2452 std::streamsize len = fis.gcount();
2453 tmp_os.write(buf, len);
2454 file_size_bunch_total += len;
2463 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2464 <<name<<"\""<<std::endl;
2467 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2468 <<tname<<"\""<<std::endl;*/
2470 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2472 // Start next bunch if got enough data
2473 if(file_size_bunch_total >= bytes_per_bunch) {
2474 file_bunches.emplace_back();
2475 file_size_bunch_total = 0;
2480 /* Create and send packets */
2482 u16 num_bunches = file_bunches.size();
2483 for (u16 i = 0; i < num_bunches; i++) {
2486 u16 total number of texture bunches
2487 u16 index of this bunch
2488 u32 number of files in this bunch
2497 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2498 pkt << num_bunches << i << (u32) file_bunches[i].size();
2500 for (const SendableMedia &j : file_bunches[i]) {
2502 pkt.putLongString(j.data);
2505 verbosestream << "Server::sendRequestedMedia(): bunch "
2506 << i << "/" << num_bunches
2507 << " files=" << file_bunches[i].size()
2508 << " size=" << pkt.getSize() << std::endl;
2513 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2515 if(m_detached_inventories.count(name) == 0) {
2516 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2519 Inventory *inv = m_detached_inventories[name];
2520 std::ostringstream os(std::ios_base::binary);
2522 os << serializeString(name);
2526 std::string s = os.str();
2528 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2529 pkt.putRawString(s.c_str(), s.size());
2531 const std::string &check = m_detached_inventories_player[name];
2532 if (peer_id == PEER_ID_INEXISTENT) {
2534 return m_clients.sendToAll(&pkt);
2535 RemotePlayer *p = m_env->getPlayer(check.c_str());
2537 m_clients.send(p->peer_id, 0, &pkt, true);
2539 if (check.empty() || getPlayerName(peer_id) == check)
2544 void Server::sendDetachedInventories(u16 peer_id)
2546 DSTACK(FUNCTION_NAME);
2548 for (const auto &detached_inventory : m_detached_inventories) {
2549 const std::string &name = detached_inventory.first;
2550 //Inventory *inv = i->second;
2551 sendDetachedInventory(name, peer_id);
2559 void Server::DiePlayer(u16 peer_id)
2561 DSTACK(FUNCTION_NAME);
2562 PlayerSAO *playersao = getPlayerSAO(peer_id);
2563 // In some rare cases this can be NULL -- if the player is disconnected
2564 // when a Lua function modifies l_punch, for example
2568 infostream << "Server::DiePlayer(): Player "
2569 << playersao->getPlayer()->getName()
2570 << " dies" << std::endl;
2572 playersao->setHP(0);
2574 // Trigger scripted stuff
2575 m_script->on_dieplayer(playersao);
2577 SendPlayerHP(peer_id);
2578 SendDeathscreen(peer_id, false, v3f(0,0,0));
2581 void Server::RespawnPlayer(u16 peer_id)
2583 DSTACK(FUNCTION_NAME);
2585 PlayerSAO *playersao = getPlayerSAO(peer_id);
2588 infostream << "Server::RespawnPlayer(): Player "
2589 << playersao->getPlayer()->getName()
2590 << " respawns" << std::endl;
2592 playersao->setHP(playersao->accessObjectProperties()->hp_max);
2593 playersao->setBreath(PLAYER_MAX_BREATH);
2595 bool repositioned = m_script->on_respawnplayer(playersao);
2596 if (!repositioned) {
2597 // setPos will send the new position to client
2598 playersao->setPos(findSpawnPos());
2601 SendPlayerHP(peer_id);
2605 void Server::DenySudoAccess(u16 peer_id)
2607 DSTACK(FUNCTION_NAME);
2609 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2614 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2615 const std::string &str_reason, bool reconnect)
2617 if (proto_ver >= 25) {
2618 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2620 std::wstring wreason = utf8_to_wide(
2621 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2622 accessDeniedStrings[(u8)reason]);
2623 SendAccessDenied_Legacy(peer_id, wreason);
2626 m_clients.event(peer_id, CSE_SetDenied);
2627 m_con->DisconnectPeer(peer_id);
2631 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2633 DSTACK(FUNCTION_NAME);
2635 SendAccessDenied(peer_id, reason, custom_reason);
2636 m_clients.event(peer_id, CSE_SetDenied);
2637 m_con->DisconnectPeer(peer_id);
2640 // 13/03/15: remove this function when protocol version 25 will become
2641 // the minimum version for MT users, maybe in 1 year
2642 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2644 DSTACK(FUNCTION_NAME);
2646 SendAccessDenied_Legacy(peer_id, reason);
2647 m_clients.event(peer_id, CSE_SetDenied);
2648 m_con->DisconnectPeer(peer_id);
2651 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2653 DSTACK(FUNCTION_NAME);
2656 RemoteClient* client = getClient(peer_id, CS_Invalid);
2658 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2660 // Right now, the auth mechs don't change between login and sudo mode.
2661 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2662 client->allowed_sudo_mechs = sudo_auth_mechs;
2664 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2665 << g_settings->getFloat("dedicated_server_step")
2669 m_clients.event(peer_id, CSE_AuthAccept);
2671 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2673 // We only support SRP right now
2674 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2676 resp_pkt << sudo_auth_mechs;
2678 m_clients.event(peer_id, CSE_SudoSuccess);
2682 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2684 DSTACK(FUNCTION_NAME);
2685 std::wstring message;
2688 Clear references to playing sounds
2690 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2691 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2692 ServerPlayingSound &psound = i->second;
2693 psound.clients.erase(peer_id);
2694 if (psound.clients.empty())
2695 m_playing_sounds.erase(i++);
2700 RemotePlayer *player = m_env->getPlayer(peer_id);
2702 /* Run scripts and remove from environment */
2704 PlayerSAO *playersao = player->getPlayerSAO();
2707 // inform connected clients
2708 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2709 // (u16) 1 + std::string represents a vector serialization representation
2710 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2711 m_clients.sendToAll(¬ice);
2713 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2715 playersao->disconnected();
2722 if (player && reason != CDR_DENY) {
2723 std::ostringstream os(std::ios_base::binary);
2724 std::vector<u16> clients = m_clients.getClientIDs();
2726 for (const u16 client_id : clients) {
2728 RemotePlayer *player = m_env->getPlayer(client_id);
2732 // Get name of player
2733 os << player->getName() << " ";
2736 std::string name = player->getName();
2737 actionstream << name << " "
2738 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2739 << " List of players: " << os.str() << std::endl;
2741 m_admin_chat->outgoing_queue.push_back(
2742 new ChatEventNick(CET_NICK_REMOVE, name));
2746 MutexAutoLock env_lock(m_env_mutex);
2747 m_clients.DeleteClient(peer_id);
2751 // Send leave chat message to all remaining clients
2752 if (!message.empty()) {
2753 SendChatMessage(PEER_ID_INEXISTENT,
2754 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2758 void Server::UpdateCrafting(RemotePlayer *player)
2760 DSTACK(FUNCTION_NAME);
2762 // Get a preview for crafting
2764 InventoryLocation loc;
2765 loc.setPlayer(player->getName());
2766 std::vector<ItemStack> output_replacements;
2767 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2768 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2769 (&player->inventory)->getList("craft"), loc);
2771 // Put the new preview in
2772 InventoryList *plist = player->inventory.getList("craftpreview");
2773 sanity_check(plist);
2774 sanity_check(plist->getSize() >= 1);
2775 plist->changeItem(0, preview);
2778 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2780 if (evt->type == CET_NICK_ADD) {
2781 // The terminal informed us of its nick choice
2782 m_admin_nick = ((ChatEventNick *)evt)->nick;
2783 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2784 errorstream << "You haven't set up an account." << std::endl
2785 << "Please log in using the client as '"
2786 << m_admin_nick << "' with a secure password." << std::endl
2787 << "Until then, you can't execute admin tasks via the console," << std::endl
2788 << "and everybody can claim the user account instead of you," << std::endl
2789 << "giving them full control over this server." << std::endl;
2792 assert(evt->type == CET_CHAT);
2793 handleAdminChat((ChatEventChat *)evt);
2797 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2798 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2800 // If something goes wrong, this player is to blame
2801 RollbackScopeActor rollback_scope(m_rollback,
2802 std::string("player:") + name);
2804 if (g_settings->getBool("strip_color_codes"))
2805 wmessage = unescape_enriched(wmessage);
2808 switch (player->canSendChatMessage()) {
2809 case RPLAYER_CHATRESULT_FLOODING: {
2810 std::wstringstream ws;
2811 ws << L"You cannot send more messages. You are limited to "
2812 << g_settings->getFloat("chat_message_limit_per_10sec")
2813 << L" messages per 10 seconds.";
2816 case RPLAYER_CHATRESULT_KICK:
2817 DenyAccess_Legacy(player->peer_id,
2818 L"You have been kicked due to message flooding.");
2820 case RPLAYER_CHATRESULT_OK:
2823 FATAL_ERROR("Unhandled chat filtering result found.");
2827 if (m_max_chatmessage_length > 0
2828 && wmessage.length() > m_max_chatmessage_length) {
2829 return L"Your message exceed the maximum chat message limit set on the server. "
2830 L"It was refused. Send a shorter message";
2833 // Run script hook, exit if script ate the chat message
2834 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2839 // Whether to send line to the player that sent the message, or to all players
2840 bool broadcast_line = true;
2842 if (check_shout_priv && !checkPriv(name, "shout")) {
2843 line += L"-!- You don't have permission to shout.";
2844 broadcast_line = false;
2853 Tell calling method to send the message to sender
2855 if (!broadcast_line)
2859 Send the message to others
2861 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2863 std::vector<u16> clients = m_clients.getClientIDs();
2866 Send the message back to the inital sender
2867 if they are using protocol version >= 29
2870 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2871 if (player && player->protocol_version >= 29)
2872 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2874 for (u16 cid : clients) {
2875 if (cid != peer_id_to_avoid_sending)
2876 SendChatMessage(cid, ChatMessage(line));
2881 void Server::handleAdminChat(const ChatEventChat *evt)
2883 std::string name = evt->nick;
2884 std::wstring wname = utf8_to_wide(name);
2885 std::wstring wmessage = evt->evt_msg;
2887 std::wstring answer = handleChat(name, wname, wmessage);
2889 // If asked to send answer to sender
2890 if (!answer.empty()) {
2891 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2895 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2897 RemoteClient *client = getClientNoEx(peer_id,state_min);
2899 throw ClientNotFoundException("Client not found");
2903 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2905 return m_clients.getClientNoEx(peer_id, state_min);
2908 std::string Server::getPlayerName(u16 peer_id)
2910 RemotePlayer *player = m_env->getPlayer(peer_id);
2912 return "[id="+itos(peer_id)+"]";
2913 return player->getName();
2916 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2918 RemotePlayer *player = m_env->getPlayer(peer_id);
2921 return player->getPlayerSAO();
2924 std::wstring Server::getStatusString()
2926 std::wostringstream os(std::ios_base::binary);
2929 os<<L"version="<<narrow_to_wide(g_version_string);
2931 os<<L", uptime="<<m_uptime.get();
2933 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2934 // Information about clients
2937 std::vector<u16> clients = m_clients.getClientIDs();
2938 for (u16 client_id : clients) {
2940 RemotePlayer *player = m_env->getPlayer(client_id);
2941 // Get name of player
2942 std::wstring name = L"unknown";
2944 name = narrow_to_wide(player->getName());
2945 // Add name to information string
2954 if (!((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
2955 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2957 if (!g_settings->get("motd").empty())
2958 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2962 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2964 std::set<std::string> privs;
2965 m_script->getAuth(name, NULL, &privs);
2969 bool Server::checkPriv(const std::string &name, const std::string &priv)
2971 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2972 return (privs.count(priv) != 0);
2975 void Server::reportPrivsModified(const std::string &name)
2978 std::vector<u16> clients = m_clients.getClientIDs();
2979 for (const u16 client_id : clients) {
2980 RemotePlayer *player = m_env->getPlayer(client_id);
2981 reportPrivsModified(player->getName());
2984 RemotePlayer *player = m_env->getPlayer(name.c_str());
2987 SendPlayerPrivileges(player->peer_id);
2988 PlayerSAO *sao = player->getPlayerSAO();
2991 sao->updatePrivileges(
2992 getPlayerEffectivePrivs(name),
2997 void Server::reportInventoryFormspecModified(const std::string &name)
2999 RemotePlayer *player = m_env->getPlayer(name.c_str());
3002 SendPlayerInventoryFormspec(player->peer_id);
3005 void Server::setIpBanned(const std::string &ip, const std::string &name)
3007 m_banmanager->add(ip, name);
3010 void Server::unsetIpBanned(const std::string &ip_or_name)
3012 m_banmanager->remove(ip_or_name);
3015 std::string Server::getBanDescription(const std::string &ip_or_name)
3017 return m_banmanager->getBanDescription(ip_or_name);
3020 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3022 // m_env will be NULL if the server is initializing
3026 if (m_admin_nick == name && !m_admin_nick.empty()) {
3027 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3030 RemotePlayer *player = m_env->getPlayer(name);
3035 if (player->peer_id == PEER_ID_INEXISTENT)
3038 SendChatMessage(player->peer_id, ChatMessage(msg));
3041 bool Server::showFormspec(const char *playername, const std::string &formspec,
3042 const std::string &formname)
3044 // m_env will be NULL if the server is initializing
3048 RemotePlayer *player = m_env->getPlayer(playername);
3052 SendShowFormspecMessage(player->peer_id, formspec, formname);
3056 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3061 u32 id = player->addHud(form);
3063 SendHUDAdd(player->peer_id, id, form);
3068 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3072 HudElement* todel = player->removeHud(id);
3079 SendHUDRemove(player->peer_id, id);
3083 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3088 SendHUDChange(player->peer_id, id, stat, data);
3092 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3097 SendHUDSetFlags(player->peer_id, flags, mask);
3098 player->hud_flags &= ~mask;
3099 player->hud_flags |= flags;
3101 PlayerSAO* playersao = player->getPlayerSAO();
3106 m_script->player_event(playersao, "hud_changed");
3110 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3115 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3118 player->setHotbarItemcount(hotbar_itemcount);
3119 std::ostringstream os(std::ios::binary);
3120 writeS32(os, hotbar_itemcount);
3121 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3125 s32 Server::hudGetHotbarItemcount(RemotePlayer *player) const
3127 return player->getHotbarItemcount();
3130 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3135 player->setHotbarImage(name);
3136 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3139 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3143 return player->getHotbarImage();
3146 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3151 player->setHotbarSelectedImage(name);
3152 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3155 const std::string& Server::hudGetHotbarSelectedImage(RemotePlayer *player) const
3157 return player->getHotbarSelectedImage();
3160 Address Server::getPeerAddress(u16 peer_id)
3162 return m_con->GetPeerAddress(peer_id);
3165 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3166 v2s32 animation_frames[4], f32 frame_speed)
3171 player->setLocalAnimations(animation_frames, frame_speed);
3172 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3176 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3181 player->eye_offset_first = first;
3182 player->eye_offset_third = third;
3183 SendEyeOffset(player->peer_id, first, third);
3187 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3188 const std::string &type, const std::vector<std::string> ¶ms,
3194 player->setSky(bgcolor, type, params, clouds);
3195 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3199 bool Server::setClouds(RemotePlayer *player, float density,
3200 const video::SColor &color_bright,
3201 const video::SColor &color_ambient,
3209 SendCloudParams(player->peer_id, density,
3210 color_bright, color_ambient, height,
3215 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3221 player->overrideDayNightRatio(do_override, ratio);
3222 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3226 void Server::notifyPlayers(const std::wstring &msg)
3228 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3231 void Server::spawnParticle(const std::string &playername, v3f pos,
3232 v3f velocity, v3f acceleration,
3233 float expirationtime, float size, bool
3234 collisiondetection, bool collision_removal,
3235 bool vertical, const std::string &texture,
3236 const struct TileAnimationParams &animation, u8 glow)
3238 // m_env will be NULL if the server is initializing
3242 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3243 if (!playername.empty()) {
3244 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3247 peer_id = player->peer_id;
3248 proto_ver = player->protocol_version;
3251 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3252 expirationtime, size, collisiondetection,
3253 collision_removal, vertical, texture, animation, glow);
3256 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3257 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3258 float minexptime, float maxexptime, float minsize, float maxsize,
3259 bool collisiondetection, bool collision_removal,
3260 ServerActiveObject *attached, bool vertical, const std::string &texture,
3261 const std::string &playername, const struct TileAnimationParams &animation,
3264 // m_env will be NULL if the server is initializing
3268 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3269 if (!playername.empty()) {
3270 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3273 peer_id = player->peer_id;
3274 proto_ver = player->protocol_version;
3277 u16 attached_id = attached ? attached->getId() : 0;
3280 if (attached_id == 0)
3281 id = m_env->addParticleSpawner(spawntime);
3283 id = m_env->addParticleSpawner(spawntime, attached_id);
3285 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3286 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3287 minexptime, maxexptime, minsize, maxsize,
3288 collisiondetection, collision_removal, attached_id, vertical,
3289 texture, id, animation, glow);
3294 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3296 // m_env will be NULL if the server is initializing
3298 throw ServerError("Can't delete particle spawners during initialisation!");
3300 u16 peer_id = PEER_ID_INEXISTENT;
3301 if (!playername.empty()) {
3302 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3305 peer_id = player->peer_id;
3308 m_env->deleteParticleSpawner(id);
3309 SendDeleteParticleSpawner(peer_id, id);
3312 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3314 if(m_detached_inventories.count(name) > 0){
3315 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3316 delete m_detached_inventories[name];
3318 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3320 Inventory *inv = new Inventory(m_itemdef);
3322 m_detached_inventories[name] = inv;
3323 m_detached_inventories_player[name] = player;
3324 //TODO find a better way to do this
3325 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3329 // actions: time-reversed list
3330 // Return value: success/failure
3331 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3332 std::list<std::string> *log)
3334 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3335 ServerMap *map = (ServerMap*)(&m_env->getMap());
3337 // Fail if no actions to handle
3338 if(actions.empty()){
3339 log->push_back("Nothing to do.");
3346 for (const RollbackAction &action : actions) {
3348 bool success = action.applyRevert(map, this, this);
3351 std::ostringstream os;
3352 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3353 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3355 log->push_back(os.str());
3357 std::ostringstream os;
3358 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3359 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3361 log->push_back(os.str());
3365 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3366 <<" failed"<<std::endl;
3368 // Call it done if less than half failed
3369 return num_failed <= num_tried/2;
3372 // IGameDef interface
3374 IItemDefManager *Server::getItemDefManager()
3379 INodeDefManager *Server::getNodeDefManager()
3384 ICraftDefManager *Server::getCraftDefManager()
3389 u16 Server::allocateUnknownNodeId(const std::string &name)
3391 return m_nodedef->allocateDummy(name);
3394 MtEventManager *Server::getEventManager()
3399 IWritableItemDefManager *Server::getWritableItemDefManager()
3404 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3409 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3414 const ModSpec *Server::getModSpec(const std::string &modname) const
3416 std::vector<ModSpec>::const_iterator it;
3417 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3418 const ModSpec &mod = *it;
3419 if (mod.name == modname)
3425 void Server::getModNames(std::vector<std::string> &modlist)
3427 std::vector<ModSpec>::iterator it;
3428 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3429 modlist.push_back(it->name);
3432 std::string Server::getBuiltinLuaPath()
3434 return porting::path_share + DIR_DELIM + "builtin";
3437 std::string Server::getModStoragePath() const
3439 return m_path_world + DIR_DELIM + "mod_storage";
3442 v3f Server::findSpawnPos()
3444 ServerMap &map = m_env->getServerMap();
3446 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3447 return nodeposf * BS;
3450 bool is_good = false;
3451 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3452 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3454 // Try to find a good place a few times
3455 for(s32 i = 0; i < 4000 && !is_good; i++) {
3456 s32 range = MYMIN(1 + i, range_max);
3457 // We're going to try to throw the player to this position
3458 v2s16 nodepos2d = v2s16(
3459 -range + (myrand() % (range * 2)),
3460 -range + (myrand() % (range * 2)));
3462 // Get spawn level at point
3463 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3464 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3465 // the mapgen to signify an unsuitable spawn position
3466 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3469 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3472 for (s32 i = 0; i < 10; i++) {
3473 v3s16 blockpos = getNodeBlockPos(nodepos);
3474 map.emergeBlock(blockpos, true);
3475 content_t c = map.getNodeNoEx(nodepos).getContent();
3476 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3478 if (air_count >= 2) {
3479 nodeposf = intToFloat(nodepos, BS);
3480 // Don't spawn the player outside map boundaries
3481 if (objectpos_over_limit(nodeposf))
3494 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3496 m_shutdown_timer = delay;
3497 m_shutdown_msg = msg;
3498 m_shutdown_ask_reconnect = reconnect;
3500 if (delay == 0.0f) {
3501 // No delay, shutdown immediately
3502 m_shutdown_requested = true;
3503 // only print to the infostream, a chat message saying
3504 // "Server Shutting Down" is sent when the server destructs.
3505 infostream << "*** Immediate Server shutdown requested." << std::endl;
3506 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3507 // Negative delay, cancel shutdown if requested
3508 m_shutdown_timer = 0.0f;
3509 m_shutdown_msg = "";
3510 m_shutdown_ask_reconnect = false;
3511 m_shutdown_requested = false;
3512 std::wstringstream ws;
3514 ws << L"*** Server shutdown canceled.";
3516 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3517 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3518 } else if (delay > 0.0f) {
3519 // Positive delay, tell the clients when the server will shut down
3520 std::wstringstream ws;
3522 ws << L"*** Server shutting down in "
3523 << duration_to_string(myround(m_shutdown_timer)).c_str()
3526 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3527 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3531 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3534 Try to get an existing player
3536 RemotePlayer *player = m_env->getPlayer(name);
3538 // If player is already connected, cancel
3539 if (player && player->peer_id != 0) {
3540 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3545 If player with the wanted peer_id already exists, cancel.
3547 if (m_env->getPlayer(peer_id)) {
3548 infostream<<"emergePlayer(): Player with wrong name but same"
3549 " peer_id already exists"<<std::endl;
3554 player = new RemotePlayer(name, idef());
3557 bool newplayer = false;
3560 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3562 // Complete init with server parts
3563 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3564 player->protocol_version = proto_version;
3568 m_script->on_newplayer(playersao);
3574 bool Server::registerModStorage(ModMetadata *storage)
3576 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3577 errorstream << "Unable to register same mod storage twice. Storage name: "
3578 << storage->getModName() << std::endl;
3582 m_mod_storages[storage->getModName()] = storage;
3586 void Server::unregisterModStorage(const std::string &name)
3588 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3589 if (it != m_mod_storages.end()) {
3590 // Save unconditionaly on unregistration
3591 it->second->save(getModStoragePath());
3592 m_mod_storages.erase(name);
3596 void dedicated_server_loop(Server &server, bool &kill)
3598 DSTACK(FUNCTION_NAME);
3600 verbosestream<<"dedicated_server_loop()"<<std::endl;
3602 IntervalLimiter m_profiler_interval;
3604 static thread_local const float steplen =
3605 g_settings->getFloat("dedicated_server_step");
3606 static thread_local const float profiler_print_interval =
3607 g_settings->getFloat("profiler_print_interval");
3610 // This is kind of a hack but can be done like this
3611 // because server.step() is very light
3613 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3614 sleep_ms((int)(steplen*1000.0));
3616 server.step(steplen);
3618 if (server.getShutdownRequested() || kill)
3624 if (profiler_print_interval != 0) {
3625 if(m_profiler_interval.step(steplen, profiler_print_interval))
3627 infostream<<"Profiler:"<<std::endl;
3628 g_profiler->print(infostream);
3629 g_profiler->clear();
3634 infostream << "Dedicated server quitting" << std::endl;
3636 if (g_settings->getBool("server_announce"))
3637 ServerList::sendAnnounce(ServerList::AA_DELETE,
3638 server.m_bind_addr.getPort());