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 "modchannels.h"
55 #include "serverlist.h"
56 #include "util/string.h"
58 #include "util/serialize.h"
59 #include "util/thread.h"
60 #include "defaultsettings.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
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()),
173 m_modchannel_mgr(new ModChannelMgr())
175 m_lag = g_settings->getFloat("dedicated_server_step");
177 if (path_world.empty())
178 throw ServerError("Supplied empty world path");
180 if(!gamespec.isValid())
181 throw ServerError("Supplied invalid gamespec");
183 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
184 if(m_simple_singleplayer_mode)
185 infostream<<" in simple singleplayer mode"<<std::endl;
187 infostream<<std::endl;
188 infostream<<"- world: "<<m_path_world<<std::endl;
189 infostream<<"- game: "<<m_gamespec.path<<std::endl;
191 // Create world if it doesn't exist
192 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
193 throw ServerError("Failed to initialize world");
195 // Create server thread
196 m_thread = new ServerThread(this);
198 // Create emerge manager
199 m_emerge = new EmergeManager(this);
201 // Create ban manager
202 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
203 m_banmanager = new BanManager(ban_path);
205 ServerModConfiguration modconf(m_path_world);
206 m_mods = modconf.getMods();
207 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
208 // complain about mods with unsatisfied dependencies
209 if (!modconf.isConsistent()) {
210 modconf.printUnsatisfiedModsError();
214 MutexAutoLock envlock(m_env_mutex);
216 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
217 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
219 // Initialize scripting
220 infostream<<"Server: Initializing Lua"<<std::endl;
222 m_script = new ServerScripting(this);
224 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
227 infostream << "Server: Loading mods: ";
228 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
229 i != m_mods.end(); ++i) {
230 infostream << (*i).name << " ";
232 infostream << std::endl;
233 // Load and run "mod" scripts
234 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
235 it != m_mods.end(); ++it) {
236 const ModSpec &mod = *it;
237 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
238 throw ModError("Error loading mod \"" + mod.name +
239 "\": Mod name does not follow naming conventions: "
240 "Only characters [a-z0-9_] are allowed.");
242 std::string script_path = mod.path + DIR_DELIM + "init.lua";
243 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
244 << script_path << "\"]" << std::endl;
245 m_script->loadMod(script_path, mod.name);
248 // Read Textures and calculate sha1 sums
251 // Apply item aliases in the node definition manager
252 m_nodedef->updateAliases(m_itemdef);
254 // Apply texture overrides from texturepack/override.txt
255 std::string texture_path = g_settings->get("texture_path");
256 if (!texture_path.empty() && fs::IsDir(texture_path))
257 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
259 m_nodedef->setNodeRegistrationStatus(true);
261 // Perform pending node name resolutions
262 m_nodedef->runNodeResolveCallbacks();
264 // unmap node names for connected nodeboxes
265 m_nodedef->mapNodeboxConnections();
267 // init the recipe hashes to speed up crafting
268 m_craftdef->initHashes(this);
270 // Initialize Environment
271 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
273 m_clients.setEnv(m_env);
275 if (!servermap->settings_mgr.makeMapgenParams())
276 FATAL_ERROR("Couldn't create any mapgen type");
278 // Initialize mapgens
279 m_emerge->initMapgens(servermap->getMapgenParams());
281 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
282 if (m_enable_rollback_recording) {
283 // Create rollback manager
284 m_rollback = new RollbackManager(m_path_world, this);
287 // Give environment reference to scripting api
288 m_script->initializeEnvironment(m_env);
290 // Register us to receive map edit events
291 servermap->addEventReceiver(this);
293 // If file exists, load environment metadata
294 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
295 infostream << "Server: Loading environment metadata" << std::endl;
298 m_env->loadDefaultMeta();
301 m_liquid_transform_every = g_settings->getFloat("liquid_update");
302 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
303 m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
304 m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
309 infostream<<"Server destructing"<<std::endl;
311 // Send shutdown message
312 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
313 L"*** Server shutting down"));
316 MutexAutoLock envlock(m_env_mutex);
318 // Execute script shutdown hooks
319 m_script->on_shutdown();
321 infostream << "Server: Saving players" << std::endl;
322 m_env->saveLoadedPlayers();
324 infostream << "Server: Kicking players" << std::endl;
325 std::string kick_msg;
326 bool reconnect = false;
327 if (getShutdownRequested()) {
328 reconnect = m_shutdown_ask_reconnect;
329 kick_msg = m_shutdown_msg;
331 if (kick_msg.empty()) {
332 kick_msg = g_settings->get("kick_msg_shutdown");
334 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
335 kick_msg, reconnect);
337 infostream << "Server: Saving environment metadata" << std::endl;
345 // stop all emerge threads before deleting players that may have
346 // requested blocks to be emerged
347 m_emerge->stopThreads();
349 // Delete things in the reverse order of creation
359 // Deinitialize scripting
360 infostream<<"Server: Deinitializing scripting"<<std::endl;
363 // Delete detached inventories
364 for (auto &detached_inventory : m_detached_inventories) {
365 delete detached_inventory.second;
369 void Server::start(Address bind_addr)
371 m_bind_addr = bind_addr;
373 infostream<<"Starting server on "
374 << bind_addr.serializeString() <<"..."<<std::endl;
376 // Stop thread if already running
379 // Initialize connection
380 m_con->SetTimeoutMs(30);
381 m_con->Serve(bind_addr);
386 // ASCII art for the win!
388 <<" .__ __ __ "<<std::endl
389 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
390 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
391 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
392 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
393 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
394 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
395 actionstream<<"Server for gameid=\""<<m_gamespec.id
396 <<"\" listening on "<<bind_addr.serializeString()<<":"
397 <<bind_addr.getPort() << "."<<std::endl;
402 infostream<<"Server: Stopping and waiting threads"<<std::endl;
404 // Stop threads (set run=false first so both start stopping)
406 //m_emergethread.setRun(false);
408 //m_emergethread.stop();
410 infostream<<"Server: Threads stopped"<<std::endl;
413 void Server::step(float dtime)
419 MutexAutoLock lock(m_step_dtime_mutex);
420 m_step_dtime += dtime;
422 // Throw if fatal error occurred in thread
423 std::string async_err = m_async_fatal_error.get();
424 if (!async_err.empty()) {
425 if (!m_simple_singleplayer_mode) {
426 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
427 g_settings->get("kick_msg_crash"),
428 g_settings->getBool("ask_reconnect_on_crash"));
430 throw ServerError("AsyncErr: " + async_err);
434 void Server::AsyncRunStep(bool initial_step)
436 g_profiler->add("Server::AsyncRunStep (num)", 1);
440 MutexAutoLock lock1(m_step_dtime_mutex);
441 dtime = m_step_dtime;
445 // Send blocks to clients
449 if((dtime < 0.001) && !initial_step)
452 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
454 //infostream<<"Server steps "<<dtime<<std::endl;
455 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
458 MutexAutoLock lock1(m_step_dtime_mutex);
459 m_step_dtime -= dtime;
466 m_uptime.set(m_uptime.get() + dtime);
472 Update time of day and overall game time
474 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
477 Send to clients at constant intervals
480 m_time_of_day_send_timer -= dtime;
481 if(m_time_of_day_send_timer < 0.0) {
482 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
483 u16 time = m_env->getTimeOfDay();
484 float time_speed = g_settings->getFloat("time_speed");
485 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
489 MutexAutoLock lock(m_env_mutex);
490 // Figure out and report maximum lag to environment
491 float max_lag = m_env->getMaxLagEstimate();
492 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
494 if(dtime > 0.1 && dtime > max_lag * 2.0)
495 infostream<<"Server: Maximum lag peaked to "<<dtime
499 m_env->reportMaxLagEstimate(max_lag);
501 ScopeProfiler sp(g_profiler, "SEnv step");
502 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
506 static const float map_timer_and_unload_dtime = 2.92;
507 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
509 MutexAutoLock lock(m_env_mutex);
510 // Run Map's timers and unload unused data
511 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
512 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
513 g_settings->getFloat("server_unload_unused_data_timeout"),
518 Listen to the admin chat, if available
521 if (!m_admin_chat->command_queue.empty()) {
522 MutexAutoLock lock(m_env_mutex);
523 while (!m_admin_chat->command_queue.empty()) {
524 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
525 handleChatInterfaceEvent(evt);
529 m_admin_chat->outgoing_queue.push_back(
530 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
537 /* Transform liquids */
538 m_liquid_transform_timer += dtime;
539 if(m_liquid_transform_timer >= m_liquid_transform_every)
541 m_liquid_transform_timer -= m_liquid_transform_every;
543 MutexAutoLock lock(m_env_mutex);
545 ScopeProfiler sp(g_profiler, "Server: liquid transform");
547 std::map<v3s16, MapBlock*> modified_blocks;
548 m_env->getMap().transformLiquids(modified_blocks, m_env);
551 Set the modified blocks unsent for all the clients
553 if(!modified_blocks.empty())
555 SetBlocksNotSent(modified_blocks);
558 m_clients.step(dtime);
560 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
562 // send masterserver announce
564 float &counter = m_masterserver_timer;
565 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
566 g_settings->getBool("server_announce")) {
567 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
568 ServerList::AA_START,
569 m_bind_addr.getPort(),
570 m_clients.getPlayerNames(),
572 m_env->getGameTime(),
575 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
585 Check added and deleted active objects
588 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
589 MutexAutoLock envlock(m_env_mutex);
592 const RemoteClientMap &clients = m_clients.getClientList();
593 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
595 // Radius inside which objects are active
596 static thread_local const s16 radius =
597 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
599 // Radius inside which players are active
600 static thread_local const bool is_transfer_limited =
601 g_settings->exists("unlimited_player_transfer_distance") &&
602 !g_settings->getBool("unlimited_player_transfer_distance");
603 static thread_local const s16 player_transfer_dist =
604 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
605 s16 player_radius = player_transfer_dist;
606 if (player_radius == 0 && is_transfer_limited)
607 player_radius = radius;
609 for (const auto &client_it : clients) {
610 RemoteClient *client = client_it.second;
612 // If definitions and textures have not been sent, don't
613 // send objects either
614 if (client->getState() < CS_DefinitionsSent)
617 RemotePlayer *player = m_env->getPlayer(client->peer_id);
619 // This can happen if the client timeouts somehow
623 PlayerSAO *playersao = player->getPlayerSAO();
627 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
628 if (my_radius <= 0) my_radius = radius;
629 //infostream << "Server: Active Radius " << my_radius << std::endl;
631 std::queue<u16> removed_objects;
632 std::queue<u16> added_objects;
633 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
634 client->m_known_objects, removed_objects);
635 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
636 client->m_known_objects, added_objects);
638 // Ignore if nothing happened
639 if (removed_objects.empty() && added_objects.empty()) {
643 std::string data_buffer;
647 // Handle removed objects
648 writeU16((u8*)buf, removed_objects.size());
649 data_buffer.append(buf, 2);
650 while (!removed_objects.empty()) {
652 u16 id = removed_objects.front();
653 ServerActiveObject* obj = m_env->getActiveObject(id);
655 // Add to data buffer for sending
656 writeU16((u8*)buf, id);
657 data_buffer.append(buf, 2);
659 // Remove from known objects
660 client->m_known_objects.erase(id);
662 if(obj && obj->m_known_by_count > 0)
663 obj->m_known_by_count--;
664 removed_objects.pop();
667 // Handle added objects
668 writeU16((u8*)buf, added_objects.size());
669 data_buffer.append(buf, 2);
670 while (!added_objects.empty()) {
672 u16 id = added_objects.front();
673 ServerActiveObject* obj = m_env->getActiveObject(id);
676 u8 type = ACTIVEOBJECT_TYPE_INVALID;
678 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
680 type = obj->getSendType();
682 // Add to data buffer for sending
683 writeU16((u8*)buf, id);
684 data_buffer.append(buf, 2);
685 writeU8((u8*)buf, type);
686 data_buffer.append(buf, 1);
689 data_buffer.append(serializeLongString(
690 obj->getClientInitializationData(client->net_proto_version)));
692 data_buffer.append(serializeLongString(""));
694 // Add to known objects
695 client->m_known_objects.insert(id);
698 obj->m_known_by_count++;
703 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
704 verbosestream << "Server: Sent object remove/add: "
705 << removed_objects.size() << " removed, "
706 << added_objects.size() << " added, "
707 << "packet size is " << pktSize << std::endl;
711 m_mod_storage_save_timer -= dtime;
712 if (m_mod_storage_save_timer <= 0.0f) {
713 infostream << "Saving registered mod storages." << std::endl;
714 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
715 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
716 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
717 if (it->second->isModified()) {
718 it->second->save(getModStoragePath());
728 MutexAutoLock envlock(m_env_mutex);
729 ScopeProfiler sp(g_profiler, "Server: sending object messages");
732 // Value = data sent by object
733 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
735 // Get active object messages from environment
737 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
741 std::vector<ActiveObjectMessage>* message_list = nullptr;
742 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
743 n = buffered_messages.find(aom.id);
744 if (n == buffered_messages.end()) {
745 message_list = new std::vector<ActiveObjectMessage>;
746 buffered_messages[aom.id] = message_list;
749 message_list = n->second;
751 message_list->push_back(aom);
755 const RemoteClientMap &clients = m_clients.getClientList();
756 // Route data to every client
757 for (const auto &client_it : clients) {
758 RemoteClient *client = client_it.second;
759 std::string reliable_data;
760 std::string unreliable_data;
761 // Go through all objects in message buffer
762 for (const auto &buffered_message : buffered_messages) {
763 // If object is not known by client, skip it
764 u16 id = buffered_message.first;
765 if (client->m_known_objects.find(id) == client->m_known_objects.end())
768 // Get message list of object
769 std::vector<ActiveObjectMessage>* list = buffered_message.second;
770 // Go through every message
771 for (const ActiveObjectMessage &aom : *list) {
772 // Compose the full new data with header
773 std::string new_data;
776 writeU16((u8*)&buf[0], aom.id);
777 new_data.append(buf, 2);
779 new_data += serializeString(aom.datastring);
780 // Add data to buffer
782 reliable_data += new_data;
784 unreliable_data += new_data;
788 reliable_data and unreliable_data are now ready.
791 if (!reliable_data.empty()) {
792 SendActiveObjectMessages(client->peer_id, reliable_data);
795 if (!unreliable_data.empty()) {
796 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
801 // Clear buffered_messages
802 for (auto &buffered_message : buffered_messages) {
803 delete buffered_message.second;
808 Send queued-for-sending map edit events.
811 // We will be accessing the environment
812 MutexAutoLock lock(m_env_mutex);
814 // Don't send too many at a time
817 // Single change sending is disabled if queue size is not small
818 bool disable_single_change_sending = false;
819 if(m_unsent_map_edit_queue.size() >= 4)
820 disable_single_change_sending = true;
822 int event_count = m_unsent_map_edit_queue.size();
824 // We'll log the amount of each
827 while (!m_unsent_map_edit_queue.empty()) {
828 MapEditEvent* event = m_unsent_map_edit_queue.front();
829 m_unsent_map_edit_queue.pop();
831 // Players far away from the change are stored here.
832 // Instead of sending the changes, MapBlocks are set not sent
834 std::vector<u16> far_players;
836 switch (event->type) {
839 prof.add("MEET_ADDNODE", 1);
840 sendAddNode(event->p, event->n, event->already_known_by_peer,
841 &far_players, disable_single_change_sending ? 5 : 30,
842 event->type == MEET_ADDNODE);
844 case MEET_REMOVENODE:
845 prof.add("MEET_REMOVENODE", 1);
846 sendRemoveNode(event->p, event->already_known_by_peer,
847 &far_players, disable_single_change_sending ? 5 : 30);
849 case MEET_BLOCK_NODE_METADATA_CHANGED:
850 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
851 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
852 setBlockNotSent(event->p);
855 infostream << "Server: MEET_OTHER" << std::endl;
856 prof.add("MEET_OTHER", 1);
857 for (const v3s16 &modified_block : event->modified_blocks) {
858 setBlockNotSent(modified_block);
862 prof.add("unknown", 1);
863 warningstream << "Server: Unknown MapEditEvent "
864 << ((u32)event->type) << std::endl;
869 Set blocks not sent to far players
871 if (!far_players.empty()) {
872 // Convert list format to that wanted by SetBlocksNotSent
873 std::map<v3s16, MapBlock*> modified_blocks2;
874 for (const v3s16 &modified_block : event->modified_blocks) {
875 modified_blocks2[modified_block] =
876 m_env->getMap().getBlockNoCreateNoEx(modified_block);
879 // Set blocks not sent
880 for (const u16 far_player : far_players) {
881 if (RemoteClient *client = getClient(far_player))
882 client->SetBlocksNotSent(modified_blocks2);
889 if (event_count >= 5) {
890 infostream << "Server: MapEditEvents:" << std::endl;
891 prof.print(infostream);
892 } else if (event_count != 0) {
893 verbosestream << "Server: MapEditEvents:" << std::endl;
894 prof.print(verbosestream);
900 Trigger emergethread (it somehow gets to a non-triggered but
901 bysy state sometimes)
904 float &counter = m_emergethread_trigger_timer;
906 if (counter >= 2.0) {
909 m_emerge->startThreads();
913 // Save map, players and auth stuff
915 float &counter = m_savemap_timer;
917 static thread_local const float save_interval =
918 g_settings->getFloat("server_map_save_interval");
919 if (counter >= save_interval) {
921 MutexAutoLock lock(m_env_mutex);
923 ScopeProfiler sp(g_profiler, "Server: saving stuff");
926 if (m_banmanager->isModified()) {
927 m_banmanager->save();
930 // Save changed parts of map
931 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
934 m_env->saveLoadedPlayers();
936 // Save environment metadata
942 static const float shutdown_msg_times[] =
944 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
947 if (m_shutdown_timer > 0.0f) {
948 // Automated messages
949 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
950 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
951 // If shutdown timer matches an automessage, shot it
952 if (m_shutdown_timer > shutdown_msg_times[i] &&
953 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
954 std::wstringstream ws;
956 ws << L"*** Server shutting down in "
957 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
960 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
961 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
967 m_shutdown_timer -= dtime;
968 if (m_shutdown_timer < 0.0f) {
969 m_shutdown_timer = 0.0f;
970 m_shutdown_requested = true;
975 void Server::Receive()
980 m_con->Receive(&pkt);
981 peer_id = pkt.getPeerId();
983 } catch (const con::InvalidIncomingDataException &e) {
984 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
985 << e.what() << std::endl;
986 } catch (const SerializationError &e) {
987 infostream << "Server::Receive(): SerializationError: what()="
988 << e.what() << std::endl;
989 } catch (const ClientStateError &e) {
990 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
991 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
992 L"Try reconnecting or updating your client");
993 } catch (const con::PeerNotFoundException &e) {
998 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1000 std::string playername;
1001 PlayerSAO *playersao = NULL;
1004 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1006 playername = client->getName();
1007 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1009 } catch (std::exception &e) {
1015 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1017 // If failed, cancel
1018 if (!playersao || !player) {
1019 if (player && player->peer_id != 0) {
1020 actionstream << "Server: Failed to emerge player \"" << playername
1021 << "\" (player allocated to an another client)" << std::endl;
1022 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1023 L"name. If your client closed unexpectedly, try again in "
1026 errorstream << "Server: " << playername << ": Failed to emerge player"
1028 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1034 Send complete position information
1036 SendMovePlayer(peer_id);
1039 SendPlayerPrivileges(peer_id);
1041 // Send inventory formspec
1042 SendPlayerInventoryFormspec(peer_id);
1045 SendInventory(playersao);
1047 // Send HP or death screen
1048 if (playersao->isDead())
1049 SendDeathscreen(peer_id, false, v3f(0,0,0));
1051 SendPlayerHPOrDie(playersao);
1054 SendPlayerBreath(playersao);
1056 // Note things in chat if not in simple singleplayer mode
1057 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1058 // Send information about server to player in chat
1059 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1061 Address addr = getPeerAddress(player->peer_id);
1062 std::string ip_str = addr.serializeString();
1063 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1068 const std::vector<std::string> &names = m_clients.getPlayerNames();
1070 actionstream << player->getName() << " joins game. List of players: ";
1072 for (const std::string &name : names) {
1073 actionstream << name << " ";
1076 actionstream << player->getName() <<std::endl;
1081 inline void Server::handleCommand(NetworkPacket* pkt)
1083 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1084 (this->*opHandle.handler)(pkt);
1087 void Server::ProcessData(NetworkPacket *pkt)
1089 // Environment is locked first.
1090 MutexAutoLock envlock(m_env_mutex);
1092 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1093 u32 peer_id = pkt->getPeerId();
1096 Address address = getPeerAddress(peer_id);
1097 std::string addr_s = address.serializeString();
1099 if(m_banmanager->isIpBanned(addr_s)) {
1100 std::string ban_name = m_banmanager->getBanName(addr_s);
1101 infostream << "Server: A banned client tried to connect from "
1102 << addr_s << "; banned name was "
1103 << ban_name << std::endl;
1104 // This actually doesn't seem to transfer to the client
1105 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1106 + utf8_to_wide(ban_name));
1110 catch(con::PeerNotFoundException &e) {
1112 * no peer for this packet found
1113 * most common reason is peer timeout, e.g. peer didn't
1114 * respond for some time, your server was overloaded or
1117 infostream << "Server::ProcessData(): Canceling: peer "
1118 << peer_id << " not found" << std::endl;
1123 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1125 // Command must be handled into ToServerCommandHandler
1126 if (command >= TOSERVER_NUM_MSG_TYPES) {
1127 infostream << "Server: Ignoring unknown command "
1128 << command << std::endl;
1132 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1137 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1139 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1140 errorstream << "Server::ProcessData(): Cancelling: Peer"
1141 " serialization format invalid or not initialized."
1142 " Skipping incoming command=" << command << std::endl;
1146 /* Handle commands related to client startup */
1147 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1152 if (m_clients.getClientState(peer_id) < CS_Active) {
1153 if (command == TOSERVER_PLAYERPOS) return;
1155 errorstream << "Got packet command: " << command << " for peer id "
1156 << peer_id << " but client isn't active yet. Dropping packet "
1162 } catch (SendFailedException &e) {
1163 errorstream << "Server::ProcessData(): SendFailedException: "
1164 << "what=" << e.what()
1166 } catch (PacketError &e) {
1167 actionstream << "Server::ProcessData(): PacketError: "
1168 << "what=" << e.what()
1173 void Server::setTimeOfDay(u32 time)
1175 m_env->setTimeOfDay(time);
1176 m_time_of_day_send_timer = 0;
1179 void Server::onMapEditEvent(MapEditEvent *event)
1181 if(m_ignore_map_edit_events)
1183 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1185 MapEditEvent *e = event->clone();
1186 m_unsent_map_edit_queue.push(e);
1189 Inventory* Server::getInventory(const InventoryLocation &loc)
1192 case InventoryLocation::UNDEFINED:
1193 case InventoryLocation::CURRENT_PLAYER:
1195 case InventoryLocation::PLAYER:
1197 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1200 PlayerSAO *playersao = player->getPlayerSAO();
1203 return playersao->getInventory();
1206 case InventoryLocation::NODEMETA:
1208 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1211 return meta->getInventory();
1214 case InventoryLocation::DETACHED:
1216 if(m_detached_inventories.count(loc.name) == 0)
1218 return m_detached_inventories[loc.name];
1222 sanity_check(false); // abort
1227 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1230 case InventoryLocation::UNDEFINED:
1232 case InventoryLocation::PLAYER:
1237 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1242 PlayerSAO *playersao = player->getPlayerSAO();
1246 SendInventory(playersao);
1249 case InventoryLocation::NODEMETA:
1251 v3s16 blockpos = getNodeBlockPos(loc.p);
1253 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1255 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1257 setBlockNotSent(blockpos);
1260 case InventoryLocation::DETACHED:
1262 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1266 sanity_check(false); // abort
1271 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1273 std::vector<u16> clients = m_clients.getClientIDs();
1275 // Set the modified blocks unsent for all the clients
1276 for (const u16 client_id : clients) {
1277 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1278 client->SetBlocksNotSent(block);
1283 void Server::peerAdded(con::Peer *peer)
1285 verbosestream<<"Server::peerAdded(): peer->id="
1286 <<peer->id<<std::endl;
1288 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1291 void Server::deletingPeer(con::Peer *peer, bool timeout)
1293 verbosestream<<"Server::deletingPeer(): peer->id="
1294 <<peer->id<<", timeout="<<timeout<<std::endl;
1296 m_clients.event(peer->id, CSE_Disconnect);
1297 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1300 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1302 *retval = m_con->getPeerStat(peer_id,type);
1303 return *retval != -1;
1306 bool Server::getClientInfo(
1315 std::string* vers_string
1318 *state = m_clients.getClientState(peer_id);
1320 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1327 *uptime = client->uptime();
1328 *ser_vers = client->serialization_version;
1329 *prot_vers = client->net_proto_version;
1331 *major = client->getMajor();
1332 *minor = client->getMinor();
1333 *patch = client->getPatch();
1334 *vers_string = client->getPatch();
1341 void Server::handlePeerChanges()
1343 while(!m_peer_change_queue.empty())
1345 con::PeerChange c = m_peer_change_queue.front();
1346 m_peer_change_queue.pop();
1348 verbosestream<<"Server: Handling peer change: "
1349 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1354 case con::PEER_ADDED:
1355 m_clients.CreateClient(c.peer_id);
1358 case con::PEER_REMOVED:
1359 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1363 FATAL_ERROR("Invalid peer change event received!");
1369 void Server::printToConsoleOnly(const std::string &text)
1372 m_admin_chat->outgoing_queue.push_back(
1373 new ChatEventChat("", utf8_to_wide(text)));
1375 std::cout << text << std::endl;
1379 void Server::Send(NetworkPacket *pkt)
1381 Send(pkt->getPeerId(), pkt);
1384 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1386 m_clients.send(peer_id,
1387 clientCommandFactoryTable[pkt->getCommand()].channel,
1389 clientCommandFactoryTable[pkt->getCommand()].reliable);
1392 void Server::SendMovement(session_t peer_id)
1394 std::ostringstream os(std::ios_base::binary);
1396 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1398 pkt << g_settings->getFloat("movement_acceleration_default");
1399 pkt << g_settings->getFloat("movement_acceleration_air");
1400 pkt << g_settings->getFloat("movement_acceleration_fast");
1401 pkt << g_settings->getFloat("movement_speed_walk");
1402 pkt << g_settings->getFloat("movement_speed_crouch");
1403 pkt << g_settings->getFloat("movement_speed_fast");
1404 pkt << g_settings->getFloat("movement_speed_climb");
1405 pkt << g_settings->getFloat("movement_speed_jump");
1406 pkt << g_settings->getFloat("movement_liquid_fluidity");
1407 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1408 pkt << g_settings->getFloat("movement_liquid_sink");
1409 pkt << g_settings->getFloat("movement_gravity");
1414 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1416 if (!g_settings->getBool("enable_damage"))
1419 session_t peer_id = playersao->getPeerID();
1420 bool is_alive = playersao->getHP() > 0;
1423 SendPlayerHP(peer_id);
1428 void Server::SendHP(session_t peer_id, u16 hp)
1430 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1435 void Server::SendBreath(session_t peer_id, u16 breath)
1437 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1438 pkt << (u16) breath;
1442 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1443 const std::string &custom_reason, bool reconnect)
1445 assert(reason < SERVER_ACCESSDENIED_MAX);
1447 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1449 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1450 pkt << custom_reason;
1451 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1452 reason == SERVER_ACCESSDENIED_CRASH)
1453 pkt << custom_reason << (u8)reconnect;
1457 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1459 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1464 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1465 v3f camera_point_target)
1467 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1468 pkt << set_camera_point_target << camera_point_target;
1472 void Server::SendItemDef(session_t peer_id,
1473 IItemDefManager *itemdef, u16 protocol_version)
1475 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1479 u32 length of the next item
1480 zlib-compressed serialized ItemDefManager
1482 std::ostringstream tmp_os(std::ios::binary);
1483 itemdef->serialize(tmp_os, protocol_version);
1484 std::ostringstream tmp_os2(std::ios::binary);
1485 compressZlib(tmp_os.str(), tmp_os2);
1486 pkt.putLongString(tmp_os2.str());
1489 verbosestream << "Server: Sending item definitions to id(" << peer_id
1490 << "): size=" << pkt.getSize() << std::endl;
1495 void Server::SendNodeDef(session_t peer_id,
1496 INodeDefManager *nodedef, u16 protocol_version)
1498 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1502 u32 length of the next item
1503 zlib-compressed serialized NodeDefManager
1505 std::ostringstream tmp_os(std::ios::binary);
1506 nodedef->serialize(tmp_os, protocol_version);
1507 std::ostringstream tmp_os2(std::ios::binary);
1508 compressZlib(tmp_os.str(), tmp_os2);
1510 pkt.putLongString(tmp_os2.str());
1513 verbosestream << "Server: Sending node definitions to id(" << peer_id
1514 << "): size=" << pkt.getSize() << std::endl;
1520 Non-static send methods
1523 void Server::SendInventory(PlayerSAO* playerSAO)
1525 UpdateCrafting(playerSAO->getPlayer());
1531 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1533 std::ostringstream os;
1534 playerSAO->getInventory()->serialize(os);
1536 std::string s = os.str();
1538 pkt.putRawString(s.c_str(), s.size());
1542 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1544 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1546 u8 type = message.type;
1547 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1549 if (peer_id != PEER_ID_INEXISTENT) {
1550 RemotePlayer *player = m_env->getPlayer(peer_id);
1556 m_clients.sendToAll(&pkt);
1560 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1561 const std::string &formname)
1563 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1564 if (formspec.empty()){
1565 //the client should close the formspec
1566 pkt.putLongString("");
1568 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1575 // Spawns a particle on peer with peer_id
1576 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1577 v3f pos, v3f velocity, v3f acceleration,
1578 float expirationtime, float size, bool collisiondetection,
1579 bool collision_removal,
1580 bool vertical, const std::string &texture,
1581 const struct TileAnimationParams &animation, u8 glow)
1583 static thread_local const float radius =
1584 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1586 if (peer_id == PEER_ID_INEXISTENT) {
1587 std::vector<u16> clients = m_clients.getClientIDs();
1589 for (const u16 client_id : clients) {
1590 RemotePlayer *player = m_env->getPlayer(client_id);
1594 PlayerSAO *sao = player->getPlayerSAO();
1598 // Do not send to distant clients
1599 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1602 SendSpawnParticle(client_id, player->protocol_version,
1603 pos, velocity, acceleration,
1604 expirationtime, size, collisiondetection,
1605 collision_removal, vertical, texture, animation, glow);
1610 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1612 pkt << pos << velocity << acceleration << expirationtime
1613 << size << collisiondetection;
1614 pkt.putLongString(texture);
1616 pkt << collision_removal;
1617 // This is horrible but required (why are there two ways to serialize pkts?)
1618 std::ostringstream os(std::ios_base::binary);
1619 animation.serialize(os, protocol_version);
1620 pkt.putRawString(os.str());
1626 // Adds a ParticleSpawner on peer with peer_id
1627 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1628 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1629 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1630 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1631 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1632 const struct TileAnimationParams &animation, u8 glow)
1634 if (peer_id == PEER_ID_INEXISTENT) {
1635 // This sucks and should be replaced:
1636 std::vector<u16> clients = m_clients.getClientIDs();
1637 for (const u16 client_id : clients) {
1638 RemotePlayer *player = m_env->getPlayer(client_id);
1641 SendAddParticleSpawner(client_id, player->protocol_version,
1642 amount, spawntime, minpos, maxpos,
1643 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1644 minsize, maxsize, collisiondetection, collision_removal,
1645 attached_id, vertical, texture, id, animation, glow);
1650 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1652 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1653 << minacc << maxacc << minexptime << maxexptime << minsize
1654 << maxsize << collisiondetection;
1656 pkt.putLongString(texture);
1658 pkt << id << vertical;
1659 pkt << collision_removal;
1661 // This is horrible but required
1662 std::ostringstream os(std::ios_base::binary);
1663 animation.serialize(os, protocol_version);
1664 pkt.putRawString(os.str());
1670 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1672 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1674 // Ugly error in this packet
1677 if (peer_id != PEER_ID_INEXISTENT)
1680 m_clients.sendToAll(&pkt);
1684 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1686 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1688 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1689 << form->text << form->number << form->item << form->dir
1690 << form->align << form->offset << form->world_pos << form->size;
1695 void Server::SendHUDRemove(session_t peer_id, u32 id)
1697 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1702 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1704 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1705 pkt << id << (u8) stat;
1709 case HUD_STAT_SCALE:
1710 case HUD_STAT_ALIGN:
1711 case HUD_STAT_OFFSET:
1712 pkt << *(v2f *) value;
1716 pkt << *(std::string *) value;
1718 case HUD_STAT_WORLD_POS:
1719 pkt << *(v3f *) value;
1722 pkt << *(v2s32 *) value;
1724 case HUD_STAT_NUMBER:
1728 pkt << *(u32 *) value;
1735 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1737 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1739 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1741 pkt << flags << mask;
1746 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1748 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1749 pkt << param << value;
1753 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1754 const std::string &type, const std::vector<std::string> ¶ms,
1757 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1758 pkt << bgcolor << type << (u16) params.size();
1760 for (const std::string ¶m : params)
1768 void Server::SendCloudParams(session_t peer_id, float density,
1769 const video::SColor &color_bright,
1770 const video::SColor &color_ambient,
1775 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1776 pkt << density << color_bright << color_ambient
1777 << height << thickness << speed;
1782 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1785 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1788 pkt << do_override << (u16) (ratio * 65535);
1793 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1795 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1796 pkt << time << time_speed;
1798 if (peer_id == PEER_ID_INEXISTENT) {
1799 m_clients.sendToAll(&pkt);
1806 void Server::SendPlayerHP(session_t peer_id)
1808 PlayerSAO *playersao = getPlayerSAO(peer_id);
1809 // In some rare case if the player is disconnected
1810 // while Lua call l_punch, for example, this can be NULL
1814 SendHP(peer_id, playersao->getHP());
1815 m_script->player_event(playersao,"health_changed");
1817 // Send to other clients
1818 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1819 ActiveObjectMessage aom(playersao->getId(), true, str);
1820 playersao->m_messages_out.push(aom);
1823 void Server::SendPlayerBreath(PlayerSAO *sao)
1827 m_script->player_event(sao, "breath_changed");
1828 SendBreath(sao->getPeerID(), sao->getBreath());
1831 void Server::SendMovePlayer(session_t peer_id)
1833 RemotePlayer *player = m_env->getPlayer(peer_id);
1835 PlayerSAO *sao = player->getPlayerSAO();
1838 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1839 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1842 v3f pos = sao->getBasePosition();
1843 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1844 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1845 << " pitch=" << sao->getPitch()
1846 << " yaw=" << sao->getYaw()
1853 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1854 f32 animation_speed)
1856 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1859 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1860 << animation_frames[3] << animation_speed;
1865 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1867 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1868 pkt << first << third;
1872 void Server::SendPlayerPrivileges(session_t peer_id)
1874 RemotePlayer *player = m_env->getPlayer(peer_id);
1876 if(player->peer_id == PEER_ID_INEXISTENT)
1879 std::set<std::string> privs;
1880 m_script->getAuth(player->getName(), NULL, &privs);
1882 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1883 pkt << (u16) privs.size();
1885 for (const std::string &priv : privs) {
1892 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1894 RemotePlayer *player = m_env->getPlayer(peer_id);
1896 if(player->peer_id == PEER_ID_INEXISTENT)
1899 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1900 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1904 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1906 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1907 pkt.putRawString(datas.c_str(), datas.size());
1909 return pkt.getSize();
1912 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1915 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1916 datas.size(), peer_id);
1918 pkt.putRawString(datas.c_str(), datas.size());
1920 m_clients.send(pkt.getPeerId(),
1921 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1925 void Server::SendCSMFlavourLimits(session_t peer_id)
1927 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
1928 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
1929 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
1933 s32 Server::playSound(const SimpleSoundSpec &spec,
1934 const ServerSoundParams ¶ms)
1936 // Find out initial position of sound
1937 bool pos_exists = false;
1938 v3f pos = params.getPos(m_env, &pos_exists);
1939 // If position is not found while it should be, cancel sound
1940 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1943 // Filter destination clients
1944 std::vector<u16> dst_clients;
1945 if(!params.to_player.empty()) {
1946 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1948 infostream<<"Server::playSound: Player \""<<params.to_player
1949 <<"\" not found"<<std::endl;
1952 if(player->peer_id == PEER_ID_INEXISTENT){
1953 infostream<<"Server::playSound: Player \""<<params.to_player
1954 <<"\" not connected"<<std::endl;
1957 dst_clients.push_back(player->peer_id);
1959 std::vector<u16> clients = m_clients.getClientIDs();
1961 for (const u16 client_id : clients) {
1962 RemotePlayer *player = m_env->getPlayer(client_id);
1966 PlayerSAO *sao = player->getPlayerSAO();
1971 if(sao->getBasePosition().getDistanceFrom(pos) >
1972 params.max_hear_distance)
1975 dst_clients.push_back(client_id);
1979 if(dst_clients.empty())
1983 s32 id = m_next_sound_id++;
1984 // The sound will exist as a reference in m_playing_sounds
1985 m_playing_sounds[id] = ServerPlayingSound();
1986 ServerPlayingSound &psound = m_playing_sounds[id];
1987 psound.params = params;
1990 float gain = params.gain * spec.gain;
1991 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1992 pkt << id << spec.name << gain
1993 << (u8) params.type << pos << params.object
1994 << params.loop << params.fade << params.pitch;
1996 // Backwards compability
1997 bool play_sound = gain > 0;
1999 for (const u16 dst_client : dst_clients) {
2000 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2001 psound.clients.insert(dst_client);
2002 m_clients.send(dst_client, 0, &pkt, true);
2007 void Server::stopSound(s32 handle)
2009 // Get sound reference
2010 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2011 m_playing_sounds.find(handle);
2012 if (i == m_playing_sounds.end())
2014 ServerPlayingSound &psound = i->second;
2016 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2019 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2020 si != psound.clients.end(); ++si) {
2022 m_clients.send(*si, 0, &pkt, true);
2024 // Remove sound reference
2025 m_playing_sounds.erase(i);
2028 void Server::fadeSound(s32 handle, float step, float gain)
2030 // Get sound reference
2031 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2032 m_playing_sounds.find(handle);
2033 if (i == m_playing_sounds.end())
2036 ServerPlayingSound &psound = i->second;
2037 psound.params.gain = gain;
2039 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2040 pkt << handle << step << gain;
2042 // Backwards compability
2043 bool play_sound = gain > 0;
2044 ServerPlayingSound compat_psound = psound;
2045 compat_psound.clients.clear();
2047 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2048 compat_pkt << handle;
2050 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2051 it != psound.clients.end();) {
2052 if (m_clients.getProtocolVersion(*it) >= 32) {
2054 m_clients.send(*it, 0, &pkt, true);
2057 compat_psound.clients.insert(*it);
2059 m_clients.send(*it, 0, &compat_pkt, true);
2060 psound.clients.erase(it++);
2064 // Remove sound reference
2065 if (!play_sound || psound.clients.empty())
2066 m_playing_sounds.erase(i);
2068 if (play_sound && !compat_psound.clients.empty()) {
2069 // Play new sound volume on older clients
2070 playSound(compat_psound.spec, compat_psound.params);
2074 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2075 std::vector<u16> *far_players, float far_d_nodes)
2077 float maxd = far_d_nodes*BS;
2078 v3f p_f = intToFloat(p, BS);
2080 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2083 std::vector<u16> clients = m_clients.getClientIDs();
2084 for (u16 client_id : clients) {
2087 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2088 PlayerSAO *sao = player->getPlayerSAO();
2092 // If player is far away, only set modified blocks not sent
2093 v3f player_pos = sao->getBasePosition();
2094 if (player_pos.getDistanceFrom(p_f) > maxd) {
2095 far_players->push_back(client_id);
2102 m_clients.send(client_id, 0, &pkt, true);
2106 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2107 std::vector<u16> *far_players, float far_d_nodes,
2108 bool remove_metadata)
2110 float maxd = far_d_nodes*BS;
2111 v3f p_f = intToFloat(p, BS);
2113 std::vector<u16> clients = m_clients.getClientIDs();
2114 for (const u16 client_id : clients) {
2117 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2118 PlayerSAO *sao = player->getPlayerSAO();
2122 // If player is far away, only set modified blocks not sent
2123 v3f player_pos = sao->getBasePosition();
2124 if(player_pos.getDistanceFrom(p_f) > maxd) {
2125 far_players->push_back(client_id);
2131 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2133 RemoteClient* client = m_clients.lockedGetClientNoEx(client_id);
2135 pkt << p << n.param0 << n.param1 << n.param2
2136 << (u8) (remove_metadata ? 0 : 1);
2141 if (pkt.getSize() > 0)
2142 m_clients.send(client_id, 0, &pkt, true);
2146 void Server::setBlockNotSent(v3s16 p)
2148 std::vector<u16> clients = m_clients.getClientIDs();
2150 for (const u16 i : clients) {
2151 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2152 client->SetBlockNotSent(p);
2157 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2158 u16 net_proto_version)
2160 v3s16 p = block->getPos();
2163 Create a packet with the block in the right format
2166 std::ostringstream os(std::ios_base::binary);
2167 block->serialize(os, ver, false);
2168 block->serializeNetworkSpecific(os);
2169 std::string s = os.str();
2171 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2174 pkt.putRawString(s.c_str(), s.size());
2178 void Server::SendBlocks(float dtime)
2180 MutexAutoLock envlock(m_env_mutex);
2181 //TODO check if one big lock could be faster then multiple small ones
2183 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2185 std::vector<PrioritySortedBlockTransfer> queue;
2187 u32 total_sending = 0;
2190 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2192 std::vector<u16> clients = m_clients.getClientIDs();
2195 for (const u16 client_id : clients) {
2196 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2201 total_sending += client->getSendingCount();
2202 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2208 // Lowest priority number comes first.
2209 // Lowest is most important.
2210 std::sort(queue.begin(), queue.end());
2214 // Maximal total count calculation
2215 // The per-client block sends is halved with the maximal online users
2216 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2217 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2219 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2220 if (total_sending >= max_blocks_to_send)
2223 MapBlock *block = nullptr;
2225 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2226 } catch (const InvalidPositionException &e) {
2230 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2235 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2236 client->net_proto_version);
2238 client->SentBlock(block_to_send.pos);
2244 void Server::fillMediaCache()
2246 infostream<<"Server: Calculating media file checksums"<<std::endl;
2248 // Collect all media file paths
2249 std::vector<std::string> paths;
2250 for (const ModSpec &mod : m_mods) {
2251 paths.push_back(mod.path + DIR_DELIM + "textures");
2252 paths.push_back(mod.path + DIR_DELIM + "sounds");
2253 paths.push_back(mod.path + DIR_DELIM + "media");
2254 paths.push_back(mod.path + DIR_DELIM + "models");
2255 paths.push_back(mod.path + DIR_DELIM + "locale");
2257 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2259 // Collect media file information from paths into cache
2260 for (const std::string &mediapath : paths) {
2261 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2262 for (const fs::DirListNode &dln : dirlist) {
2263 if (dln.dir) // Ignode dirs
2265 std::string filename = dln.name;
2266 // If name contains illegal characters, ignore the file
2267 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2268 infostream<<"Server: ignoring illegal file name: \""
2269 << filename << "\"" << std::endl;
2272 // If name is not in a supported format, ignore it
2273 const char *supported_ext[] = {
2274 ".png", ".jpg", ".bmp", ".tga",
2275 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2277 ".x", ".b3d", ".md2", ".obj",
2278 // Custom translation file format
2282 if (removeStringEnd(filename, supported_ext).empty()){
2283 infostream << "Server: ignoring unsupported file extension: \""
2284 << filename << "\"" << std::endl;
2287 // Ok, attempt to load the file and add to cache
2288 std::string filepath;
2289 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2292 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2294 errorstream << "Server::fillMediaCache(): Could not open \""
2295 << filename << "\" for reading" << std::endl;
2298 std::ostringstream tmp_os(std::ios_base::binary);
2302 fis.read(buf, 1024);
2303 std::streamsize len = fis.gcount();
2304 tmp_os.write(buf, len);
2313 errorstream<<"Server::fillMediaCache(): Failed to read \""
2314 << filename << "\"" << std::endl;
2317 if(tmp_os.str().length() == 0) {
2318 errorstream << "Server::fillMediaCache(): Empty file \""
2319 << filepath << "\"" << std::endl;
2324 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2326 unsigned char *digest = sha1.getDigest();
2327 std::string sha1_base64 = base64_encode(digest, 20);
2328 std::string sha1_hex = hex_encode((char*)digest, 20);
2332 m_media[filename] = MediaInfo(filepath, sha1_base64);
2333 verbosestream << "Server: " << sha1_hex << " is " << filename
2339 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2341 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2345 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2348 std::string lang_suffix;
2349 lang_suffix.append(".").append(lang_code).append(".tr");
2350 for (const auto &i : m_media) {
2351 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2358 for (const auto &i : m_media) {
2359 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2361 pkt << i.first << i.second.sha1_digest;
2364 pkt << g_settings->get("remote_media");
2368 struct SendableMedia
2374 SendableMedia(const std::string &name_="", const std::string &path_="",
2375 const std::string &data_=""):
2382 void Server::sendRequestedMedia(session_t peer_id,
2383 const std::vector<std::string> &tosend)
2385 verbosestream<<"Server::sendRequestedMedia(): "
2386 <<"Sending files to client"<<std::endl;
2390 // Put 5kB in one bunch (this is not accurate)
2391 u32 bytes_per_bunch = 5000;
2393 std::vector< std::vector<SendableMedia> > file_bunches;
2394 file_bunches.emplace_back();
2396 u32 file_size_bunch_total = 0;
2398 for (const std::string &name : tosend) {
2399 if (m_media.find(name) == m_media.end()) {
2400 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2401 <<"unknown file \""<<(name)<<"\""<<std::endl;
2405 //TODO get path + name
2406 std::string tpath = m_media[name].path;
2409 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2411 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2412 <<tpath<<"\" for reading"<<std::endl;
2415 std::ostringstream tmp_os(std::ios_base::binary);
2419 fis.read(buf, 1024);
2420 std::streamsize len = fis.gcount();
2421 tmp_os.write(buf, len);
2422 file_size_bunch_total += len;
2431 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2432 <<name<<"\""<<std::endl;
2435 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2436 <<tname<<"\""<<std::endl;*/
2438 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2440 // Start next bunch if got enough data
2441 if(file_size_bunch_total >= bytes_per_bunch) {
2442 file_bunches.emplace_back();
2443 file_size_bunch_total = 0;
2448 /* Create and send packets */
2450 u16 num_bunches = file_bunches.size();
2451 for (u16 i = 0; i < num_bunches; i++) {
2454 u16 total number of texture bunches
2455 u16 index of this bunch
2456 u32 number of files in this bunch
2465 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2466 pkt << num_bunches << i << (u32) file_bunches[i].size();
2468 for (const SendableMedia &j : file_bunches[i]) {
2470 pkt.putLongString(j.data);
2473 verbosestream << "Server::sendRequestedMedia(): bunch "
2474 << i << "/" << num_bunches
2475 << " files=" << file_bunches[i].size()
2476 << " size=" << pkt.getSize() << std::endl;
2481 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2483 if(m_detached_inventories.count(name) == 0) {
2484 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2487 Inventory *inv = m_detached_inventories[name];
2488 std::ostringstream os(std::ios_base::binary);
2490 os << serializeString(name);
2494 std::string s = os.str();
2496 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2497 pkt.putRawString(s.c_str(), s.size());
2499 const std::string &check = m_detached_inventories_player[name];
2500 if (peer_id == PEER_ID_INEXISTENT) {
2502 return m_clients.sendToAll(&pkt);
2503 RemotePlayer *p = m_env->getPlayer(check.c_str());
2505 m_clients.send(p->peer_id, 0, &pkt, true);
2507 if (check.empty() || getPlayerName(peer_id) == check)
2512 void Server::sendDetachedInventories(session_t peer_id)
2514 for (const auto &detached_inventory : m_detached_inventories) {
2515 const std::string &name = detached_inventory.first;
2516 //Inventory *inv = i->second;
2517 sendDetachedInventory(name, peer_id);
2525 void Server::DiePlayer(session_t peer_id)
2527 PlayerSAO *playersao = getPlayerSAO(peer_id);
2528 // In some rare cases this can be NULL -- if the player is disconnected
2529 // when a Lua function modifies l_punch, for example
2533 infostream << "Server::DiePlayer(): Player "
2534 << playersao->getPlayer()->getName()
2535 << " dies" << std::endl;
2537 playersao->setHP(0);
2539 // Trigger scripted stuff
2540 m_script->on_dieplayer(playersao);
2542 SendPlayerHP(peer_id);
2543 SendDeathscreen(peer_id, false, v3f(0,0,0));
2546 void Server::RespawnPlayer(session_t peer_id)
2548 PlayerSAO *playersao = getPlayerSAO(peer_id);
2551 infostream << "Server::RespawnPlayer(): Player "
2552 << playersao->getPlayer()->getName()
2553 << " respawns" << std::endl;
2555 playersao->setHP(playersao->accessObjectProperties()->hp_max);
2556 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2558 bool repositioned = m_script->on_respawnplayer(playersao);
2559 if (!repositioned) {
2560 // setPos will send the new position to client
2561 playersao->setPos(findSpawnPos());
2564 SendPlayerHP(peer_id);
2568 void Server::DenySudoAccess(session_t peer_id)
2570 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2575 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2576 const std::string &str_reason, bool reconnect)
2578 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2580 m_clients.event(peer_id, CSE_SetDenied);
2581 DisconnectPeer(peer_id);
2585 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2586 const std::string &custom_reason)
2588 SendAccessDenied(peer_id, reason, custom_reason);
2589 m_clients.event(peer_id, CSE_SetDenied);
2590 DisconnectPeer(peer_id);
2593 // 13/03/15: remove this function when protocol version 25 will become
2594 // the minimum version for MT users, maybe in 1 year
2595 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2597 SendAccessDenied_Legacy(peer_id, reason);
2598 m_clients.event(peer_id, CSE_SetDenied);
2599 DisconnectPeer(peer_id);
2602 void Server::DisconnectPeer(session_t peer_id)
2604 m_modchannel_mgr->leaveAllChannels(peer_id);
2605 m_con->DisconnectPeer(peer_id);
2608 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2611 RemoteClient* client = getClient(peer_id, CS_Invalid);
2613 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2615 // Right now, the auth mechs don't change between login and sudo mode.
2616 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2617 client->allowed_sudo_mechs = sudo_auth_mechs;
2619 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2620 << g_settings->getFloat("dedicated_server_step")
2624 m_clients.event(peer_id, CSE_AuthAccept);
2626 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2628 // We only support SRP right now
2629 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2631 resp_pkt << sudo_auth_mechs;
2633 m_clients.event(peer_id, CSE_SudoSuccess);
2637 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2639 std::wstring message;
2642 Clear references to playing sounds
2644 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2645 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2646 ServerPlayingSound &psound = i->second;
2647 psound.clients.erase(peer_id);
2648 if (psound.clients.empty())
2649 m_playing_sounds.erase(i++);
2654 RemotePlayer *player = m_env->getPlayer(peer_id);
2656 /* Run scripts and remove from environment */
2658 PlayerSAO *playersao = player->getPlayerSAO();
2661 // inform connected clients
2662 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2663 // (u16) 1 + std::string represents a vector serialization representation
2664 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2665 m_clients.sendToAll(¬ice);
2667 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2669 playersao->disconnected();
2676 if (player && reason != CDR_DENY) {
2677 std::ostringstream os(std::ios_base::binary);
2678 std::vector<u16> clients = m_clients.getClientIDs();
2680 for (const u16 client_id : clients) {
2682 RemotePlayer *player = m_env->getPlayer(client_id);
2686 // Get name of player
2687 os << player->getName() << " ";
2690 std::string name = player->getName();
2691 actionstream << name << " "
2692 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2693 << " List of players: " << os.str() << std::endl;
2695 m_admin_chat->outgoing_queue.push_back(
2696 new ChatEventNick(CET_NICK_REMOVE, name));
2700 MutexAutoLock env_lock(m_env_mutex);
2701 m_clients.DeleteClient(peer_id);
2705 // Send leave chat message to all remaining clients
2706 if (!message.empty()) {
2707 SendChatMessage(PEER_ID_INEXISTENT,
2708 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2712 void Server::UpdateCrafting(RemotePlayer *player)
2714 // Get a preview for crafting
2716 InventoryLocation loc;
2717 loc.setPlayer(player->getName());
2718 std::vector<ItemStack> output_replacements;
2719 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2720 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2721 (&player->inventory)->getList("craft"), loc);
2723 // Put the new preview in
2724 InventoryList *plist = player->inventory.getList("craftpreview");
2725 sanity_check(plist);
2726 sanity_check(plist->getSize() >= 1);
2727 plist->changeItem(0, preview);
2730 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2732 if (evt->type == CET_NICK_ADD) {
2733 // The terminal informed us of its nick choice
2734 m_admin_nick = ((ChatEventNick *)evt)->nick;
2735 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2736 errorstream << "You haven't set up an account." << std::endl
2737 << "Please log in using the client as '"
2738 << m_admin_nick << "' with a secure password." << std::endl
2739 << "Until then, you can't execute admin tasks via the console," << std::endl
2740 << "and everybody can claim the user account instead of you," << std::endl
2741 << "giving them full control over this server." << std::endl;
2744 assert(evt->type == CET_CHAT);
2745 handleAdminChat((ChatEventChat *)evt);
2749 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2750 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2752 // If something goes wrong, this player is to blame
2753 RollbackScopeActor rollback_scope(m_rollback,
2754 std::string("player:") + name);
2756 if (g_settings->getBool("strip_color_codes"))
2757 wmessage = unescape_enriched(wmessage);
2760 switch (player->canSendChatMessage()) {
2761 case RPLAYER_CHATRESULT_FLOODING: {
2762 std::wstringstream ws;
2763 ws << L"You cannot send more messages. You are limited to "
2764 << g_settings->getFloat("chat_message_limit_per_10sec")
2765 << L" messages per 10 seconds.";
2768 case RPLAYER_CHATRESULT_KICK:
2769 DenyAccess_Legacy(player->peer_id,
2770 L"You have been kicked due to message flooding.");
2772 case RPLAYER_CHATRESULT_OK:
2775 FATAL_ERROR("Unhandled chat filtering result found.");
2779 if (m_max_chatmessage_length > 0
2780 && wmessage.length() > m_max_chatmessage_length) {
2781 return L"Your message exceed the maximum chat message limit set on the server. "
2782 L"It was refused. Send a shorter message";
2785 // Run script hook, exit if script ate the chat message
2786 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2791 // Whether to send line to the player that sent the message, or to all players
2792 bool broadcast_line = true;
2794 if (check_shout_priv && !checkPriv(name, "shout")) {
2795 line += L"-!- You don't have permission to shout.";
2796 broadcast_line = false;
2805 Tell calling method to send the message to sender
2807 if (!broadcast_line)
2811 Send the message to others
2813 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2815 std::vector<u16> clients = m_clients.getClientIDs();
2818 Send the message back to the inital sender
2819 if they are using protocol version >= 29
2822 session_t peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2823 if (player && player->protocol_version >= 29)
2824 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2826 for (u16 cid : clients) {
2827 if (cid != peer_id_to_avoid_sending)
2828 SendChatMessage(cid, ChatMessage(line));
2833 void Server::handleAdminChat(const ChatEventChat *evt)
2835 std::string name = evt->nick;
2836 std::wstring wname = utf8_to_wide(name);
2837 std::wstring wmessage = evt->evt_msg;
2839 std::wstring answer = handleChat(name, wname, wmessage);
2841 // If asked to send answer to sender
2842 if (!answer.empty()) {
2843 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2847 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2849 RemoteClient *client = getClientNoEx(peer_id,state_min);
2851 throw ClientNotFoundException("Client not found");
2855 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2857 return m_clients.getClientNoEx(peer_id, state_min);
2860 std::string Server::getPlayerName(session_t peer_id)
2862 RemotePlayer *player = m_env->getPlayer(peer_id);
2864 return "[id="+itos(peer_id)+"]";
2865 return player->getName();
2868 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2870 RemotePlayer *player = m_env->getPlayer(peer_id);
2873 return player->getPlayerSAO();
2876 std::wstring Server::getStatusString()
2878 std::wostringstream os(std::ios_base::binary);
2881 os<<L"version="<<narrow_to_wide(g_version_string);
2883 os<<L", uptime="<<m_uptime.get();
2885 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2886 // Information about clients
2889 std::vector<u16> clients = m_clients.getClientIDs();
2890 for (u16 client_id : clients) {
2892 RemotePlayer *player = m_env->getPlayer(client_id);
2893 // Get name of player
2894 std::wstring name = L"unknown";
2896 name = narrow_to_wide(player->getName());
2897 // Add name to information string
2906 if (!((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
2907 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2909 if (!g_settings->get("motd").empty())
2910 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2914 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2916 std::set<std::string> privs;
2917 m_script->getAuth(name, NULL, &privs);
2921 bool Server::checkPriv(const std::string &name, const std::string &priv)
2923 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2924 return (privs.count(priv) != 0);
2927 void Server::reportPrivsModified(const std::string &name)
2930 std::vector<u16> clients = m_clients.getClientIDs();
2931 for (const u16 client_id : clients) {
2932 RemotePlayer *player = m_env->getPlayer(client_id);
2933 reportPrivsModified(player->getName());
2936 RemotePlayer *player = m_env->getPlayer(name.c_str());
2939 SendPlayerPrivileges(player->peer_id);
2940 PlayerSAO *sao = player->getPlayerSAO();
2943 sao->updatePrivileges(
2944 getPlayerEffectivePrivs(name),
2949 void Server::reportInventoryFormspecModified(const std::string &name)
2951 RemotePlayer *player = m_env->getPlayer(name.c_str());
2954 SendPlayerInventoryFormspec(player->peer_id);
2957 void Server::setIpBanned(const std::string &ip, const std::string &name)
2959 m_banmanager->add(ip, name);
2962 void Server::unsetIpBanned(const std::string &ip_or_name)
2964 m_banmanager->remove(ip_or_name);
2967 std::string Server::getBanDescription(const std::string &ip_or_name)
2969 return m_banmanager->getBanDescription(ip_or_name);
2972 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2974 // m_env will be NULL if the server is initializing
2978 if (m_admin_nick == name && !m_admin_nick.empty()) {
2979 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2982 RemotePlayer *player = m_env->getPlayer(name);
2987 if (player->peer_id == PEER_ID_INEXISTENT)
2990 SendChatMessage(player->peer_id, ChatMessage(msg));
2993 bool Server::showFormspec(const char *playername, const std::string &formspec,
2994 const std::string &formname)
2996 // m_env will be NULL if the server is initializing
3000 RemotePlayer *player = m_env->getPlayer(playername);
3004 SendShowFormspecMessage(player->peer_id, formspec, formname);
3008 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3013 u32 id = player->addHud(form);
3015 SendHUDAdd(player->peer_id, id, form);
3020 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3024 HudElement* todel = player->removeHud(id);
3031 SendHUDRemove(player->peer_id, id);
3035 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3040 SendHUDChange(player->peer_id, id, stat, data);
3044 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3049 SendHUDSetFlags(player->peer_id, flags, mask);
3050 player->hud_flags &= ~mask;
3051 player->hud_flags |= flags;
3053 PlayerSAO* playersao = player->getPlayerSAO();
3058 m_script->player_event(playersao, "hud_changed");
3062 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3067 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3070 player->setHotbarItemcount(hotbar_itemcount);
3071 std::ostringstream os(std::ios::binary);
3072 writeS32(os, hotbar_itemcount);
3073 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3077 s32 Server::hudGetHotbarItemcount(RemotePlayer *player) const
3079 return player->getHotbarItemcount();
3082 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3087 player->setHotbarImage(name);
3088 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3091 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3095 return player->getHotbarImage();
3098 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3103 player->setHotbarSelectedImage(name);
3104 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3107 const std::string& Server::hudGetHotbarSelectedImage(RemotePlayer *player) const
3109 return player->getHotbarSelectedImage();
3112 Address Server::getPeerAddress(session_t peer_id)
3114 return m_con->GetPeerAddress(peer_id);
3117 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3118 v2s32 animation_frames[4], f32 frame_speed)
3123 player->setLocalAnimations(animation_frames, frame_speed);
3124 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3128 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3133 player->eye_offset_first = first;
3134 player->eye_offset_third = third;
3135 SendEyeOffset(player->peer_id, first, third);
3139 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3140 const std::string &type, const std::vector<std::string> ¶ms,
3146 player->setSky(bgcolor, type, params, clouds);
3147 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3151 bool Server::setClouds(RemotePlayer *player, float density,
3152 const video::SColor &color_bright,
3153 const video::SColor &color_ambient,
3161 SendCloudParams(player->peer_id, density,
3162 color_bright, color_ambient, height,
3167 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3173 player->overrideDayNightRatio(do_override, ratio);
3174 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3178 void Server::notifyPlayers(const std::wstring &msg)
3180 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3183 void Server::spawnParticle(const std::string &playername, v3f pos,
3184 v3f velocity, v3f acceleration,
3185 float expirationtime, float size, bool
3186 collisiondetection, bool collision_removal,
3187 bool vertical, const std::string &texture,
3188 const struct TileAnimationParams &animation, u8 glow)
3190 // m_env will be NULL if the server is initializing
3194 session_t peer_id = PEER_ID_INEXISTENT;
3196 if (!playername.empty()) {
3197 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3200 peer_id = player->peer_id;
3201 proto_ver = player->protocol_version;
3204 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3205 expirationtime, size, collisiondetection,
3206 collision_removal, vertical, texture, animation, glow);
3209 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3210 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3211 float minexptime, float maxexptime, float minsize, float maxsize,
3212 bool collisiondetection, bool collision_removal,
3213 ServerActiveObject *attached, bool vertical, const std::string &texture,
3214 const std::string &playername, const struct TileAnimationParams &animation,
3217 // m_env will be NULL if the server is initializing
3221 session_t peer_id = PEER_ID_INEXISTENT;
3223 if (!playername.empty()) {
3224 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3227 peer_id = player->peer_id;
3228 proto_ver = player->protocol_version;
3231 u16 attached_id = attached ? attached->getId() : 0;
3234 if (attached_id == 0)
3235 id = m_env->addParticleSpawner(spawntime);
3237 id = m_env->addParticleSpawner(spawntime, attached_id);
3239 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3240 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3241 minexptime, maxexptime, minsize, maxsize,
3242 collisiondetection, collision_removal, attached_id, vertical,
3243 texture, id, animation, glow);
3248 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3250 // m_env will be NULL if the server is initializing
3252 throw ServerError("Can't delete particle spawners during initialisation!");
3254 session_t peer_id = PEER_ID_INEXISTENT;
3255 if (!playername.empty()) {
3256 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3259 peer_id = player->peer_id;
3262 m_env->deleteParticleSpawner(id);
3263 SendDeleteParticleSpawner(peer_id, id);
3266 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3268 if(m_detached_inventories.count(name) > 0){
3269 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3270 delete m_detached_inventories[name];
3272 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3274 Inventory *inv = new Inventory(m_itemdef);
3276 m_detached_inventories[name] = inv;
3277 m_detached_inventories_player[name] = player;
3278 //TODO find a better way to do this
3279 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3283 // actions: time-reversed list
3284 // Return value: success/failure
3285 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3286 std::list<std::string> *log)
3288 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3289 ServerMap *map = (ServerMap*)(&m_env->getMap());
3291 // Fail if no actions to handle
3292 if(actions.empty()){
3293 log->push_back("Nothing to do.");
3300 for (const RollbackAction &action : actions) {
3302 bool success = action.applyRevert(map, this, this);
3305 std::ostringstream os;
3306 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3307 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3309 log->push_back(os.str());
3311 std::ostringstream os;
3312 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3313 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3315 log->push_back(os.str());
3319 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3320 <<" failed"<<std::endl;
3322 // Call it done if less than half failed
3323 return num_failed <= num_tried/2;
3326 // IGameDef interface
3328 IItemDefManager *Server::getItemDefManager()
3333 INodeDefManager *Server::getNodeDefManager()
3338 ICraftDefManager *Server::getCraftDefManager()
3343 u16 Server::allocateUnknownNodeId(const std::string &name)
3345 return m_nodedef->allocateDummy(name);
3348 MtEventManager *Server::getEventManager()
3353 IWritableItemDefManager *Server::getWritableItemDefManager()
3358 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3363 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3368 const ModSpec *Server::getModSpec(const std::string &modname) const
3370 std::vector<ModSpec>::const_iterator it;
3371 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3372 const ModSpec &mod = *it;
3373 if (mod.name == modname)
3379 void Server::getModNames(std::vector<std::string> &modlist)
3381 std::vector<ModSpec>::iterator it;
3382 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3383 modlist.push_back(it->name);
3386 std::string Server::getBuiltinLuaPath()
3388 return porting::path_share + DIR_DELIM + "builtin";
3391 std::string Server::getModStoragePath() const
3393 return m_path_world + DIR_DELIM + "mod_storage";
3396 v3f Server::findSpawnPos()
3398 ServerMap &map = m_env->getServerMap();
3400 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3401 return nodeposf * BS;
3404 bool is_good = false;
3405 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3406 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3408 // Try to find a good place a few times
3409 for(s32 i = 0; i < 4000 && !is_good; i++) {
3410 s32 range = MYMIN(1 + i, range_max);
3411 // We're going to try to throw the player to this position
3412 v2s16 nodepos2d = v2s16(
3413 -range + (myrand() % (range * 2)),
3414 -range + (myrand() % (range * 2)));
3416 // Get spawn level at point
3417 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3418 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3419 // the mapgen to signify an unsuitable spawn position
3420 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3423 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3426 for (s32 i = 0; i < 10; i++) {
3427 v3s16 blockpos = getNodeBlockPos(nodepos);
3428 map.emergeBlock(blockpos, true);
3429 content_t c = map.getNodeNoEx(nodepos).getContent();
3430 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3432 if (air_count >= 2) {
3433 nodeposf = intToFloat(nodepos, BS);
3434 // Don't spawn the player outside map boundaries
3435 if (objectpos_over_limit(nodeposf))
3448 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3450 m_shutdown_timer = delay;
3451 m_shutdown_msg = msg;
3452 m_shutdown_ask_reconnect = reconnect;
3454 if (delay == 0.0f) {
3455 // No delay, shutdown immediately
3456 m_shutdown_requested = true;
3457 // only print to the infostream, a chat message saying
3458 // "Server Shutting Down" is sent when the server destructs.
3459 infostream << "*** Immediate Server shutdown requested." << std::endl;
3460 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3461 // Negative delay, cancel shutdown if requested
3462 m_shutdown_timer = 0.0f;
3463 m_shutdown_msg = "";
3464 m_shutdown_ask_reconnect = false;
3465 m_shutdown_requested = false;
3466 std::wstringstream ws;
3468 ws << L"*** Server shutdown canceled.";
3470 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3471 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3472 } else if (delay > 0.0f) {
3473 // Positive delay, tell the clients when the server will shut down
3474 std::wstringstream ws;
3476 ws << L"*** Server shutting down in "
3477 << duration_to_string(myround(m_shutdown_timer)).c_str()
3480 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3481 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3485 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3488 Try to get an existing player
3490 RemotePlayer *player = m_env->getPlayer(name);
3492 // If player is already connected, cancel
3493 if (player && player->peer_id != 0) {
3494 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3499 If player with the wanted peer_id already exists, cancel.
3501 if (m_env->getPlayer(peer_id)) {
3502 infostream<<"emergePlayer(): Player with wrong name but same"
3503 " peer_id already exists"<<std::endl;
3508 player = new RemotePlayer(name, idef());
3511 bool newplayer = false;
3514 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3516 // Complete init with server parts
3517 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3518 player->protocol_version = proto_version;
3522 m_script->on_newplayer(playersao);
3528 bool Server::registerModStorage(ModMetadata *storage)
3530 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3531 errorstream << "Unable to register same mod storage twice. Storage name: "
3532 << storage->getModName() << std::endl;
3536 m_mod_storages[storage->getModName()] = storage;
3540 void Server::unregisterModStorage(const std::string &name)
3542 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3543 if (it != m_mod_storages.end()) {
3544 // Save unconditionaly on unregistration
3545 it->second->save(getModStoragePath());
3546 m_mod_storages.erase(name);
3550 void dedicated_server_loop(Server &server, bool &kill)
3552 verbosestream<<"dedicated_server_loop()"<<std::endl;
3554 IntervalLimiter m_profiler_interval;
3556 static thread_local const float steplen =
3557 g_settings->getFloat("dedicated_server_step");
3558 static thread_local const float profiler_print_interval =
3559 g_settings->getFloat("profiler_print_interval");
3562 // This is kind of a hack but can be done like this
3563 // because server.step() is very light
3565 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3566 sleep_ms((int)(steplen*1000.0));
3568 server.step(steplen);
3570 if (server.getShutdownRequested() || kill)
3576 if (profiler_print_interval != 0) {
3577 if(m_profiler_interval.step(steplen, profiler_print_interval))
3579 infostream<<"Profiler:"<<std::endl;
3580 g_profiler->print(infostream);
3581 g_profiler->clear();
3586 infostream << "Dedicated server quitting" << std::endl;
3588 if (g_settings->getBool("server_announce"))
3589 ServerList::sendAnnounce(ServerList::AA_DELETE,
3590 server.m_bind_addr.getPort());
3599 bool Server::joinModChannel(const std::string &channel)
3601 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3602 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3605 bool Server::leaveModChannel(const std::string &channel)
3607 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3610 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3612 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3615 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3619 ModChannel* Server::getModChannel(const std::string &channel)
3621 return m_modchannel_mgr->getModChannel(channel);
3624 void Server::broadcastModChannelMessage(const std::string &channel,
3625 const std::string &message, u16 from_peer)
3627 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3631 if (message.size() > STRING_MAX_LEN) {
3632 warningstream << "ModChannel message too long, dropping before sending "
3633 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3634 << channel << ")" << std::endl;
3639 if (from_peer != PEER_ID_SERVER) {
3640 sender = getPlayerName(from_peer);
3643 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3644 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3645 resp_pkt << channel << sender << message;
3646 for (session_t peer_id : peers) {
3648 if (peer_id == from_peer)
3651 Send(peer_id, &resp_pkt);
3654 if (from_peer != PEER_ID_SERVER) {
3655 m_script->on_modchannel_message(channel, sender, message);