3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_server.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_sao.h"
52 #include "event_manager.h"
53 #include "serverlist.h"
54 #include "util/string.h"
56 #include "util/serialize.h"
57 #include "util/thread.h"
58 #include "defaultsettings.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public Thread
79 ServerThread(Server *server):
90 void *ServerThread::run()
92 DSTACK(FUNCTION_NAME);
93 BEGIN_DEBUG_EXCEPTION_HANDLER
95 m_server->AsyncRunStep(true);
97 while (!stopRequested()) {
99 m_server->AsyncRunStep();
103 } catch (con::NoIncomingDataException &e) {
104 } catch (con::PeerNotFoundException &e) {
105 infostream<<"Server: PeerNotFoundException"<<std::endl;
106 } catch (ClientNotFoundException &e) {
107 } catch (con::ConnectionBindFailed &e) {
108 m_server->setAsyncFatalError(e.what());
109 } catch (LuaError &e) {
110 m_server->setAsyncFatalError(
111 "ServerThread::run Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
155 m_path_world(path_world),
156 m_gamespec(gamespec),
157 m_simple_singleplayer_mode(simple_singleplayer_mode),
158 m_dedicated(dedicated),
159 m_async_fatal_error(""),
165 m_itemdef(createItemDefManager()),
166 m_nodedef(createNodeDefManager()),
167 m_craftdef(createCraftDefManager()),
168 m_event(new EventManager()),
173 m_lag = g_settings->getFloat("dedicated_server_step");
175 if (path_world.empty())
176 throw ServerError("Supplied empty world path");
178 if(!gamespec.isValid())
179 throw ServerError("Supplied invalid gamespec");
181 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
182 if(m_simple_singleplayer_mode)
183 infostream<<" in simple singleplayer mode"<<std::endl;
185 infostream<<std::endl;
186 infostream<<"- world: "<<m_path_world<<std::endl;
187 infostream<<"- game: "<<m_gamespec.path<<std::endl;
189 // Create world if it doesn't exist
190 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
191 throw ServerError("Failed to initialize world");
193 // Create server thread
194 m_thread = new ServerThread(this);
196 // Create emerge manager
197 m_emerge = new EmergeManager(this);
199 // Create ban manager
200 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
201 m_banmanager = new BanManager(ban_path);
203 ServerModConfiguration modconf(m_path_world);
204 m_mods = modconf.getMods();
205 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
206 // complain about mods with unsatisfied dependencies
207 if (!modconf.isConsistent()) {
208 modconf.printUnsatisfiedModsError();
212 MutexAutoLock envlock(m_env_mutex);
214 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
215 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
217 // Initialize scripting
218 infostream<<"Server: Initializing Lua"<<std::endl;
220 m_script = new ServerScripting(this);
222 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
225 infostream << "Server: Loading mods: ";
226 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
227 i != m_mods.end(); ++i) {
228 infostream << (*i).name << " ";
230 infostream << std::endl;
231 // Load and run "mod" scripts
232 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
233 it != m_mods.end(); ++it) {
234 const ModSpec &mod = *it;
235 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
236 throw ModError("Error loading mod \"" + mod.name +
237 "\": Mod name does not follow naming conventions: "
238 "Only characters [a-z0-9_] are allowed.");
240 std::string script_path = mod.path + DIR_DELIM + "init.lua";
241 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
242 << script_path << "\"]" << std::endl;
243 m_script->loadMod(script_path, mod.name);
246 // Read Textures and calculate sha1 sums
249 // Apply item aliases in the node definition manager
250 m_nodedef->updateAliases(m_itemdef);
252 // Apply texture overrides from texturepack/override.txt
253 std::string texture_path = g_settings->get("texture_path");
254 if (!texture_path.empty() && fs::IsDir(texture_path))
255 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
257 m_nodedef->setNodeRegistrationStatus(true);
259 // Perform pending node name resolutions
260 m_nodedef->runNodeResolveCallbacks();
262 // unmap node names for connected nodeboxes
263 m_nodedef->mapNodeboxConnections();
265 // init the recipe hashes to speed up crafting
266 m_craftdef->initHashes(this);
268 // Initialize Environment
269 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
271 m_clients.setEnv(m_env);
273 if (!servermap->settings_mgr.makeMapgenParams())
274 FATAL_ERROR("Couldn't create any mapgen type");
276 // Initialize mapgens
277 m_emerge->initMapgens(servermap->getMapgenParams());
279 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
280 if (m_enable_rollback_recording) {
281 // Create rollback manager
282 m_rollback = new RollbackManager(m_path_world, this);
285 // Give environment reference to scripting api
286 m_script->initializeEnvironment(m_env);
288 // Register us to receive map edit events
289 servermap->addEventReceiver(this);
291 // If file exists, load environment metadata
292 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
293 infostream << "Server: Loading environment metadata" << std::endl;
296 m_env->loadDefaultMeta();
299 m_liquid_transform_every = g_settings->getFloat("liquid_update");
300 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
301 m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
302 m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
307 infostream<<"Server destructing"<<std::endl;
309 // Send shutdown message
310 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
311 L"*** Server shutting down"));
314 MutexAutoLock envlock(m_env_mutex);
316 // Execute script shutdown hooks
317 m_script->on_shutdown();
319 infostream << "Server: Saving players" << std::endl;
320 m_env->saveLoadedPlayers();
322 infostream << "Server: Kicking players" << std::endl;
323 std::string kick_msg;
324 bool reconnect = false;
325 if (getShutdownRequested()) {
326 reconnect = m_shutdown_ask_reconnect;
327 kick_msg = m_shutdown_msg;
329 if (kick_msg.empty()) {
330 kick_msg = g_settings->get("kick_msg_shutdown");
332 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
333 kick_msg, reconnect);
335 infostream << "Server: Saving environment metadata" << std::endl;
343 // stop all emerge threads before deleting players that may have
344 // requested blocks to be emerged
345 m_emerge->stopThreads();
347 // Delete things in the reverse order of creation
357 // Deinitialize scripting
358 infostream<<"Server: Deinitializing scripting"<<std::endl;
361 // Delete detached inventories
362 for (auto &detached_inventory : m_detached_inventories) {
363 delete detached_inventory.second;
367 void Server::start(Address bind_addr)
369 DSTACK(FUNCTION_NAME);
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 DSTACK(FUNCTION_NAME);
404 infostream<<"Server: Stopping and waiting threads"<<std::endl;
406 // Stop threads (set run=false first so both start stopping)
408 //m_emergethread.setRun(false);
410 //m_emergethread.stop();
412 infostream<<"Server: Threads stopped"<<std::endl;
415 void Server::step(float dtime)
417 DSTACK(FUNCTION_NAME);
422 MutexAutoLock lock(m_step_dtime_mutex);
423 m_step_dtime += dtime;
425 // Throw if fatal error occurred in thread
426 std::string async_err = m_async_fatal_error.get();
427 if (!async_err.empty()) {
428 if (!m_simple_singleplayer_mode) {
429 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
430 g_settings->get("kick_msg_crash"),
431 g_settings->getBool("ask_reconnect_on_crash"));
433 throw ServerError("AsyncErr: " + async_err);
437 void Server::AsyncRunStep(bool initial_step)
439 DSTACK(FUNCTION_NAME);
441 g_profiler->add("Server::AsyncRunStep (num)", 1);
445 MutexAutoLock lock1(m_step_dtime_mutex);
446 dtime = m_step_dtime;
450 // Send blocks to clients
454 if((dtime < 0.001) && !initial_step)
457 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
459 //infostream<<"Server steps "<<dtime<<std::endl;
460 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
463 MutexAutoLock lock1(m_step_dtime_mutex);
464 m_step_dtime -= dtime;
471 m_uptime.set(m_uptime.get() + dtime);
477 Update time of day and overall game time
479 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
482 Send to clients at constant intervals
485 m_time_of_day_send_timer -= dtime;
486 if(m_time_of_day_send_timer < 0.0) {
487 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
488 u16 time = m_env->getTimeOfDay();
489 float time_speed = g_settings->getFloat("time_speed");
490 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
494 MutexAutoLock lock(m_env_mutex);
495 // Figure out and report maximum lag to environment
496 float max_lag = m_env->getMaxLagEstimate();
497 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
499 if(dtime > 0.1 && dtime > max_lag * 2.0)
500 infostream<<"Server: Maximum lag peaked to "<<dtime
504 m_env->reportMaxLagEstimate(max_lag);
506 ScopeProfiler sp(g_profiler, "SEnv step");
507 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
511 static const float map_timer_and_unload_dtime = 2.92;
512 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
514 MutexAutoLock lock(m_env_mutex);
515 // Run Map's timers and unload unused data
516 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
517 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
518 g_settings->getFloat("server_unload_unused_data_timeout"),
523 Listen to the admin chat, if available
526 if (!m_admin_chat->command_queue.empty()) {
527 MutexAutoLock lock(m_env_mutex);
528 while (!m_admin_chat->command_queue.empty()) {
529 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
530 handleChatInterfaceEvent(evt);
534 m_admin_chat->outgoing_queue.push_back(
535 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
542 /* Transform liquids */
543 m_liquid_transform_timer += dtime;
544 if(m_liquid_transform_timer >= m_liquid_transform_every)
546 m_liquid_transform_timer -= m_liquid_transform_every;
548 MutexAutoLock lock(m_env_mutex);
550 ScopeProfiler sp(g_profiler, "Server: liquid transform");
552 std::map<v3s16, MapBlock*> modified_blocks;
553 m_env->getMap().transformLiquids(modified_blocks, m_env);
556 Set the modified blocks unsent for all the clients
558 if(!modified_blocks.empty())
560 SetBlocksNotSent(modified_blocks);
563 m_clients.step(dtime);
565 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
567 // send masterserver announce
569 float &counter = m_masterserver_timer;
570 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
571 g_settings->getBool("server_announce")) {
572 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
573 ServerList::AA_START,
574 m_bind_addr.getPort(),
575 m_clients.getPlayerNames(),
577 m_env->getGameTime(),
580 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
590 Check added and deleted active objects
593 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
594 MutexAutoLock envlock(m_env_mutex);
597 const RemoteClientMap &clients = m_clients.getClientList();
598 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
600 // Radius inside which objects are active
601 static thread_local const s16 radius =
602 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
604 // Radius inside which players are active
605 static thread_local const bool is_transfer_limited =
606 g_settings->exists("unlimited_player_transfer_distance") &&
607 !g_settings->getBool("unlimited_player_transfer_distance");
608 static thread_local const s16 player_transfer_dist =
609 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
610 s16 player_radius = player_transfer_dist;
611 if (player_radius == 0 && is_transfer_limited)
612 player_radius = radius;
614 for (const auto &client_it : clients) {
615 RemoteClient *client = client_it.second;
617 // If definitions and textures have not been sent, don't
618 // send objects either
619 if (client->getState() < CS_DefinitionsSent)
622 RemotePlayer *player = m_env->getPlayer(client->peer_id);
624 // This can happen if the client timeouts somehow
628 PlayerSAO *playersao = player->getPlayerSAO();
632 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
633 if (my_radius <= 0) my_radius = radius;
634 //infostream << "Server: Active Radius " << my_radius << std::endl;
636 std::queue<u16> removed_objects;
637 std::queue<u16> added_objects;
638 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
639 client->m_known_objects, removed_objects);
640 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
641 client->m_known_objects, added_objects);
643 // Ignore if nothing happened
644 if (removed_objects.empty() && added_objects.empty()) {
648 std::string data_buffer;
652 // Handle removed objects
653 writeU16((u8*)buf, removed_objects.size());
654 data_buffer.append(buf, 2);
655 while (!removed_objects.empty()) {
657 u16 id = removed_objects.front();
658 ServerActiveObject* obj = m_env->getActiveObject(id);
660 // Add to data buffer for sending
661 writeU16((u8*)buf, id);
662 data_buffer.append(buf, 2);
664 // Remove from known objects
665 client->m_known_objects.erase(id);
667 if(obj && obj->m_known_by_count > 0)
668 obj->m_known_by_count--;
669 removed_objects.pop();
672 // Handle added objects
673 writeU16((u8*)buf, added_objects.size());
674 data_buffer.append(buf, 2);
675 while (!added_objects.empty()) {
677 u16 id = added_objects.front();
678 ServerActiveObject* obj = m_env->getActiveObject(id);
681 u8 type = ACTIVEOBJECT_TYPE_INVALID;
683 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
685 type = obj->getSendType();
687 // Add to data buffer for sending
688 writeU16((u8*)buf, id);
689 data_buffer.append(buf, 2);
690 writeU8((u8*)buf, type);
691 data_buffer.append(buf, 1);
694 data_buffer.append(serializeLongString(
695 obj->getClientInitializationData(client->net_proto_version)));
697 data_buffer.append(serializeLongString(""));
699 // Add to known objects
700 client->m_known_objects.insert(id);
703 obj->m_known_by_count++;
708 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
709 verbosestream << "Server: Sent object remove/add: "
710 << removed_objects.size() << " removed, "
711 << added_objects.size() << " added, "
712 << "packet size is " << pktSize << std::endl;
716 m_mod_storage_save_timer -= dtime;
717 if (m_mod_storage_save_timer <= 0.0f) {
718 infostream << "Saving registered mod storages." << std::endl;
719 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
720 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
721 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
722 if (it->second->isModified()) {
723 it->second->save(getModStoragePath());
733 MutexAutoLock envlock(m_env_mutex);
734 ScopeProfiler sp(g_profiler, "Server: sending object messages");
737 // Value = data sent by object
738 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
740 // Get active object messages from environment
742 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
746 std::vector<ActiveObjectMessage>* message_list = nullptr;
747 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
748 n = buffered_messages.find(aom.id);
749 if (n == buffered_messages.end()) {
750 message_list = new std::vector<ActiveObjectMessage>;
751 buffered_messages[aom.id] = message_list;
754 message_list = n->second;
756 message_list->push_back(aom);
760 const RemoteClientMap &clients = m_clients.getClientList();
761 // Route data to every client
762 for (const auto &client_it : clients) {
763 RemoteClient *client = client_it.second;
764 std::string reliable_data;
765 std::string unreliable_data;
766 // Go through all objects in message buffer
767 for (const auto &buffered_message : buffered_messages) {
768 // If object is not known by client, skip it
769 u16 id = buffered_message.first;
770 if (client->m_known_objects.find(id) == client->m_known_objects.end())
773 // Get message list of object
774 std::vector<ActiveObjectMessage>* list = buffered_message.second;
775 // Go through every message
776 for (const ActiveObjectMessage &aom : *list) {
777 // Compose the full new data with header
778 std::string new_data;
781 writeU16((u8*)&buf[0], aom.id);
782 new_data.append(buf, 2);
784 new_data += serializeString(aom.datastring);
785 // Add data to buffer
787 reliable_data += new_data;
789 unreliable_data += new_data;
793 reliable_data and unreliable_data are now ready.
796 if (!reliable_data.empty()) {
797 SendActiveObjectMessages(client->peer_id, reliable_data);
800 if (!unreliable_data.empty()) {
801 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
806 // Clear buffered_messages
807 for (auto &buffered_message : buffered_messages) {
808 delete buffered_message.second;
813 Send queued-for-sending map edit events.
816 // We will be accessing the environment
817 MutexAutoLock lock(m_env_mutex);
819 // Don't send too many at a time
822 // Single change sending is disabled if queue size is not small
823 bool disable_single_change_sending = false;
824 if(m_unsent_map_edit_queue.size() >= 4)
825 disable_single_change_sending = true;
827 int event_count = m_unsent_map_edit_queue.size();
829 // We'll log the amount of each
832 while (!m_unsent_map_edit_queue.empty()) {
833 MapEditEvent* event = m_unsent_map_edit_queue.front();
834 m_unsent_map_edit_queue.pop();
836 // Players far away from the change are stored here.
837 // Instead of sending the changes, MapBlocks are set not sent
839 std::vector<u16> far_players;
841 switch (event->type) {
844 prof.add("MEET_ADDNODE", 1);
845 sendAddNode(event->p, event->n, event->already_known_by_peer,
846 &far_players, disable_single_change_sending ? 5 : 30,
847 event->type == MEET_ADDNODE);
849 case MEET_REMOVENODE:
850 prof.add("MEET_REMOVENODE", 1);
851 sendRemoveNode(event->p, event->already_known_by_peer,
852 &far_players, disable_single_change_sending ? 5 : 30);
854 case MEET_BLOCK_NODE_METADATA_CHANGED:
855 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
856 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
857 setBlockNotSent(event->p);
860 infostream << "Server: MEET_OTHER" << std::endl;
861 prof.add("MEET_OTHER", 1);
862 for (const v3s16 &modified_block : event->modified_blocks) {
863 setBlockNotSent(modified_block);
867 prof.add("unknown", 1);
868 warningstream << "Server: Unknown MapEditEvent "
869 << ((u32)event->type) << std::endl;
874 Set blocks not sent to far players
876 if (!far_players.empty()) {
877 // Convert list format to that wanted by SetBlocksNotSent
878 std::map<v3s16, MapBlock*> modified_blocks2;
879 for (const v3s16 &modified_block : event->modified_blocks) {
880 modified_blocks2[modified_block] =
881 m_env->getMap().getBlockNoCreateNoEx(modified_block);
884 // Set blocks not sent
885 for (const u16 far_player : far_players) {
886 if (RemoteClient *client = getClient(far_player))
887 client->SetBlocksNotSent(modified_blocks2);
894 if (event_count >= 5) {
895 infostream << "Server: MapEditEvents:" << std::endl;
896 prof.print(infostream);
897 } else if (event_count != 0) {
898 verbosestream << "Server: MapEditEvents:" << std::endl;
899 prof.print(verbosestream);
905 Trigger emergethread (it somehow gets to a non-triggered but
906 bysy state sometimes)
909 float &counter = m_emergethread_trigger_timer;
911 if (counter >= 2.0) {
914 m_emerge->startThreads();
918 // Save map, players and auth stuff
920 float &counter = m_savemap_timer;
922 static thread_local const float save_interval =
923 g_settings->getFloat("server_map_save_interval");
924 if (counter >= save_interval) {
926 MutexAutoLock lock(m_env_mutex);
928 ScopeProfiler sp(g_profiler, "Server: saving stuff");
931 if (m_banmanager->isModified()) {
932 m_banmanager->save();
935 // Save changed parts of map
936 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
939 m_env->saveLoadedPlayers();
941 // Save environment metadata
947 static const float shutdown_msg_times[] =
949 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
952 if (m_shutdown_timer > 0.0f) {
953 // Automated messages
954 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
955 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
956 // If shutdown timer matches an automessage, shot it
957 if (m_shutdown_timer > shutdown_msg_times[i] &&
958 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
959 std::wstringstream ws;
961 ws << L"*** Server shutting down in "
962 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
965 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
966 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
972 m_shutdown_timer -= dtime;
973 if (m_shutdown_timer < 0.0f) {
974 m_shutdown_timer = 0.0f;
975 m_shutdown_requested = true;
980 void Server::Receive()
982 DSTACK(FUNCTION_NAME);
987 peer_id = pkt.getPeerId();
989 } catch (const con::InvalidIncomingDataException &e) {
990 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
991 << e.what() << std::endl;
992 } catch (const SerializationError &e) {
993 infostream << "Server::Receive(): SerializationError: what()="
994 << e.what() << std::endl;
995 } catch (const ClientStateError &e) {
996 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
997 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
998 L"Try reconnecting or updating your client");
999 } catch (const con::PeerNotFoundException &e) {
1004 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1006 std::string playername;
1007 PlayerSAO *playersao = NULL;
1010 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1012 playername = client->getName();
1013 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1015 } catch (std::exception &e) {
1021 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1023 // If failed, cancel
1024 if (!playersao || !player) {
1025 if (player && player->peer_id != 0) {
1026 actionstream << "Server: Failed to emerge player \"" << playername
1027 << "\" (player allocated to an another client)" << std::endl;
1028 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1029 L"name. If your client closed unexpectedly, try again in "
1032 errorstream << "Server: " << playername << ": Failed to emerge player"
1034 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1040 Send complete position information
1042 SendMovePlayer(peer_id);
1045 SendPlayerPrivileges(peer_id);
1047 // Send inventory formspec
1048 SendPlayerInventoryFormspec(peer_id);
1051 SendInventory(playersao);
1053 // Send HP or death screen
1054 if (playersao->isDead())
1055 SendDeathscreen(peer_id, false, v3f(0,0,0));
1057 SendPlayerHPOrDie(playersao);
1060 SendPlayerBreath(playersao);
1062 // Note things in chat if not in simple singleplayer mode
1063 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1064 // Send information about server to player in chat
1065 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1067 Address addr = getPeerAddress(player->peer_id);
1068 std::string ip_str = addr.serializeString();
1069 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1074 const std::vector<std::string> &names = m_clients.getPlayerNames();
1076 actionstream << player->getName() << " joins game. List of players: ";
1078 for (const std::string &name : names) {
1079 actionstream << name << " ";
1082 actionstream << player->getName() <<std::endl;
1087 inline void Server::handleCommand(NetworkPacket* pkt)
1089 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1090 (this->*opHandle.handler)(pkt);
1093 void Server::ProcessData(NetworkPacket *pkt)
1095 DSTACK(FUNCTION_NAME);
1096 // Environment is locked first.
1097 MutexAutoLock envlock(m_env_mutex);
1099 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1100 u32 peer_id = pkt->getPeerId();
1103 Address address = getPeerAddress(peer_id);
1104 std::string addr_s = address.serializeString();
1106 if(m_banmanager->isIpBanned(addr_s)) {
1107 std::string ban_name = m_banmanager->getBanName(addr_s);
1108 infostream << "Server: A banned client tried to connect from "
1109 << addr_s << "; banned name was "
1110 << ban_name << std::endl;
1111 // This actually doesn't seem to transfer to the client
1112 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1113 + utf8_to_wide(ban_name));
1117 catch(con::PeerNotFoundException &e) {
1119 * no peer for this packet found
1120 * most common reason is peer timeout, e.g. peer didn't
1121 * respond for some time, your server was overloaded or
1124 infostream << "Server::ProcessData(): Canceling: peer "
1125 << peer_id << " not found" << std::endl;
1130 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1132 // Command must be handled into ToServerCommandHandler
1133 if (command >= TOSERVER_NUM_MSG_TYPES) {
1134 infostream << "Server: Ignoring unknown command "
1135 << command << std::endl;
1139 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1144 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1146 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1147 errorstream << "Server::ProcessData(): Cancelling: Peer"
1148 " serialization format invalid or not initialized."
1149 " Skipping incoming command=" << command << std::endl;
1153 /* Handle commands related to client startup */
1154 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1159 if (m_clients.getClientState(peer_id) < CS_Active) {
1160 if (command == TOSERVER_PLAYERPOS) return;
1162 errorstream << "Got packet command: " << command << " for peer id "
1163 << peer_id << " but client isn't active yet. Dropping packet "
1169 } catch (SendFailedException &e) {
1170 errorstream << "Server::ProcessData(): SendFailedException: "
1171 << "what=" << e.what()
1173 } catch (PacketError &e) {
1174 actionstream << "Server::ProcessData(): PacketError: "
1175 << "what=" << e.what()
1180 void Server::setTimeOfDay(u32 time)
1182 m_env->setTimeOfDay(time);
1183 m_time_of_day_send_timer = 0;
1186 void Server::onMapEditEvent(MapEditEvent *event)
1188 if(m_ignore_map_edit_events)
1190 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1192 MapEditEvent *e = event->clone();
1193 m_unsent_map_edit_queue.push(e);
1196 Inventory* Server::getInventory(const InventoryLocation &loc)
1199 case InventoryLocation::UNDEFINED:
1200 case InventoryLocation::CURRENT_PLAYER:
1202 case InventoryLocation::PLAYER:
1204 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1207 PlayerSAO *playersao = player->getPlayerSAO();
1210 return playersao->getInventory();
1213 case InventoryLocation::NODEMETA:
1215 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1218 return meta->getInventory();
1221 case InventoryLocation::DETACHED:
1223 if(m_detached_inventories.count(loc.name) == 0)
1225 return m_detached_inventories[loc.name];
1229 sanity_check(false); // abort
1234 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1237 case InventoryLocation::UNDEFINED:
1239 case InventoryLocation::PLAYER:
1244 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1249 PlayerSAO *playersao = player->getPlayerSAO();
1253 SendInventory(playersao);
1256 case InventoryLocation::NODEMETA:
1258 v3s16 blockpos = getNodeBlockPos(loc.p);
1260 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1262 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1264 setBlockNotSent(blockpos);
1267 case InventoryLocation::DETACHED:
1269 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1273 sanity_check(false); // abort
1278 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1280 std::vector<u16> clients = m_clients.getClientIDs();
1282 // Set the modified blocks unsent for all the clients
1283 for (const u16 client_id : clients) {
1284 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1285 client->SetBlocksNotSent(block);
1290 void Server::peerAdded(con::Peer *peer)
1292 DSTACK(FUNCTION_NAME);
1293 verbosestream<<"Server::peerAdded(): peer->id="
1294 <<peer->id<<std::endl;
1296 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1299 void Server::deletingPeer(con::Peer *peer, bool timeout)
1301 DSTACK(FUNCTION_NAME);
1302 verbosestream<<"Server::deletingPeer(): peer->id="
1303 <<peer->id<<", timeout="<<timeout<<std::endl;
1305 m_clients.event(peer->id, CSE_Disconnect);
1306 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1309 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1311 *retval = m_con.getPeerStat(peer_id,type);
1312 return *retval != -1;
1315 bool Server::getClientInfo(
1324 std::string* vers_string
1327 *state = m_clients.getClientState(peer_id);
1329 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1336 *uptime = client->uptime();
1337 *ser_vers = client->serialization_version;
1338 *prot_vers = client->net_proto_version;
1340 *major = client->getMajor();
1341 *minor = client->getMinor();
1342 *patch = client->getPatch();
1343 *vers_string = client->getPatch();
1350 void Server::handlePeerChanges()
1352 while(!m_peer_change_queue.empty())
1354 con::PeerChange c = m_peer_change_queue.front();
1355 m_peer_change_queue.pop();
1357 verbosestream<<"Server: Handling peer change: "
1358 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1363 case con::PEER_ADDED:
1364 m_clients.CreateClient(c.peer_id);
1367 case con::PEER_REMOVED:
1368 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1372 FATAL_ERROR("Invalid peer change event received!");
1378 void Server::printToConsoleOnly(const std::string &text)
1381 m_admin_chat->outgoing_queue.push_back(
1382 new ChatEventChat("", utf8_to_wide(text)));
1384 std::cout << text << std::endl;
1388 void Server::Send(NetworkPacket* pkt)
1390 m_clients.send(pkt->getPeerId(),
1391 clientCommandFactoryTable[pkt->getCommand()].channel,
1393 clientCommandFactoryTable[pkt->getCommand()].reliable);
1396 void Server::SendMovement(u16 peer_id)
1398 DSTACK(FUNCTION_NAME);
1399 std::ostringstream os(std::ios_base::binary);
1401 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1403 pkt << g_settings->getFloat("movement_acceleration_default");
1404 pkt << g_settings->getFloat("movement_acceleration_air");
1405 pkt << g_settings->getFloat("movement_acceleration_fast");
1406 pkt << g_settings->getFloat("movement_speed_walk");
1407 pkt << g_settings->getFloat("movement_speed_crouch");
1408 pkt << g_settings->getFloat("movement_speed_fast");
1409 pkt << g_settings->getFloat("movement_speed_climb");
1410 pkt << g_settings->getFloat("movement_speed_jump");
1411 pkt << g_settings->getFloat("movement_liquid_fluidity");
1412 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1413 pkt << g_settings->getFloat("movement_liquid_sink");
1414 pkt << g_settings->getFloat("movement_gravity");
1419 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1421 if (!g_settings->getBool("enable_damage"))
1424 u16 peer_id = playersao->getPeerID();
1425 bool is_alive = playersao->getHP() > 0;
1428 SendPlayerHP(peer_id);
1433 void Server::SendHP(u16 peer_id, u8 hp)
1435 DSTACK(FUNCTION_NAME);
1437 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1442 void Server::SendBreath(u16 peer_id, u16 breath)
1444 DSTACK(FUNCTION_NAME);
1446 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1447 pkt << (u16) breath;
1451 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1452 const std::string &custom_reason, bool reconnect)
1454 assert(reason < SERVER_ACCESSDENIED_MAX);
1456 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1458 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1459 pkt << custom_reason;
1460 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1461 reason == SERVER_ACCESSDENIED_CRASH)
1462 pkt << custom_reason << (u8)reconnect;
1466 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1468 DSTACK(FUNCTION_NAME);
1470 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1475 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1476 v3f camera_point_target)
1478 DSTACK(FUNCTION_NAME);
1480 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1481 pkt << set_camera_point_target << camera_point_target;
1485 void Server::SendItemDef(u16 peer_id,
1486 IItemDefManager *itemdef, u16 protocol_version)
1488 DSTACK(FUNCTION_NAME);
1490 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1494 u32 length of the next item
1495 zlib-compressed serialized ItemDefManager
1497 std::ostringstream tmp_os(std::ios::binary);
1498 itemdef->serialize(tmp_os, protocol_version);
1499 std::ostringstream tmp_os2(std::ios::binary);
1500 compressZlib(tmp_os.str(), tmp_os2);
1501 pkt.putLongString(tmp_os2.str());
1504 verbosestream << "Server: Sending item definitions to id(" << peer_id
1505 << "): size=" << pkt.getSize() << std::endl;
1510 void Server::SendNodeDef(u16 peer_id,
1511 INodeDefManager *nodedef, u16 protocol_version)
1513 DSTACK(FUNCTION_NAME);
1515 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1519 u32 length of the next item
1520 zlib-compressed serialized NodeDefManager
1522 std::ostringstream tmp_os(std::ios::binary);
1523 nodedef->serialize(tmp_os, protocol_version);
1524 std::ostringstream tmp_os2(std::ios::binary);
1525 compressZlib(tmp_os.str(), tmp_os2);
1527 pkt.putLongString(tmp_os2.str());
1530 verbosestream << "Server: Sending node definitions to id(" << peer_id
1531 << "): size=" << pkt.getSize() << std::endl;
1537 Non-static send methods
1540 void Server::SendInventory(PlayerSAO* playerSAO)
1542 DSTACK(FUNCTION_NAME);
1544 UpdateCrafting(playerSAO->getPlayer());
1550 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1552 std::ostringstream os;
1553 playerSAO->getInventory()->serialize(os);
1555 std::string s = os.str();
1557 pkt.putRawString(s.c_str(), s.size());
1561 void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
1563 DSTACK(FUNCTION_NAME);
1565 NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
1566 legacypkt << message.message;
1568 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1570 u8 type = message.type;
1571 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1573 if (peer_id != PEER_ID_INEXISTENT) {
1574 RemotePlayer *player = m_env->getPlayer(peer_id);
1578 if (player->protocol_version < 35)
1583 m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
1587 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1588 const std::string &formname)
1590 DSTACK(FUNCTION_NAME);
1592 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1593 if (formspec.empty()){
1594 //the client should close the formspec
1595 pkt.putLongString("");
1597 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1604 // Spawns a particle on peer with peer_id
1605 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1606 v3f pos, v3f velocity, v3f acceleration,
1607 float expirationtime, float size, bool collisiondetection,
1608 bool collision_removal,
1609 bool vertical, const std::string &texture,
1610 const struct TileAnimationParams &animation, u8 glow)
1612 DSTACK(FUNCTION_NAME);
1613 static thread_local const float radius =
1614 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1616 if (peer_id == PEER_ID_INEXISTENT) {
1617 std::vector<u16> clients = m_clients.getClientIDs();
1619 for (const u16 client_id : clients) {
1620 RemotePlayer *player = m_env->getPlayer(client_id);
1624 PlayerSAO *sao = player->getPlayerSAO();
1628 // Do not send to distant clients
1629 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1632 SendSpawnParticle(client_id, player->protocol_version,
1633 pos, velocity, acceleration,
1634 expirationtime, size, collisiondetection,
1635 collision_removal, vertical, texture, animation, glow);
1640 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1642 pkt << pos << velocity << acceleration << expirationtime
1643 << size << collisiondetection;
1644 pkt.putLongString(texture);
1646 pkt << collision_removal;
1647 // This is horrible but required (why are there two ways to serialize pkts?)
1648 std::ostringstream os(std::ios_base::binary);
1649 animation.serialize(os, protocol_version);
1650 pkt.putRawString(os.str());
1656 // Adds a ParticleSpawner on peer with peer_id
1657 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1658 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1659 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1660 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1661 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1662 const struct TileAnimationParams &animation, u8 glow)
1664 DSTACK(FUNCTION_NAME);
1665 if (peer_id == PEER_ID_INEXISTENT) {
1666 // This sucks and should be replaced:
1667 std::vector<u16> clients = m_clients.getClientIDs();
1668 for (const u16 client_id : clients) {
1669 RemotePlayer *player = m_env->getPlayer(client_id);
1672 SendAddParticleSpawner(client_id, player->protocol_version,
1673 amount, spawntime, minpos, maxpos,
1674 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1675 minsize, maxsize, collisiondetection, collision_removal,
1676 attached_id, vertical, texture, id, animation, glow);
1681 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1683 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1684 << minacc << maxacc << minexptime << maxexptime << minsize
1685 << maxsize << collisiondetection;
1687 pkt.putLongString(texture);
1689 pkt << id << vertical;
1690 pkt << collision_removal;
1692 // This is horrible but required
1693 std::ostringstream os(std::ios_base::binary);
1694 animation.serialize(os, protocol_version);
1695 pkt.putRawString(os.str());
1701 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1703 DSTACK(FUNCTION_NAME);
1705 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1707 // Ugly error in this packet
1710 if (peer_id != PEER_ID_INEXISTENT) {
1714 m_clients.sendToAll(&pkt);
1719 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1721 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1723 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1724 << form->text << form->number << form->item << form->dir
1725 << form->align << form->offset << form->world_pos << form->size;
1730 void Server::SendHUDRemove(u16 peer_id, u32 id)
1732 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1737 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1739 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1740 pkt << id << (u8) stat;
1744 case HUD_STAT_SCALE:
1745 case HUD_STAT_ALIGN:
1746 case HUD_STAT_OFFSET:
1747 pkt << *(v2f *) value;
1751 pkt << *(std::string *) value;
1753 case HUD_STAT_WORLD_POS:
1754 pkt << *(v3f *) value;
1757 pkt << *(v2s32 *) value;
1759 case HUD_STAT_NUMBER:
1763 pkt << *(u32 *) value;
1770 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1772 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1774 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1776 pkt << flags << mask;
1781 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1783 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1784 pkt << param << value;
1788 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1789 const std::string &type, const std::vector<std::string> ¶ms,
1792 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1793 pkt << bgcolor << type << (u16) params.size();
1795 for (const std::string ¶m : params)
1803 void Server::SendCloudParams(u16 peer_id, float density,
1804 const video::SColor &color_bright,
1805 const video::SColor &color_ambient,
1810 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1811 pkt << density << color_bright << color_ambient
1812 << height << thickness << speed;
1817 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1820 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1823 pkt << do_override << (u16) (ratio * 65535);
1828 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1830 DSTACK(FUNCTION_NAME);
1832 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1833 pkt << time << time_speed;
1835 if (peer_id == PEER_ID_INEXISTENT) {
1836 m_clients.sendToAll(&pkt);
1843 void Server::SendPlayerHP(u16 peer_id)
1845 DSTACK(FUNCTION_NAME);
1846 PlayerSAO *playersao = getPlayerSAO(peer_id);
1847 // In some rare case if the player is disconnected
1848 // while Lua call l_punch, for example, this can be NULL
1852 SendHP(peer_id, playersao->getHP());
1853 m_script->player_event(playersao,"health_changed");
1855 // Send to other clients
1856 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1857 ActiveObjectMessage aom(playersao->getId(), true, str);
1858 playersao->m_messages_out.push(aom);
1861 void Server::SendPlayerBreath(PlayerSAO *sao)
1863 DSTACK(FUNCTION_NAME);
1866 m_script->player_event(sao, "breath_changed");
1867 SendBreath(sao->getPeerID(), sao->getBreath());
1870 void Server::SendMovePlayer(u16 peer_id)
1872 DSTACK(FUNCTION_NAME);
1873 RemotePlayer *player = m_env->getPlayer(peer_id);
1875 PlayerSAO *sao = player->getPlayerSAO();
1878 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1879 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1882 v3f pos = sao->getBasePosition();
1883 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1884 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1885 << " pitch=" << sao->getPitch()
1886 << " yaw=" << sao->getYaw()
1893 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1895 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1898 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1899 << animation_frames[3] << animation_speed;
1904 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1906 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1907 pkt << first << third;
1910 void Server::SendPlayerPrivileges(u16 peer_id)
1912 RemotePlayer *player = m_env->getPlayer(peer_id);
1914 if(player->peer_id == PEER_ID_INEXISTENT)
1917 std::set<std::string> privs;
1918 m_script->getAuth(player->getName(), NULL, &privs);
1920 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1921 pkt << (u16) privs.size();
1923 for (const std::string &priv : privs) {
1930 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1932 RemotePlayer *player = m_env->getPlayer(peer_id);
1934 if(player->peer_id == PEER_ID_INEXISTENT)
1937 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1938 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1942 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1944 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1945 pkt.putRawString(datas.c_str(), datas.size());
1947 return pkt.getSize();
1950 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1952 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1953 datas.size(), peer_id);
1955 pkt.putRawString(datas.c_str(), datas.size());
1957 m_clients.send(pkt.getPeerId(),
1958 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1962 void Server::SendCSMFlavourLimits(u16 peer_id)
1964 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
1965 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
1966 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
1970 s32 Server::playSound(const SimpleSoundSpec &spec,
1971 const ServerSoundParams ¶ms)
1973 // Find out initial position of sound
1974 bool pos_exists = false;
1975 v3f pos = params.getPos(m_env, &pos_exists);
1976 // If position is not found while it should be, cancel sound
1977 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1980 // Filter destination clients
1981 std::vector<u16> dst_clients;
1982 if(!params.to_player.empty()) {
1983 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1985 infostream<<"Server::playSound: Player \""<<params.to_player
1986 <<"\" not found"<<std::endl;
1989 if(player->peer_id == PEER_ID_INEXISTENT){
1990 infostream<<"Server::playSound: Player \""<<params.to_player
1991 <<"\" not connected"<<std::endl;
1994 dst_clients.push_back(player->peer_id);
1996 std::vector<u16> clients = m_clients.getClientIDs();
1998 for (const u16 client_id : clients) {
1999 RemotePlayer *player = m_env->getPlayer(client_id);
2003 PlayerSAO *sao = player->getPlayerSAO();
2008 if(sao->getBasePosition().getDistanceFrom(pos) >
2009 params.max_hear_distance)
2012 dst_clients.push_back(client_id);
2016 if(dst_clients.empty())
2020 s32 id = m_next_sound_id++;
2021 // The sound will exist as a reference in m_playing_sounds
2022 m_playing_sounds[id] = ServerPlayingSound();
2023 ServerPlayingSound &psound = m_playing_sounds[id];
2024 psound.params = params;
2027 float gain = params.gain * spec.gain;
2028 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2029 pkt << id << spec.name << gain
2030 << (u8) params.type << pos << params.object
2031 << params.loop << params.fade << params.pitch;
2033 // Backwards compability
2034 bool play_sound = gain > 0;
2036 for (const u16 dst_client : dst_clients) {
2037 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2038 psound.clients.insert(dst_client);
2039 m_clients.send(dst_client, 0, &pkt, true);
2044 void Server::stopSound(s32 handle)
2046 // Get sound reference
2047 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2048 m_playing_sounds.find(handle);
2049 if (i == m_playing_sounds.end())
2051 ServerPlayingSound &psound = i->second;
2053 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2056 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2057 si != psound.clients.end(); ++si) {
2059 m_clients.send(*si, 0, &pkt, true);
2061 // Remove sound reference
2062 m_playing_sounds.erase(i);
2065 void Server::fadeSound(s32 handle, float step, float gain)
2067 // Get sound reference
2068 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2069 m_playing_sounds.find(handle);
2070 if (i == m_playing_sounds.end())
2073 ServerPlayingSound &psound = i->second;
2074 psound.params.gain = gain;
2076 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2077 pkt << handle << step << gain;
2079 // Backwards compability
2080 bool play_sound = gain > 0;
2081 ServerPlayingSound compat_psound = psound;
2082 compat_psound.clients.clear();
2084 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2085 compat_pkt << handle;
2087 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2088 it != psound.clients.end();) {
2089 if (m_clients.getProtocolVersion(*it) >= 32) {
2091 m_clients.send(*it, 0, &pkt, true);
2094 compat_psound.clients.insert(*it);
2096 m_clients.send(*it, 0, &compat_pkt, true);
2097 psound.clients.erase(it++);
2101 // Remove sound reference
2102 if (!play_sound || psound.clients.empty())
2103 m_playing_sounds.erase(i);
2105 if (play_sound && !compat_psound.clients.empty()) {
2106 // Play new sound volume on older clients
2107 playSound(compat_psound.spec, compat_psound.params);
2111 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2112 std::vector<u16> *far_players, float far_d_nodes)
2114 float maxd = far_d_nodes*BS;
2115 v3f p_f = intToFloat(p, BS);
2117 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2120 std::vector<u16> clients = m_clients.getClientIDs();
2121 for (u16 client_id : clients) {
2124 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2125 PlayerSAO *sao = player->getPlayerSAO();
2129 // If player is far away, only set modified blocks not sent
2130 v3f player_pos = sao->getBasePosition();
2131 if (player_pos.getDistanceFrom(p_f) > maxd) {
2132 far_players->push_back(client_id);
2139 m_clients.send(client_id, 0, &pkt, true);
2143 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2144 std::vector<u16> *far_players, float far_d_nodes,
2145 bool remove_metadata)
2147 float maxd = far_d_nodes*BS;
2148 v3f p_f = intToFloat(p, BS);
2150 std::vector<u16> clients = m_clients.getClientIDs();
2151 for (const u16 client_id : clients) {
2154 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2155 PlayerSAO *sao = player->getPlayerSAO();
2159 // If player is far away, only set modified blocks not sent
2160 v3f player_pos = sao->getBasePosition();
2161 if(player_pos.getDistanceFrom(p_f) > maxd) {
2162 far_players->push_back(client_id);
2168 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2170 RemoteClient* client = m_clients.lockedGetClientNoEx(client_id);
2172 pkt << p << n.param0 << n.param1 << n.param2
2173 << (u8) (remove_metadata ? 0 : 1);
2178 if (pkt.getSize() > 0)
2179 m_clients.send(client_id, 0, &pkt, true);
2183 void Server::setBlockNotSent(v3s16 p)
2185 std::vector<u16> clients = m_clients.getClientIDs();
2187 for (const u16 i : clients) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2189 client->SetBlockNotSent(p);
2194 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2196 DSTACK(FUNCTION_NAME);
2198 v3s16 p = block->getPos();
2201 Create a packet with the block in the right format
2204 std::ostringstream os(std::ios_base::binary);
2205 block->serialize(os, ver, false);
2206 block->serializeNetworkSpecific(os);
2207 std::string s = os.str();
2209 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2212 pkt.putRawString(s.c_str(), s.size());
2216 void Server::SendBlocks(float dtime)
2218 DSTACK(FUNCTION_NAME);
2220 MutexAutoLock envlock(m_env_mutex);
2221 //TODO check if one big lock could be faster then multiple small ones
2223 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2225 std::vector<PrioritySortedBlockTransfer> queue;
2227 s32 total_sending = 0;
2230 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2232 std::vector<u16> clients = m_clients.getClientIDs();
2235 for (const u16 client_id : clients) {
2236 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2241 total_sending += client->SendingCount();
2242 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2248 // Lowest priority number comes first.
2249 // Lowest is most important.
2250 std::sort(queue.begin(), queue.end());
2253 s32 max_blocks_to_send =
2254 g_settings->getS32("max_simultaneous_block_sends_server_total");
2256 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2257 //TODO: Calculate limit dynamically
2258 if (total_sending >= max_blocks_to_send)
2261 MapBlock *block = nullptr;
2263 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2264 } catch (const InvalidPositionException &e) {
2268 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2273 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2274 client->net_proto_version);
2276 client->SentBlock(block_to_send.pos);
2282 void Server::fillMediaCache()
2284 DSTACK(FUNCTION_NAME);
2286 infostream<<"Server: Calculating media file checksums"<<std::endl;
2288 // Collect all media file paths
2289 std::vector<std::string> paths;
2290 for (const ModSpec &mod : m_mods) {
2291 paths.push_back(mod.path + DIR_DELIM + "textures");
2292 paths.push_back(mod.path + DIR_DELIM + "sounds");
2293 paths.push_back(mod.path + DIR_DELIM + "media");
2294 paths.push_back(mod.path + DIR_DELIM + "models");
2296 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2298 // Collect media file information from paths into cache
2299 for (const std::string &mediapath : paths) {
2300 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2301 for (const fs::DirListNode &dln : dirlist) {
2302 if (dln.dir) // Ignode dirs
2304 std::string filename = dln.name;
2305 // If name contains illegal characters, ignore the file
2306 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2307 infostream<<"Server: ignoring illegal file name: \""
2308 << filename << "\"" << std::endl;
2311 // If name is not in a supported format, ignore it
2312 const char *supported_ext[] = {
2313 ".png", ".jpg", ".bmp", ".tga",
2314 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2316 ".x", ".b3d", ".md2", ".obj",
2319 if (removeStringEnd(filename, supported_ext).empty()){
2320 infostream << "Server: ignoring unsupported file extension: \""
2321 << filename << "\"" << std::endl;
2324 // Ok, attempt to load the file and add to cache
2325 std::string filepath;
2326 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2329 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2331 errorstream << "Server::fillMediaCache(): Could not open \""
2332 << filename << "\" for reading" << std::endl;
2335 std::ostringstream tmp_os(std::ios_base::binary);
2339 fis.read(buf, 1024);
2340 std::streamsize len = fis.gcount();
2341 tmp_os.write(buf, len);
2350 errorstream<<"Server::fillMediaCache(): Failed to read \""
2351 << filename << "\"" << std::endl;
2354 if(tmp_os.str().length() == 0) {
2355 errorstream << "Server::fillMediaCache(): Empty file \""
2356 << filepath << "\"" << std::endl;
2361 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2363 unsigned char *digest = sha1.getDigest();
2364 std::string sha1_base64 = base64_encode(digest, 20);
2365 std::string sha1_hex = hex_encode((char*)digest, 20);
2369 m_media[filename] = MediaInfo(filepath, sha1_base64);
2370 verbosestream << "Server: " << sha1_hex << " is " << filename
2376 void Server::sendMediaAnnouncement(u16 peer_id)
2378 DSTACK(FUNCTION_NAME);
2380 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2384 std::ostringstream os(std::ios_base::binary);
2386 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2387 pkt << (u16) m_media.size();
2389 for (const auto &i : m_media) {
2390 pkt << i.first << i.second.sha1_digest;
2393 pkt << g_settings->get("remote_media");
2397 struct SendableMedia
2403 SendableMedia(const std::string &name_="", const std::string &path_="",
2404 const std::string &data_=""):
2411 void Server::sendRequestedMedia(u16 peer_id,
2412 const std::vector<std::string> &tosend)
2414 DSTACK(FUNCTION_NAME);
2416 verbosestream<<"Server::sendRequestedMedia(): "
2417 <<"Sending files to client"<<std::endl;
2421 // Put 5kB in one bunch (this is not accurate)
2422 u32 bytes_per_bunch = 5000;
2424 std::vector< std::vector<SendableMedia> > file_bunches;
2425 file_bunches.emplace_back();
2427 u32 file_size_bunch_total = 0;
2429 for (const std::string &name : tosend) {
2430 if (m_media.find(name) == m_media.end()) {
2431 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2432 <<"unknown file \""<<(name)<<"\""<<std::endl;
2436 //TODO get path + name
2437 std::string tpath = m_media[name].path;
2440 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2442 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2443 <<tpath<<"\" for reading"<<std::endl;
2446 std::ostringstream tmp_os(std::ios_base::binary);
2450 fis.read(buf, 1024);
2451 std::streamsize len = fis.gcount();
2452 tmp_os.write(buf, len);
2453 file_size_bunch_total += len;
2462 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2463 <<name<<"\""<<std::endl;
2466 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2467 <<tname<<"\""<<std::endl;*/
2469 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2471 // Start next bunch if got enough data
2472 if(file_size_bunch_total >= bytes_per_bunch) {
2473 file_bunches.emplace_back();
2474 file_size_bunch_total = 0;
2479 /* Create and send packets */
2481 u16 num_bunches = file_bunches.size();
2482 for (u16 i = 0; i < num_bunches; i++) {
2485 u16 total number of texture bunches
2486 u16 index of this bunch
2487 u32 number of files in this bunch
2496 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2497 pkt << num_bunches << i << (u32) file_bunches[i].size();
2499 for (const SendableMedia &j : file_bunches[i]) {
2501 pkt.putLongString(j.data);
2504 verbosestream << "Server::sendRequestedMedia(): bunch "
2505 << i << "/" << num_bunches
2506 << " files=" << file_bunches[i].size()
2507 << " size=" << pkt.getSize() << std::endl;
2512 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2514 if(m_detached_inventories.count(name) == 0) {
2515 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2518 Inventory *inv = m_detached_inventories[name];
2519 std::ostringstream os(std::ios_base::binary);
2521 os << serializeString(name);
2525 std::string s = os.str();
2527 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2528 pkt.putRawString(s.c_str(), s.size());
2530 const std::string &check = m_detached_inventories_player[name];
2531 if (peer_id == PEER_ID_INEXISTENT) {
2533 return m_clients.sendToAll(&pkt);
2534 RemotePlayer *p = m_env->getPlayer(check.c_str());
2536 m_clients.send(p->peer_id, 0, &pkt, true);
2538 if (check.empty() || getPlayerName(peer_id) == check)
2543 void Server::sendDetachedInventories(u16 peer_id)
2545 DSTACK(FUNCTION_NAME);
2547 for (const auto &detached_inventory : m_detached_inventories) {
2548 const std::string &name = detached_inventory.first;
2549 //Inventory *inv = i->second;
2550 sendDetachedInventory(name, peer_id);
2558 void Server::DiePlayer(u16 peer_id)
2560 DSTACK(FUNCTION_NAME);
2561 PlayerSAO *playersao = getPlayerSAO(peer_id);
2562 // In some rare cases this can be NULL -- if the player is disconnected
2563 // when a Lua function modifies l_punch, for example
2567 infostream << "Server::DiePlayer(): Player "
2568 << playersao->getPlayer()->getName()
2569 << " dies" << std::endl;
2571 playersao->setHP(0);
2573 // Trigger scripted stuff
2574 m_script->on_dieplayer(playersao);
2576 SendPlayerHP(peer_id);
2577 SendDeathscreen(peer_id, false, v3f(0,0,0));
2580 void Server::RespawnPlayer(u16 peer_id)
2582 DSTACK(FUNCTION_NAME);
2584 PlayerSAO *playersao = getPlayerSAO(peer_id);
2587 infostream << "Server::RespawnPlayer(): Player "
2588 << playersao->getPlayer()->getName()
2589 << " respawns" << std::endl;
2591 playersao->setHP(playersao->accessObjectProperties()->hp_max);
2592 playersao->setBreath(PLAYER_MAX_BREATH);
2594 bool repositioned = m_script->on_respawnplayer(playersao);
2595 if (!repositioned) {
2596 // setPos will send the new position to client
2597 playersao->setPos(findSpawnPos());
2600 SendPlayerHP(peer_id);
2604 void Server::DenySudoAccess(u16 peer_id)
2606 DSTACK(FUNCTION_NAME);
2608 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2613 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2614 const std::string &str_reason, bool reconnect)
2616 if (proto_ver >= 25) {
2617 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2619 std::wstring wreason = utf8_to_wide(
2620 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2621 accessDeniedStrings[(u8)reason]);
2622 SendAccessDenied_Legacy(peer_id, wreason);
2625 m_clients.event(peer_id, CSE_SetDenied);
2626 m_con.DisconnectPeer(peer_id);
2630 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2632 DSTACK(FUNCTION_NAME);
2634 SendAccessDenied(peer_id, reason, custom_reason);
2635 m_clients.event(peer_id, CSE_SetDenied);
2636 m_con.DisconnectPeer(peer_id);
2639 // 13/03/15: remove this function when protocol version 25 will become
2640 // the minimum version for MT users, maybe in 1 year
2641 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2643 DSTACK(FUNCTION_NAME);
2645 SendAccessDenied_Legacy(peer_id, reason);
2646 m_clients.event(peer_id, CSE_SetDenied);
2647 m_con.DisconnectPeer(peer_id);
2650 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2652 DSTACK(FUNCTION_NAME);
2655 RemoteClient* client = getClient(peer_id, CS_Invalid);
2657 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2659 // Right now, the auth mechs don't change between login and sudo mode.
2660 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2661 client->allowed_sudo_mechs = sudo_auth_mechs;
2663 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2664 << g_settings->getFloat("dedicated_server_step")
2668 m_clients.event(peer_id, CSE_AuthAccept);
2670 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2672 // We only support SRP right now
2673 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2675 resp_pkt << sudo_auth_mechs;
2677 m_clients.event(peer_id, CSE_SudoSuccess);
2681 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2683 DSTACK(FUNCTION_NAME);
2684 std::wstring message;
2687 Clear references to playing sounds
2689 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2690 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2691 ServerPlayingSound &psound = i->second;
2692 psound.clients.erase(peer_id);
2693 if (psound.clients.empty())
2694 m_playing_sounds.erase(i++);
2699 RemotePlayer *player = m_env->getPlayer(peer_id);
2701 /* Run scripts and remove from environment */
2703 PlayerSAO *playersao = player->getPlayerSAO();
2706 // inform connected clients
2707 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2708 // (u16) 1 + std::string represents a vector serialization representation
2709 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2710 m_clients.sendToAll(¬ice);
2712 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2714 playersao->disconnected();
2721 if (player && reason != CDR_DENY) {
2722 std::ostringstream os(std::ios_base::binary);
2723 std::vector<u16> clients = m_clients.getClientIDs();
2725 for (const u16 client_id : clients) {
2727 RemotePlayer *player = m_env->getPlayer(client_id);
2731 // Get name of player
2732 os << player->getName() << " ";
2735 std::string name = player->getName();
2736 actionstream << name << " "
2737 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2738 << " List of players: " << os.str() << std::endl;
2740 m_admin_chat->outgoing_queue.push_back(
2741 new ChatEventNick(CET_NICK_REMOVE, name));
2745 MutexAutoLock env_lock(m_env_mutex);
2746 m_clients.DeleteClient(peer_id);
2750 // Send leave chat message to all remaining clients
2751 if (!message.empty()) {
2752 SendChatMessage(PEER_ID_INEXISTENT,
2753 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2757 void Server::UpdateCrafting(RemotePlayer *player)
2759 DSTACK(FUNCTION_NAME);
2761 // Get a preview for crafting
2763 InventoryLocation loc;
2764 loc.setPlayer(player->getName());
2765 std::vector<ItemStack> output_replacements;
2766 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2767 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2768 (&player->inventory)->getList("craft"), loc);
2770 // Put the new preview in
2771 InventoryList *plist = player->inventory.getList("craftpreview");
2772 sanity_check(plist);
2773 sanity_check(plist->getSize() >= 1);
2774 plist->changeItem(0, preview);
2777 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2779 if (evt->type == CET_NICK_ADD) {
2780 // The terminal informed us of its nick choice
2781 m_admin_nick = ((ChatEventNick *)evt)->nick;
2782 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2783 errorstream << "You haven't set up an account." << std::endl
2784 << "Please log in using the client as '"
2785 << m_admin_nick << "' with a secure password." << std::endl
2786 << "Until then, you can't execute admin tasks via the console," << std::endl
2787 << "and everybody can claim the user account instead of you," << std::endl
2788 << "giving them full control over this server." << std::endl;
2791 assert(evt->type == CET_CHAT);
2792 handleAdminChat((ChatEventChat *)evt);
2796 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2797 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2799 // If something goes wrong, this player is to blame
2800 RollbackScopeActor rollback_scope(m_rollback,
2801 std::string("player:") + name);
2803 if (g_settings->getBool("strip_color_codes"))
2804 wmessage = unescape_enriched(wmessage);
2807 switch (player->canSendChatMessage()) {
2808 case RPLAYER_CHATRESULT_FLOODING: {
2809 std::wstringstream ws;
2810 ws << L"You cannot send more messages. You are limited to "
2811 << g_settings->getFloat("chat_message_limit_per_10sec")
2812 << L" messages per 10 seconds.";
2815 case RPLAYER_CHATRESULT_KICK:
2816 DenyAccess_Legacy(player->peer_id,
2817 L"You have been kicked due to message flooding.");
2819 case RPLAYER_CHATRESULT_OK:
2822 FATAL_ERROR("Unhandled chat filtering result found.");
2826 if (m_max_chatmessage_length > 0
2827 && wmessage.length() > m_max_chatmessage_length) {
2828 return L"Your message exceed the maximum chat message limit set on the server. "
2829 L"It was refused. Send a shorter message";
2832 // Run script hook, exit if script ate the chat message
2833 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2838 // Whether to send line to the player that sent the message, or to all players
2839 bool broadcast_line = true;
2841 if (check_shout_priv && !checkPriv(name, "shout")) {
2842 line += L"-!- You don't have permission to shout.";
2843 broadcast_line = false;
2852 Tell calling method to send the message to sender
2854 if (!broadcast_line)
2858 Send the message to others
2860 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2862 std::vector<u16> clients = m_clients.getClientIDs();
2865 Send the message back to the inital sender
2866 if they are using protocol version >= 29
2869 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2870 if (player && player->protocol_version >= 29)
2871 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2873 for (u16 cid : clients) {
2874 if (cid != peer_id_to_avoid_sending)
2875 SendChatMessage(cid, ChatMessage(line));
2880 void Server::handleAdminChat(const ChatEventChat *evt)
2882 std::string name = evt->nick;
2883 std::wstring wname = utf8_to_wide(name);
2884 std::wstring wmessage = evt->evt_msg;
2886 std::wstring answer = handleChat(name, wname, wmessage);
2888 // If asked to send answer to sender
2889 if (!answer.empty()) {
2890 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2894 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2896 RemoteClient *client = getClientNoEx(peer_id,state_min);
2898 throw ClientNotFoundException("Client not found");
2902 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2904 return m_clients.getClientNoEx(peer_id, state_min);
2907 std::string Server::getPlayerName(u16 peer_id)
2909 RemotePlayer *player = m_env->getPlayer(peer_id);
2911 return "[id="+itos(peer_id)+"]";
2912 return player->getName();
2915 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2917 RemotePlayer *player = m_env->getPlayer(peer_id);
2920 return player->getPlayerSAO();
2923 std::wstring Server::getStatusString()
2925 std::wostringstream os(std::ios_base::binary);
2928 os<<L"version="<<narrow_to_wide(g_version_string);
2930 os<<L", uptime="<<m_uptime.get();
2932 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2933 // Information about clients
2936 std::vector<u16> clients = m_clients.getClientIDs();
2937 for (u16 client_id : clients) {
2939 RemotePlayer *player = m_env->getPlayer(client_id);
2940 // Get name of player
2941 std::wstring name = L"unknown";
2943 name = narrow_to_wide(player->getName());
2944 // Add name to information string
2953 if (!((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
2954 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2956 if (!g_settings->get("motd").empty())
2957 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2961 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2963 std::set<std::string> privs;
2964 m_script->getAuth(name, NULL, &privs);
2968 bool Server::checkPriv(const std::string &name, const std::string &priv)
2970 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2971 return (privs.count(priv) != 0);
2974 void Server::reportPrivsModified(const std::string &name)
2977 std::vector<u16> clients = m_clients.getClientIDs();
2978 for (const u16 client_id : clients) {
2979 RemotePlayer *player = m_env->getPlayer(client_id);
2980 reportPrivsModified(player->getName());
2983 RemotePlayer *player = m_env->getPlayer(name.c_str());
2986 SendPlayerPrivileges(player->peer_id);
2987 PlayerSAO *sao = player->getPlayerSAO();
2990 sao->updatePrivileges(
2991 getPlayerEffectivePrivs(name),
2996 void Server::reportInventoryFormspecModified(const std::string &name)
2998 RemotePlayer *player = m_env->getPlayer(name.c_str());
3001 SendPlayerInventoryFormspec(player->peer_id);
3004 void Server::setIpBanned(const std::string &ip, const std::string &name)
3006 m_banmanager->add(ip, name);
3009 void Server::unsetIpBanned(const std::string &ip_or_name)
3011 m_banmanager->remove(ip_or_name);
3014 std::string Server::getBanDescription(const std::string &ip_or_name)
3016 return m_banmanager->getBanDescription(ip_or_name);
3019 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3021 // m_env will be NULL if the server is initializing
3025 if (m_admin_nick == name && !m_admin_nick.empty()) {
3026 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3029 RemotePlayer *player = m_env->getPlayer(name);
3034 if (player->peer_id == PEER_ID_INEXISTENT)
3037 SendChatMessage(player->peer_id, ChatMessage(msg));
3040 bool Server::showFormspec(const char *playername, const std::string &formspec,
3041 const std::string &formname)
3043 // m_env will be NULL if the server is initializing
3047 RemotePlayer *player = m_env->getPlayer(playername);
3051 SendShowFormspecMessage(player->peer_id, formspec, formname);
3055 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3060 u32 id = player->addHud(form);
3062 SendHUDAdd(player->peer_id, id, form);
3067 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3071 HudElement* todel = player->removeHud(id);
3078 SendHUDRemove(player->peer_id, id);
3082 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3087 SendHUDChange(player->peer_id, id, stat, data);
3091 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3096 SendHUDSetFlags(player->peer_id, flags, mask);
3097 player->hud_flags &= ~mask;
3098 player->hud_flags |= flags;
3100 PlayerSAO* playersao = player->getPlayerSAO();
3105 m_script->player_event(playersao, "hud_changed");
3109 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3114 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3117 player->setHotbarItemcount(hotbar_itemcount);
3118 std::ostringstream os(std::ios::binary);
3119 writeS32(os, hotbar_itemcount);
3120 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3124 s32 Server::hudGetHotbarItemcount(RemotePlayer *player) const
3126 return player->getHotbarItemcount();
3129 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3134 player->setHotbarImage(name);
3135 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3138 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3142 return player->getHotbarImage();
3145 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3150 player->setHotbarSelectedImage(name);
3151 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3154 const std::string& Server::hudGetHotbarSelectedImage(RemotePlayer *player) const
3156 return player->getHotbarSelectedImage();
3159 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3160 v2s32 animation_frames[4], f32 frame_speed)
3165 player->setLocalAnimations(animation_frames, frame_speed);
3166 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3170 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3175 player->eye_offset_first = first;
3176 player->eye_offset_third = third;
3177 SendEyeOffset(player->peer_id, first, third);
3181 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3182 const std::string &type, const std::vector<std::string> ¶ms,
3188 player->setSky(bgcolor, type, params, clouds);
3189 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3193 bool Server::setClouds(RemotePlayer *player, float density,
3194 const video::SColor &color_bright,
3195 const video::SColor &color_ambient,
3203 SendCloudParams(player->peer_id, density,
3204 color_bright, color_ambient, height,
3209 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3215 player->overrideDayNightRatio(do_override, ratio);
3216 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3220 void Server::notifyPlayers(const std::wstring &msg)
3222 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3225 void Server::spawnParticle(const std::string &playername, v3f pos,
3226 v3f velocity, v3f acceleration,
3227 float expirationtime, float size, bool
3228 collisiondetection, bool collision_removal,
3229 bool vertical, const std::string &texture,
3230 const struct TileAnimationParams &animation, u8 glow)
3232 // m_env will be NULL if the server is initializing
3236 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3237 if (!playername.empty()) {
3238 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3241 peer_id = player->peer_id;
3242 proto_ver = player->protocol_version;
3245 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3246 expirationtime, size, collisiondetection,
3247 collision_removal, vertical, texture, animation, glow);
3250 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3251 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3252 float minexptime, float maxexptime, float minsize, float maxsize,
3253 bool collisiondetection, bool collision_removal,
3254 ServerActiveObject *attached, bool vertical, const std::string &texture,
3255 const std::string &playername, const struct TileAnimationParams &animation,
3258 // m_env will be NULL if the server is initializing
3262 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3263 if (!playername.empty()) {
3264 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3267 peer_id = player->peer_id;
3268 proto_ver = player->protocol_version;
3271 u16 attached_id = attached ? attached->getId() : 0;
3274 if (attached_id == 0)
3275 id = m_env->addParticleSpawner(spawntime);
3277 id = m_env->addParticleSpawner(spawntime, attached_id);
3279 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3280 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3281 minexptime, maxexptime, minsize, maxsize,
3282 collisiondetection, collision_removal, attached_id, vertical,
3283 texture, id, animation, glow);
3288 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3290 // m_env will be NULL if the server is initializing
3292 throw ServerError("Can't delete particle spawners during initialisation!");
3294 u16 peer_id = PEER_ID_INEXISTENT;
3295 if (!playername.empty()) {
3296 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3299 peer_id = player->peer_id;
3302 m_env->deleteParticleSpawner(id);
3303 SendDeleteParticleSpawner(peer_id, id);
3306 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3308 if(m_detached_inventories.count(name) > 0){
3309 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3310 delete m_detached_inventories[name];
3312 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3314 Inventory *inv = new Inventory(m_itemdef);
3316 m_detached_inventories[name] = inv;
3317 m_detached_inventories_player[name] = player;
3318 //TODO find a better way to do this
3319 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3323 // actions: time-reversed list
3324 // Return value: success/failure
3325 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3326 std::list<std::string> *log)
3328 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3329 ServerMap *map = (ServerMap*)(&m_env->getMap());
3331 // Fail if no actions to handle
3332 if(actions.empty()){
3333 log->push_back("Nothing to do.");
3340 for (const RollbackAction &action : actions) {
3342 bool success = action.applyRevert(map, this, this);
3345 std::ostringstream os;
3346 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3347 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3349 log->push_back(os.str());
3351 std::ostringstream os;
3352 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3353 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3355 log->push_back(os.str());
3359 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3360 <<" failed"<<std::endl;
3362 // Call it done if less than half failed
3363 return num_failed <= num_tried/2;
3366 // IGameDef interface
3368 IItemDefManager *Server::getItemDefManager()
3373 INodeDefManager *Server::getNodeDefManager()
3378 ICraftDefManager *Server::getCraftDefManager()
3383 u16 Server::allocateUnknownNodeId(const std::string &name)
3385 return m_nodedef->allocateDummy(name);
3388 MtEventManager *Server::getEventManager()
3393 IWritableItemDefManager *Server::getWritableItemDefManager()
3398 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3403 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3408 const ModSpec *Server::getModSpec(const std::string &modname) const
3410 std::vector<ModSpec>::const_iterator it;
3411 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3412 const ModSpec &mod = *it;
3413 if (mod.name == modname)
3419 void Server::getModNames(std::vector<std::string> &modlist)
3421 std::vector<ModSpec>::iterator it;
3422 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3423 modlist.push_back(it->name);
3426 std::string Server::getBuiltinLuaPath()
3428 return porting::path_share + DIR_DELIM + "builtin";
3431 std::string Server::getModStoragePath() const
3433 return m_path_world + DIR_DELIM + "mod_storage";
3436 v3f Server::findSpawnPos()
3438 ServerMap &map = m_env->getServerMap();
3440 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3441 return nodeposf * BS;
3444 bool is_good = false;
3445 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3446 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3448 // Try to find a good place a few times
3449 for(s32 i = 0; i < 4000 && !is_good; i++) {
3450 s32 range = MYMIN(1 + i, range_max);
3451 // We're going to try to throw the player to this position
3452 v2s16 nodepos2d = v2s16(
3453 -range + (myrand() % (range * 2)),
3454 -range + (myrand() % (range * 2)));
3456 // Get spawn level at point
3457 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3458 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3459 // the mapgen to signify an unsuitable spawn position
3460 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3463 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3466 for (s32 i = 0; i < 10; i++) {
3467 v3s16 blockpos = getNodeBlockPos(nodepos);
3468 map.emergeBlock(blockpos, true);
3469 content_t c = map.getNodeNoEx(nodepos).getContent();
3470 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3472 if (air_count >= 2) {
3473 nodeposf = intToFloat(nodepos, BS);
3474 // Don't spawn the player outside map boundaries
3475 if (objectpos_over_limit(nodeposf))
3488 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3490 m_shutdown_timer = delay;
3491 m_shutdown_msg = msg;
3492 m_shutdown_ask_reconnect = reconnect;
3494 if (delay == 0.0f) {
3495 // No delay, shutdown immediately
3496 m_shutdown_requested = true;
3497 // only print to the infostream, a chat message saying
3498 // "Server Shutting Down" is sent when the server destructs.
3499 infostream << "*** Immediate Server shutdown requested." << std::endl;
3500 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3501 // Negative delay, cancel shutdown if requested
3502 m_shutdown_timer = 0.0f;
3503 m_shutdown_msg = "";
3504 m_shutdown_ask_reconnect = false;
3505 m_shutdown_requested = false;
3506 std::wstringstream ws;
3508 ws << L"*** Server shutdown canceled.";
3510 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3511 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3512 } else if (delay > 0.0f) {
3513 // Positive delay, tell the clients when the server will shut down
3514 std::wstringstream ws;
3516 ws << L"*** Server shutting down in "
3517 << duration_to_string(myround(m_shutdown_timer)).c_str()
3520 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3521 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3525 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3528 Try to get an existing player
3530 RemotePlayer *player = m_env->getPlayer(name);
3532 // If player is already connected, cancel
3533 if (player && player->peer_id != 0) {
3534 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3539 If player with the wanted peer_id already exists, cancel.
3541 if (m_env->getPlayer(peer_id)) {
3542 infostream<<"emergePlayer(): Player with wrong name but same"
3543 " peer_id already exists"<<std::endl;
3548 player = new RemotePlayer(name, idef());
3551 bool newplayer = false;
3554 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3556 // Complete init with server parts
3557 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3558 player->protocol_version = proto_version;
3562 m_script->on_newplayer(playersao);
3568 bool Server::registerModStorage(ModMetadata *storage)
3570 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3571 errorstream << "Unable to register same mod storage twice. Storage name: "
3572 << storage->getModName() << std::endl;
3576 m_mod_storages[storage->getModName()] = storage;
3580 void Server::unregisterModStorage(const std::string &name)
3582 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3583 if (it != m_mod_storages.end()) {
3584 // Save unconditionaly on unregistration
3585 it->second->save(getModStoragePath());
3586 m_mod_storages.erase(name);
3590 void dedicated_server_loop(Server &server, bool &kill)
3592 DSTACK(FUNCTION_NAME);
3594 verbosestream<<"dedicated_server_loop()"<<std::endl;
3596 IntervalLimiter m_profiler_interval;
3598 static thread_local const float steplen =
3599 g_settings->getFloat("dedicated_server_step");
3600 static thread_local const float profiler_print_interval =
3601 g_settings->getFloat("profiler_print_interval");
3604 // This is kind of a hack but can be done like this
3605 // because server.step() is very light
3607 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3608 sleep_ms((int)(steplen*1000.0));
3610 server.step(steplen);
3612 if (server.getShutdownRequested() || kill)
3618 if (profiler_print_interval != 0) {
3619 if(m_profiler_interval.step(steplen, profiler_print_interval))
3621 infostream<<"Profiler:"<<std::endl;
3622 g_profiler->print(infostream);
3623 g_profiler->clear();
3628 infostream << "Dedicated server quitting" << std::endl;
3630 if (g_settings->getBool("server_announce"))
3631 ServerList::sendAnnounce(ServerList::AA_DELETE,
3632 server.m_bind_addr.getPort());