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"
65 class ClientNotFoundException : public BaseException
68 ClientNotFoundException(const char *s):
73 class ServerThread : public Thread
77 ServerThread(Server *server):
88 void *ServerThread::run()
90 DSTACK(FUNCTION_NAME);
91 BEGIN_DEBUG_EXCEPTION_HANDLER
93 m_server->AsyncRunStep(true);
95 while (!stopRequested()) {
97 //TimeTaker timer("AsyncRunStep() + Receive()");
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");
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 != "" && 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 == "") {
330 kick_msg = g_settings->get("kick_msg_shutdown");
332 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
333 kick_msg, reconnect);
335 infostream << "Server: Saving environment metadata" << std::endl;
343 // stop all emerge threads before deleting players that may have
344 // requested blocks to be emerged
345 m_emerge->stopThreads();
347 // Delete things in the reverse order of creation
357 // Deinitialize scripting
358 infostream<<"Server: Deinitializing scripting"<<std::endl;
361 // Delete detached inventories
362 for (std::map<std::string, Inventory*>::iterator
363 i = m_detached_inventories.begin();
364 i != m_detached_inventories.end(); ++i) {
369 void Server::start(Address bind_addr)
371 DSTACK(FUNCTION_NAME);
373 m_bind_addr = bind_addr;
375 infostream<<"Starting server on "
376 << bind_addr.serializeString() <<"..."<<std::endl;
378 // Stop thread if already running
381 // Initialize connection
382 m_con.SetTimeoutMs(30);
383 m_con.Serve(bind_addr);
388 // ASCII art for the win!
390 <<" .__ __ __ "<<std::endl
391 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
392 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
393 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
394 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
395 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
396 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
397 actionstream<<"Server for gameid=\""<<m_gamespec.id
398 <<"\" listening on "<<bind_addr.serializeString()<<":"
399 <<bind_addr.getPort() << "."<<std::endl;
404 DSTACK(FUNCTION_NAME);
406 infostream<<"Server: Stopping and waiting threads"<<std::endl;
408 // Stop threads (set run=false first so both start stopping)
410 //m_emergethread.setRun(false);
412 //m_emergethread.stop();
414 infostream<<"Server: Threads stopped"<<std::endl;
417 void Server::step(float dtime)
419 DSTACK(FUNCTION_NAME);
424 MutexAutoLock lock(m_step_dtime_mutex);
425 m_step_dtime += dtime;
427 // Throw if fatal error occurred in thread
428 std::string async_err = m_async_fatal_error.get();
429 if (!async_err.empty()) {
430 if (!m_simple_singleplayer_mode) {
431 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
432 g_settings->get("kick_msg_crash"),
433 g_settings->getBool("ask_reconnect_on_crash"));
435 throw ServerError("AsyncErr: " + async_err);
439 void Server::AsyncRunStep(bool initial_step)
441 DSTACK(FUNCTION_NAME);
443 g_profiler->add("Server::AsyncRunStep (num)", 1);
447 MutexAutoLock lock1(m_step_dtime_mutex);
448 dtime = m_step_dtime;
452 // Send blocks to clients
456 if((dtime < 0.001) && (initial_step == false))
459 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
461 //infostream<<"Server steps "<<dtime<<std::endl;
462 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
465 MutexAutoLock lock1(m_step_dtime_mutex);
466 m_step_dtime -= dtime;
473 m_uptime.set(m_uptime.get() + dtime);
479 Update time of day and overall game time
481 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
484 Send to clients at constant intervals
487 m_time_of_day_send_timer -= dtime;
488 if(m_time_of_day_send_timer < 0.0) {
489 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
490 u16 time = m_env->getTimeOfDay();
491 float time_speed = g_settings->getFloat("time_speed");
492 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
496 MutexAutoLock lock(m_env_mutex);
497 // Figure out and report maximum lag to environment
498 float max_lag = m_env->getMaxLagEstimate();
499 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
501 if(dtime > 0.1 && dtime > max_lag * 2.0)
502 infostream<<"Server: Maximum lag peaked to "<<dtime
506 m_env->reportMaxLagEstimate(max_lag);
508 ScopeProfiler sp(g_profiler, "SEnv step");
509 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
513 static const float map_timer_and_unload_dtime = 2.92;
514 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
516 MutexAutoLock lock(m_env_mutex);
517 // Run Map's timers and unload unused data
518 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
519 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
520 g_settings->getFloat("server_unload_unused_data_timeout"),
525 Listen to the admin chat, if available
528 if (!m_admin_chat->command_queue.empty()) {
529 MutexAutoLock lock(m_env_mutex);
530 while (!m_admin_chat->command_queue.empty()) {
531 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
532 handleChatInterfaceEvent(evt);
536 m_admin_chat->outgoing_queue.push_back(
537 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
544 /* Transform liquids */
545 m_liquid_transform_timer += dtime;
546 if(m_liquid_transform_timer >= m_liquid_transform_every)
548 m_liquid_transform_timer -= m_liquid_transform_every;
550 MutexAutoLock lock(m_env_mutex);
552 ScopeProfiler sp(g_profiler, "Server: liquid transform");
554 std::map<v3s16, MapBlock*> modified_blocks;
555 m_env->getMap().transformLiquids(modified_blocks, m_env);
560 core::map<v3s16, MapBlock*> lighting_modified_blocks;
561 ServerMap &map = ((ServerMap&)m_env->getMap());
562 map.updateLighting(modified_blocks, lighting_modified_blocks);
564 // Add blocks modified by lighting to modified_blocks
565 for(core::map<v3s16, MapBlock*>::Iterator
566 i = lighting_modified_blocks.getIterator();
567 i.atEnd() == false; i++)
569 MapBlock *block = i.getNode()->getValue();
570 modified_blocks.insert(block->getPos(), block);
574 Set the modified blocks unsent for all the clients
576 if(!modified_blocks.empty())
578 SetBlocksNotSent(modified_blocks);
581 m_clients.step(dtime);
583 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
585 // send masterserver announce
587 float &counter = m_masterserver_timer;
588 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
589 g_settings->getBool("server_announce")) {
590 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
591 ServerList::AA_START,
592 m_bind_addr.getPort(),
593 m_clients.getPlayerNames(),
595 m_env->getGameTime(),
598 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
608 Check added and deleted active objects
611 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
612 MutexAutoLock envlock(m_env_mutex);
615 RemoteClientMap clients = m_clients.getClientList();
616 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
618 // Radius inside which objects are active
619 static thread_local const s16 radius =
620 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
622 // Radius inside which players are active
623 static thread_local const bool is_transfer_limited =
624 g_settings->exists("unlimited_player_transfer_distance") &&
625 !g_settings->getBool("unlimited_player_transfer_distance");
626 static thread_local const s16 player_transfer_dist =
627 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
628 s16 player_radius = player_transfer_dist;
629 if (player_radius == 0 && is_transfer_limited)
630 player_radius = radius;
632 for (RemoteClientMap::iterator i = clients.begin();
633 i != clients.end(); ++i) {
634 RemoteClient *client = i->second;
636 // If definitions and textures have not been sent, don't
637 // send objects either
638 if (client->getState() < CS_DefinitionsSent)
641 RemotePlayer *player = m_env->getPlayer(client->peer_id);
642 if (player == NULL) {
643 // This can happen if the client timeouts somehow
644 /*warningstream<<FUNCTION_NAME<<": Client "
646 <<" has no associated player"<<std::endl;*/
650 PlayerSAO *playersao = player->getPlayerSAO();
651 if (playersao == NULL)
654 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
655 if (my_radius <= 0) my_radius = radius;
656 //infostream << "Server: Active Radius " << my_radius << std::endl;
658 std::queue<u16> removed_objects;
659 std::queue<u16> added_objects;
660 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
661 client->m_known_objects, removed_objects);
662 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
663 client->m_known_objects, added_objects);
665 // Ignore if nothing happened
666 if (removed_objects.empty() && added_objects.empty()) {
670 std::string data_buffer;
674 // Handle removed objects
675 writeU16((u8*)buf, removed_objects.size());
676 data_buffer.append(buf, 2);
677 while (!removed_objects.empty()) {
679 u16 id = removed_objects.front();
680 ServerActiveObject* obj = m_env->getActiveObject(id);
682 // Add to data buffer for sending
683 writeU16((u8*)buf, id);
684 data_buffer.append(buf, 2);
686 // Remove from known objects
687 client->m_known_objects.erase(id);
689 if(obj && obj->m_known_by_count > 0)
690 obj->m_known_by_count--;
691 removed_objects.pop();
694 // Handle added objects
695 writeU16((u8*)buf, added_objects.size());
696 data_buffer.append(buf, 2);
697 while (!added_objects.empty()) {
699 u16 id = added_objects.front();
700 ServerActiveObject* obj = m_env->getActiveObject(id);
703 u8 type = ACTIVEOBJECT_TYPE_INVALID;
705 warningstream<<FUNCTION_NAME
706 <<": NULL object"<<std::endl;
708 type = obj->getSendType();
710 // Add to data buffer for sending
711 writeU16((u8*)buf, id);
712 data_buffer.append(buf, 2);
713 writeU8((u8*)buf, type);
714 data_buffer.append(buf, 1);
717 data_buffer.append(serializeLongString(
718 obj->getClientInitializationData(client->net_proto_version)));
720 data_buffer.append(serializeLongString(""));
722 // Add to known objects
723 client->m_known_objects.insert(id);
726 obj->m_known_by_count++;
731 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
732 verbosestream << "Server: Sent object remove/add: "
733 << removed_objects.size() << " removed, "
734 << added_objects.size() << " added, "
735 << "packet size is " << pktSize << std::endl;
739 m_mod_storage_save_timer -= dtime;
740 if (m_mod_storage_save_timer <= 0.0f) {
741 infostream << "Saving registered mod storages." << std::endl;
742 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
743 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
744 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
745 if (it->second->isModified()) {
746 it->second->save(getModStoragePath());
756 MutexAutoLock envlock(m_env_mutex);
757 ScopeProfiler sp(g_profiler, "Server: sending object messages");
760 // Value = data sent by object
761 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
763 // Get active object messages from environment
765 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
769 std::vector<ActiveObjectMessage>* message_list = NULL;
770 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
771 n = buffered_messages.find(aom.id);
772 if (n == buffered_messages.end()) {
773 message_list = new std::vector<ActiveObjectMessage>;
774 buffered_messages[aom.id] = message_list;
777 message_list = n->second;
779 message_list->push_back(aom);
783 RemoteClientMap clients = m_clients.getClientList();
784 // Route data to every client
785 for (std::unordered_map<u16, RemoteClient*>::iterator i = clients.begin();
786 i != clients.end(); ++i) {
787 RemoteClient *client = i->second;
788 std::string reliable_data;
789 std::string unreliable_data;
790 // Go through all objects in message buffer
791 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
792 j = buffered_messages.begin();
793 j != buffered_messages.end(); ++j) {
794 // If object is not known by client, skip it
796 if (client->m_known_objects.find(id) == client->m_known_objects.end())
799 // Get message list of object
800 std::vector<ActiveObjectMessage>* list = j->second;
801 // Go through every message
802 for (std::vector<ActiveObjectMessage>::iterator
803 k = list->begin(); k != list->end(); ++k) {
804 // Compose the full new data with header
805 ActiveObjectMessage aom = *k;
806 std::string new_data;
809 writeU16((u8*)&buf[0], aom.id);
810 new_data.append(buf, 2);
812 new_data += serializeString(aom.datastring);
813 // Add data to buffer
815 reliable_data += new_data;
817 unreliable_data += new_data;
821 reliable_data and unreliable_data are now ready.
824 if(reliable_data.size() > 0) {
825 SendActiveObjectMessages(client->peer_id, reliable_data);
828 if(unreliable_data.size() > 0) {
829 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
834 // Clear buffered_messages
835 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
836 i = buffered_messages.begin();
837 i != buffered_messages.end(); ++i) {
843 Send queued-for-sending map edit events.
846 // We will be accessing the environment
847 MutexAutoLock lock(m_env_mutex);
849 // Don't send too many at a time
852 // Single change sending is disabled if queue size is not small
853 bool disable_single_change_sending = false;
854 if(m_unsent_map_edit_queue.size() >= 4)
855 disable_single_change_sending = true;
857 int event_count = m_unsent_map_edit_queue.size();
859 // We'll log the amount of each
862 while(m_unsent_map_edit_queue.size() != 0)
864 MapEditEvent* event = m_unsent_map_edit_queue.front();
865 m_unsent_map_edit_queue.pop();
867 // Players far away from the change are stored here.
868 // Instead of sending the changes, MapBlocks are set not sent
870 std::vector<u16> far_players;
872 switch (event->type) {
875 prof.add("MEET_ADDNODE", 1);
876 sendAddNode(event->p, event->n, event->already_known_by_peer,
877 &far_players, disable_single_change_sending ? 5 : 30,
878 event->type == MEET_ADDNODE);
880 case MEET_REMOVENODE:
881 prof.add("MEET_REMOVENODE", 1);
882 sendRemoveNode(event->p, event->already_known_by_peer,
883 &far_players, disable_single_change_sending ? 5 : 30);
885 case MEET_BLOCK_NODE_METADATA_CHANGED:
886 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
887 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
888 setBlockNotSent(event->p);
891 infostream << "Server: MEET_OTHER" << std::endl;
892 prof.add("MEET_OTHER", 1);
893 for(std::set<v3s16>::iterator
894 i = event->modified_blocks.begin();
895 i != event->modified_blocks.end(); ++i) {
900 prof.add("unknown", 1);
901 warningstream << "Server: Unknown MapEditEvent "
902 << ((u32)event->type) << std::endl;
907 Set blocks not sent to far players
909 if(!far_players.empty()) {
910 // Convert list format to that wanted by SetBlocksNotSent
911 std::map<v3s16, MapBlock*> modified_blocks2;
912 for(std::set<v3s16>::iterator
913 i = event->modified_blocks.begin();
914 i != event->modified_blocks.end(); ++i) {
915 modified_blocks2[*i] =
916 m_env->getMap().getBlockNoCreateNoEx(*i);
919 // Set blocks not sent
920 for(std::vector<u16>::iterator
921 i = far_players.begin();
922 i != far_players.end(); ++i) {
923 if(RemoteClient *client = getClient(*i))
924 client->SetBlocksNotSent(modified_blocks2);
930 /*// Don't send too many at a time
932 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
936 if(event_count >= 5){
937 infostream<<"Server: MapEditEvents:"<<std::endl;
938 prof.print(infostream);
939 } else if(event_count != 0){
940 verbosestream<<"Server: MapEditEvents:"<<std::endl;
941 prof.print(verbosestream);
947 Trigger emergethread (it somehow gets to a non-triggered but
948 bysy state sometimes)
951 float &counter = m_emergethread_trigger_timer;
953 if (counter >= 2.0) {
956 m_emerge->startThreads();
960 // Save map, players and auth stuff
962 float &counter = m_savemap_timer;
964 static thread_local const float save_interval =
965 g_settings->getFloat("server_map_save_interval");
966 if (counter >= save_interval) {
968 MutexAutoLock lock(m_env_mutex);
970 ScopeProfiler sp(g_profiler, "Server: saving stuff");
973 if (m_banmanager->isModified()) {
974 m_banmanager->save();
977 // Save changed parts of map
978 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
981 m_env->saveLoadedPlayers();
983 // Save environment metadata
989 static const float shutdown_msg_times[] =
991 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
994 if (m_shutdown_timer > 0.0f) {
995 // Automated messages
996 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
997 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
998 // If shutdown timer matches an automessage, shot it
999 if (m_shutdown_timer > shutdown_msg_times[i] &&
1000 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1001 std::wstringstream ws;
1003 ws << L"*** Server shutting down in "
1004 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1007 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1008 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1014 m_shutdown_timer -= dtime;
1015 if (m_shutdown_timer < 0.0f) {
1016 m_shutdown_timer = 0.0f;
1017 m_shutdown_requested = true;
1022 void Server::Receive()
1024 DSTACK(FUNCTION_NAME);
1028 m_con.Receive(&pkt);
1029 peer_id = pkt.getPeerId();
1032 catch(con::InvalidIncomingDataException &e) {
1033 infostream<<"Server::Receive(): "
1034 "InvalidIncomingDataException: what()="
1035 <<e.what()<<std::endl;
1037 catch(SerializationError &e) {
1038 infostream<<"Server::Receive(): "
1039 "SerializationError: what()="
1040 <<e.what()<<std::endl;
1042 catch(ClientStateError &e) {
1043 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1044 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1045 L"Try reconnecting or updating your client");
1047 catch(con::PeerNotFoundException &e) {
1052 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1054 std::string playername = "";
1055 PlayerSAO *playersao = NULL;
1058 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1059 if (client != NULL) {
1060 playername = client->getName();
1061 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1063 } catch (std::exception &e) {
1069 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1071 // If failed, cancel
1072 if ((playersao == NULL) || (player == NULL)) {
1073 if (player && player->peer_id != 0) {
1074 actionstream << "Server: Failed to emerge player \"" << playername
1075 << "\" (player allocated to an another client)" << std::endl;
1076 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1077 L"name. If your client closed unexpectedly, try again in "
1080 errorstream << "Server: " << playername << ": Failed to emerge player"
1082 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1088 Send complete position information
1090 SendMovePlayer(peer_id);
1093 SendPlayerPrivileges(peer_id);
1095 // Send inventory formspec
1096 SendPlayerInventoryFormspec(peer_id);
1099 SendInventory(playersao);
1101 // Send HP or death screen
1102 if (playersao->isDead())
1103 SendDeathscreen(peer_id, false, v3f(0,0,0));
1105 SendPlayerHPOrDie(playersao);
1108 SendPlayerBreath(playersao);
1110 // Note things in chat if not in simple singleplayer mode
1111 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1112 // Send information about server to player in chat
1113 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1115 Address addr = getPeerAddress(player->peer_id);
1116 std::string ip_str = addr.serializeString();
1117 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1122 const std::vector<std::string> &names = m_clients.getPlayerNames();
1124 actionstream << player->getName() << " joins game. List of players: ";
1126 for (std::vector<std::string>::const_iterator i = names.begin();
1127 i != names.end(); ++i) {
1128 actionstream << *i << " ";
1131 actionstream << player->getName() <<std::endl;
1136 inline void Server::handleCommand(NetworkPacket* pkt)
1138 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1139 (this->*opHandle.handler)(pkt);
1142 void Server::ProcessData(NetworkPacket *pkt)
1144 DSTACK(FUNCTION_NAME);
1145 // Environment is locked first.
1146 MutexAutoLock envlock(m_env_mutex);
1148 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1149 u32 peer_id = pkt->getPeerId();
1152 Address address = getPeerAddress(peer_id);
1153 std::string addr_s = address.serializeString();
1155 if(m_banmanager->isIpBanned(addr_s)) {
1156 std::string ban_name = m_banmanager->getBanName(addr_s);
1157 infostream << "Server: A banned client tried to connect from "
1158 << addr_s << "; banned name was "
1159 << ban_name << std::endl;
1160 // This actually doesn't seem to transfer to the client
1161 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1162 + utf8_to_wide(ban_name));
1166 catch(con::PeerNotFoundException &e) {
1168 * no peer for this packet found
1169 * most common reason is peer timeout, e.g. peer didn't
1170 * respond for some time, your server was overloaded or
1173 infostream << "Server::ProcessData(): Canceling: peer "
1174 << peer_id << " not found" << std::endl;
1179 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1181 // Command must be handled into ToServerCommandHandler
1182 if (command >= TOSERVER_NUM_MSG_TYPES) {
1183 infostream << "Server: Ignoring unknown command "
1184 << command << std::endl;
1188 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1193 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1195 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1196 errorstream << "Server::ProcessData(): Cancelling: Peer"
1197 " serialization format invalid or not initialized."
1198 " Skipping incoming command=" << command << std::endl;
1202 /* Handle commands related to client startup */
1203 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1208 if (m_clients.getClientState(peer_id) < CS_Active) {
1209 if (command == TOSERVER_PLAYERPOS) return;
1211 errorstream << "Got packet command: " << command << " for peer id "
1212 << peer_id << " but client isn't active yet. Dropping packet "
1218 } catch (SendFailedException &e) {
1219 errorstream << "Server::ProcessData(): SendFailedException: "
1220 << "what=" << e.what()
1222 } catch (PacketError &e) {
1223 actionstream << "Server::ProcessData(): PacketError: "
1224 << "what=" << e.what()
1229 void Server::setTimeOfDay(u32 time)
1231 m_env->setTimeOfDay(time);
1232 m_time_of_day_send_timer = 0;
1235 void Server::onMapEditEvent(MapEditEvent *event)
1237 if(m_ignore_map_edit_events)
1239 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1241 MapEditEvent *e = event->clone();
1242 m_unsent_map_edit_queue.push(e);
1245 Inventory* Server::getInventory(const InventoryLocation &loc)
1248 case InventoryLocation::UNDEFINED:
1249 case InventoryLocation::CURRENT_PLAYER:
1251 case InventoryLocation::PLAYER:
1253 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1256 PlayerSAO *playersao = player->getPlayerSAO();
1259 return playersao->getInventory();
1262 case InventoryLocation::NODEMETA:
1264 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1267 return meta->getInventory();
1270 case InventoryLocation::DETACHED:
1272 if(m_detached_inventories.count(loc.name) == 0)
1274 return m_detached_inventories[loc.name];
1278 sanity_check(false); // abort
1283 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1286 case InventoryLocation::UNDEFINED:
1288 case InventoryLocation::PLAYER:
1293 RemotePlayer *player =
1294 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1299 PlayerSAO *playersao = player->getPlayerSAO();
1303 SendInventory(playersao);
1306 case InventoryLocation::NODEMETA:
1308 v3s16 blockpos = getNodeBlockPos(loc.p);
1310 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1312 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1314 setBlockNotSent(blockpos);
1317 case InventoryLocation::DETACHED:
1319 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1323 sanity_check(false); // abort
1328 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1330 std::vector<u16> clients = m_clients.getClientIDs();
1332 // Set the modified blocks unsent for all the clients
1333 for (std::vector<u16>::iterator i = clients.begin();
1334 i != clients.end(); ++i) {
1335 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1336 client->SetBlocksNotSent(block);
1341 void Server::peerAdded(con::Peer *peer)
1343 DSTACK(FUNCTION_NAME);
1344 verbosestream<<"Server::peerAdded(): peer->id="
1345 <<peer->id<<std::endl;
1348 c.type = con::PEER_ADDED;
1349 c.peer_id = peer->id;
1351 m_peer_change_queue.push(c);
1354 void Server::deletingPeer(con::Peer *peer, bool timeout)
1356 DSTACK(FUNCTION_NAME);
1357 verbosestream<<"Server::deletingPeer(): peer->id="
1358 <<peer->id<<", timeout="<<timeout<<std::endl;
1360 m_clients.event(peer->id, CSE_Disconnect);
1362 c.type = con::PEER_REMOVED;
1363 c.peer_id = peer->id;
1364 c.timeout = timeout;
1365 m_peer_change_queue.push(c);
1368 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1370 *retval = m_con.getPeerStat(peer_id,type);
1371 if (*retval == -1) return false;
1375 bool Server::getClientInfo(
1384 std::string* vers_string
1387 *state = m_clients.getClientState(peer_id);
1389 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1391 if (client == NULL) {
1396 *uptime = client->uptime();
1397 *ser_vers = client->serialization_version;
1398 *prot_vers = client->net_proto_version;
1400 *major = client->getMajor();
1401 *minor = client->getMinor();
1402 *patch = client->getPatch();
1403 *vers_string = client->getPatch();
1410 void Server::handlePeerChanges()
1412 while(m_peer_change_queue.size() > 0)
1414 con::PeerChange c = m_peer_change_queue.front();
1415 m_peer_change_queue.pop();
1417 verbosestream<<"Server: Handling peer change: "
1418 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1423 case con::PEER_ADDED:
1424 m_clients.CreateClient(c.peer_id);
1427 case con::PEER_REMOVED:
1428 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1432 FATAL_ERROR("Invalid peer change event received!");
1438 void Server::printToConsoleOnly(const std::string &text)
1441 m_admin_chat->outgoing_queue.push_back(
1442 new ChatEventChat("", utf8_to_wide(text)));
1444 std::cout << text << std::endl;
1448 void Server::Send(NetworkPacket* pkt)
1450 m_clients.send(pkt->getPeerId(),
1451 clientCommandFactoryTable[pkt->getCommand()].channel,
1453 clientCommandFactoryTable[pkt->getCommand()].reliable);
1456 void Server::SendMovement(u16 peer_id)
1458 DSTACK(FUNCTION_NAME);
1459 std::ostringstream os(std::ios_base::binary);
1461 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1463 pkt << g_settings->getFloat("movement_acceleration_default");
1464 pkt << g_settings->getFloat("movement_acceleration_air");
1465 pkt << g_settings->getFloat("movement_acceleration_fast");
1466 pkt << g_settings->getFloat("movement_speed_walk");
1467 pkt << g_settings->getFloat("movement_speed_crouch");
1468 pkt << g_settings->getFloat("movement_speed_fast");
1469 pkt << g_settings->getFloat("movement_speed_climb");
1470 pkt << g_settings->getFloat("movement_speed_jump");
1471 pkt << g_settings->getFloat("movement_liquid_fluidity");
1472 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1473 pkt << g_settings->getFloat("movement_liquid_sink");
1474 pkt << g_settings->getFloat("movement_gravity");
1479 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1481 if (!g_settings->getBool("enable_damage"))
1484 u16 peer_id = playersao->getPeerID();
1485 bool is_alive = playersao->getHP() > 0;
1488 SendPlayerHP(peer_id);
1493 void Server::SendHP(u16 peer_id, u8 hp)
1495 DSTACK(FUNCTION_NAME);
1497 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1502 void Server::SendBreath(u16 peer_id, u16 breath)
1504 DSTACK(FUNCTION_NAME);
1506 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1507 pkt << (u16) breath;
1511 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1512 const std::string &custom_reason, bool reconnect)
1514 assert(reason < SERVER_ACCESSDENIED_MAX);
1516 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1518 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1519 pkt << custom_reason;
1520 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1521 reason == SERVER_ACCESSDENIED_CRASH)
1522 pkt << custom_reason << (u8)reconnect;
1526 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1528 DSTACK(FUNCTION_NAME);
1530 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1535 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1536 v3f camera_point_target)
1538 DSTACK(FUNCTION_NAME);
1540 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1541 pkt << set_camera_point_target << camera_point_target;
1545 void Server::SendItemDef(u16 peer_id,
1546 IItemDefManager *itemdef, u16 protocol_version)
1548 DSTACK(FUNCTION_NAME);
1550 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1554 u32 length of the next item
1555 zlib-compressed serialized ItemDefManager
1557 std::ostringstream tmp_os(std::ios::binary);
1558 itemdef->serialize(tmp_os, protocol_version);
1559 std::ostringstream tmp_os2(std::ios::binary);
1560 compressZlib(tmp_os.str(), tmp_os2);
1561 pkt.putLongString(tmp_os2.str());
1564 verbosestream << "Server: Sending item definitions to id(" << peer_id
1565 << "): size=" << pkt.getSize() << std::endl;
1570 void Server::SendNodeDef(u16 peer_id,
1571 INodeDefManager *nodedef, u16 protocol_version)
1573 DSTACK(FUNCTION_NAME);
1575 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1579 u32 length of the next item
1580 zlib-compressed serialized NodeDefManager
1582 std::ostringstream tmp_os(std::ios::binary);
1583 nodedef->serialize(tmp_os, protocol_version);
1584 std::ostringstream tmp_os2(std::ios::binary);
1585 compressZlib(tmp_os.str(), tmp_os2);
1587 pkt.putLongString(tmp_os2.str());
1590 verbosestream << "Server: Sending node definitions to id(" << peer_id
1591 << "): size=" << pkt.getSize() << std::endl;
1597 Non-static send methods
1600 void Server::SendInventory(PlayerSAO* playerSAO)
1602 DSTACK(FUNCTION_NAME);
1604 UpdateCrafting(playerSAO->getPlayer());
1610 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1612 std::ostringstream os;
1613 playerSAO->getInventory()->serialize(os);
1615 std::string s = os.str();
1617 pkt.putRawString(s.c_str(), s.size());
1621 void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
1623 DSTACK(FUNCTION_NAME);
1625 NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
1626 legacypkt << message.message;
1628 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1630 u8 type = message.type;
1631 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1633 if (peer_id != PEER_ID_INEXISTENT) {
1634 RemotePlayer *player = m_env->getPlayer(peer_id);
1638 if (player->protocol_version < 35)
1643 m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
1647 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1648 const std::string &formname)
1650 DSTACK(FUNCTION_NAME);
1652 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1653 if (formspec == "" ){
1654 //the client should close the formspec
1655 pkt.putLongString("");
1657 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1664 // Spawns a particle on peer with peer_id
1665 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1666 v3f pos, v3f velocity, v3f acceleration,
1667 float expirationtime, float size, bool collisiondetection,
1668 bool collision_removal,
1669 bool vertical, const std::string &texture,
1670 const struct TileAnimationParams &animation, u8 glow)
1672 DSTACK(FUNCTION_NAME);
1673 static thread_local const float radius =
1674 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1676 if (peer_id == PEER_ID_INEXISTENT) {
1677 std::vector<u16> clients = m_clients.getClientIDs();
1679 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1680 RemotePlayer *player = m_env->getPlayer(*i);
1684 PlayerSAO *sao = player->getPlayerSAO();
1688 // Do not send to distant clients
1689 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1692 SendSpawnParticle(*i, player->protocol_version,
1693 pos, velocity, acceleration,
1694 expirationtime, size, collisiondetection,
1695 collision_removal, vertical, texture, animation, glow);
1700 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1702 pkt << pos << velocity << acceleration << expirationtime
1703 << size << collisiondetection;
1704 pkt.putLongString(texture);
1706 pkt << collision_removal;
1707 // This is horrible but required (why are there two ways to serialize pkts?)
1708 std::ostringstream os(std::ios_base::binary);
1709 animation.serialize(os, protocol_version);
1710 pkt.putRawString(os.str());
1716 // Adds a ParticleSpawner on peer with peer_id
1717 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1718 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1719 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1720 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1721 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1722 const struct TileAnimationParams &animation, u8 glow)
1724 DSTACK(FUNCTION_NAME);
1725 if (peer_id == PEER_ID_INEXISTENT) {
1726 // This sucks and should be replaced:
1727 std::vector<u16> clients = m_clients.getClientIDs();
1728 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1729 RemotePlayer *player = m_env->getPlayer(*i);
1732 SendAddParticleSpawner(*i, player->protocol_version,
1733 amount, spawntime, minpos, maxpos,
1734 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1735 minsize, maxsize, collisiondetection, collision_removal,
1736 attached_id, vertical, texture, id, animation, glow);
1741 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1743 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1744 << minacc << maxacc << minexptime << maxexptime << minsize
1745 << maxsize << collisiondetection;
1747 pkt.putLongString(texture);
1749 pkt << id << vertical;
1750 pkt << collision_removal;
1752 // This is horrible but required
1753 std::ostringstream os(std::ios_base::binary);
1754 animation.serialize(os, protocol_version);
1755 pkt.putRawString(os.str());
1761 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1763 DSTACK(FUNCTION_NAME);
1765 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1767 // Ugly error in this packet
1770 if (peer_id != PEER_ID_INEXISTENT) {
1774 m_clients.sendToAll(&pkt);
1779 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1781 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1783 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1784 << form->text << form->number << form->item << form->dir
1785 << form->align << form->offset << form->world_pos << form->size;
1790 void Server::SendHUDRemove(u16 peer_id, u32 id)
1792 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1797 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1799 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1800 pkt << id << (u8) stat;
1804 case HUD_STAT_SCALE:
1805 case HUD_STAT_ALIGN:
1806 case HUD_STAT_OFFSET:
1807 pkt << *(v2f *) value;
1811 pkt << *(std::string *) value;
1813 case HUD_STAT_WORLD_POS:
1814 pkt << *(v3f *) value;
1817 pkt << *(v2s32 *) value;
1819 case HUD_STAT_NUMBER:
1823 pkt << *(u32 *) value;
1830 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1832 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1834 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1836 pkt << flags << mask;
1841 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1843 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1844 pkt << param << value;
1848 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1849 const std::string &type, const std::vector<std::string> ¶ms,
1852 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1853 pkt << bgcolor << type << (u16) params.size();
1855 for(size_t i=0; i<params.size(); i++)
1863 void Server::SendCloudParams(u16 peer_id, float density,
1864 const video::SColor &color_bright,
1865 const video::SColor &color_ambient,
1870 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1871 pkt << density << color_bright << color_ambient
1872 << height << thickness << speed;
1877 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1880 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1883 pkt << do_override << (u16) (ratio * 65535);
1888 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1890 DSTACK(FUNCTION_NAME);
1892 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1893 pkt << time << time_speed;
1895 if (peer_id == PEER_ID_INEXISTENT) {
1896 m_clients.sendToAll(&pkt);
1903 void Server::SendPlayerHP(u16 peer_id)
1905 DSTACK(FUNCTION_NAME);
1906 PlayerSAO *playersao = getPlayerSAO(peer_id);
1907 // In some rare case if the player is disconnected
1908 // while Lua call l_punch, for example, this can be NULL
1912 SendHP(peer_id, playersao->getHP());
1913 m_script->player_event(playersao,"health_changed");
1915 // Send to other clients
1916 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1917 ActiveObjectMessage aom(playersao->getId(), true, str);
1918 playersao->m_messages_out.push(aom);
1921 void Server::SendPlayerBreath(PlayerSAO *sao)
1923 DSTACK(FUNCTION_NAME);
1926 m_script->player_event(sao, "breath_changed");
1927 SendBreath(sao->getPeerID(), sao->getBreath());
1930 void Server::SendMovePlayer(u16 peer_id)
1932 DSTACK(FUNCTION_NAME);
1933 RemotePlayer *player = m_env->getPlayer(peer_id);
1935 PlayerSAO *sao = player->getPlayerSAO();
1938 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1939 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1942 v3f pos = sao->getBasePosition();
1943 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1944 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1945 << " pitch=" << sao->getPitch()
1946 << " yaw=" << sao->getYaw()
1953 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1955 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1958 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1959 << animation_frames[3] << animation_speed;
1964 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1966 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1967 pkt << first << third;
1970 void Server::SendPlayerPrivileges(u16 peer_id)
1972 RemotePlayer *player = m_env->getPlayer(peer_id);
1974 if(player->peer_id == PEER_ID_INEXISTENT)
1977 std::set<std::string> privs;
1978 m_script->getAuth(player->getName(), NULL, &privs);
1980 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1981 pkt << (u16) privs.size();
1983 for(std::set<std::string>::const_iterator i = privs.begin();
1984 i != privs.end(); ++i) {
1991 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1993 RemotePlayer *player = m_env->getPlayer(peer_id);
1995 if(player->peer_id == PEER_ID_INEXISTENT)
1998 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1999 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2003 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2005 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2006 pkt.putRawString(datas.c_str(), datas.size());
2008 return pkt.getSize();
2011 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2013 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2014 datas.size(), peer_id);
2016 pkt.putRawString(datas.c_str(), datas.size());
2018 m_clients.send(pkt.getPeerId(),
2019 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2023 void Server::SendCSMFlavourLimits(u16 peer_id)
2025 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
2026 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
2027 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
2031 s32 Server::playSound(const SimpleSoundSpec &spec,
2032 const ServerSoundParams ¶ms)
2034 // Find out initial position of sound
2035 bool pos_exists = false;
2036 v3f pos = params.getPos(m_env, &pos_exists);
2037 // If position is not found while it should be, cancel sound
2038 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2041 // Filter destination clients
2042 std::vector<u16> dst_clients;
2043 if(params.to_player != "")
2045 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2047 infostream<<"Server::playSound: Player \""<<params.to_player
2048 <<"\" not found"<<std::endl;
2051 if(player->peer_id == PEER_ID_INEXISTENT){
2052 infostream<<"Server::playSound: Player \""<<params.to_player
2053 <<"\" not connected"<<std::endl;
2056 dst_clients.push_back(player->peer_id);
2059 std::vector<u16> clients = m_clients.getClientIDs();
2061 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2062 RemotePlayer *player = m_env->getPlayer(*i);
2066 PlayerSAO *sao = player->getPlayerSAO();
2071 if(sao->getBasePosition().getDistanceFrom(pos) >
2072 params.max_hear_distance)
2075 dst_clients.push_back(*i);
2079 if(dst_clients.empty())
2083 s32 id = m_next_sound_id++;
2084 // The sound will exist as a reference in m_playing_sounds
2085 m_playing_sounds[id] = ServerPlayingSound();
2086 ServerPlayingSound &psound = m_playing_sounds[id];
2087 psound.params = params;
2090 float gain = params.gain * spec.gain;
2091 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2092 pkt << id << spec.name << gain
2093 << (u8) params.type << pos << params.object
2094 << params.loop << params.fade << params.pitch;
2096 // Backwards compability
2097 bool play_sound = gain > 0;
2099 for (std::vector<u16>::iterator i = dst_clients.begin();
2100 i != dst_clients.end(); ++i) {
2101 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2102 psound.clients.insert(*i);
2103 m_clients.send(*i, 0, &pkt, true);
2108 void Server::stopSound(s32 handle)
2110 // Get sound reference
2111 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2112 m_playing_sounds.find(handle);
2113 if (i == m_playing_sounds.end())
2115 ServerPlayingSound &psound = i->second;
2117 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2120 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2121 si != psound.clients.end(); ++si) {
2123 m_clients.send(*si, 0, &pkt, true);
2125 // Remove sound reference
2126 m_playing_sounds.erase(i);
2129 void Server::fadeSound(s32 handle, float step, float gain)
2131 // Get sound reference
2132 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2133 m_playing_sounds.find(handle);
2134 if (i == m_playing_sounds.end())
2137 ServerPlayingSound &psound = i->second;
2138 psound.params.gain = gain;
2140 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2141 pkt << handle << step << gain;
2143 // Backwards compability
2144 bool play_sound = gain > 0;
2145 ServerPlayingSound compat_psound = psound;
2146 compat_psound.clients.clear();
2148 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2149 compat_pkt << handle;
2151 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2152 it != psound.clients.end();) {
2153 if (m_clients.getProtocolVersion(*it) >= 32) {
2155 m_clients.send(*it, 0, &pkt, true);
2158 compat_psound.clients.insert(*it);
2160 m_clients.send(*it, 0, &compat_pkt, true);
2161 psound.clients.erase(it++);
2165 // Remove sound reference
2166 if (!play_sound || psound.clients.size() == 0)
2167 m_playing_sounds.erase(i);
2169 if (play_sound && compat_psound.clients.size() > 0) {
2170 // Play new sound volume on older clients
2171 playSound(compat_psound.spec, compat_psound.params);
2175 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2176 std::vector<u16> *far_players, float far_d_nodes)
2178 float maxd = far_d_nodes*BS;
2179 v3f p_f = intToFloat(p, BS);
2181 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2184 std::vector<u16> clients = m_clients.getClientIDs();
2185 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2188 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2189 PlayerSAO *sao = player->getPlayerSAO();
2193 // If player is far away, only set modified blocks not sent
2194 v3f player_pos = sao->getBasePosition();
2195 if (player_pos.getDistanceFrom(p_f) > maxd) {
2196 far_players->push_back(*i);
2203 m_clients.send(*i, 0, &pkt, true);
2207 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2208 std::vector<u16> *far_players, float far_d_nodes,
2209 bool remove_metadata)
2211 float maxd = far_d_nodes*BS;
2212 v3f p_f = intToFloat(p, BS);
2214 std::vector<u16> clients = m_clients.getClientIDs();
2215 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2218 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2219 PlayerSAO *sao = player->getPlayerSAO();
2223 // If player is far away, only set modified blocks not sent
2224 v3f player_pos = sao->getBasePosition();
2225 if(player_pos.getDistanceFrom(p_f) > maxd) {
2226 far_players->push_back(*i);
2232 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2234 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2236 pkt << p << n.param0 << n.param1 << n.param2
2237 << (u8) (remove_metadata ? 0 : 1);
2242 if (pkt.getSize() > 0)
2243 m_clients.send(*i, 0, &pkt, true);
2247 void Server::setBlockNotSent(v3s16 p)
2249 std::vector<u16> clients = m_clients.getClientIDs();
2251 for(std::vector<u16>::iterator i = clients.begin();
2252 i != clients.end(); ++i) {
2253 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2254 client->SetBlockNotSent(p);
2259 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2261 DSTACK(FUNCTION_NAME);
2263 v3s16 p = block->getPos();
2266 Create a packet with the block in the right format
2269 std::ostringstream os(std::ios_base::binary);
2270 block->serialize(os, ver, false);
2271 block->serializeNetworkSpecific(os);
2272 std::string s = os.str();
2274 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2277 pkt.putRawString(s.c_str(), s.size());
2281 void Server::SendBlocks(float dtime)
2283 DSTACK(FUNCTION_NAME);
2285 MutexAutoLock envlock(m_env_mutex);
2286 //TODO check if one big lock could be faster then multiple small ones
2288 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2290 std::vector<PrioritySortedBlockTransfer> queue;
2292 s32 total_sending = 0;
2295 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2297 std::vector<u16> clients = m_clients.getClientIDs();
2300 for(std::vector<u16>::iterator i = clients.begin();
2301 i != clients.end(); ++i) {
2302 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2307 total_sending += client->SendingCount();
2308 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2314 // Lowest priority number comes first.
2315 // Lowest is most important.
2316 std::sort(queue.begin(), queue.end());
2319 for(u32 i=0; i<queue.size(); i++)
2321 //TODO: Calculate limit dynamically
2322 if(total_sending >= g_settings->getS32
2323 ("max_simultaneous_block_sends_server_total"))
2326 PrioritySortedBlockTransfer q = queue[i];
2328 MapBlock *block = NULL;
2331 block = m_env->getMap().getBlockNoCreate(q.pos);
2333 catch(InvalidPositionException &e)
2338 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2343 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2345 client->SentBlock(q.pos);
2351 void Server::fillMediaCache()
2353 DSTACK(FUNCTION_NAME);
2355 infostream<<"Server: Calculating media file checksums"<<std::endl;
2357 // Collect all media file paths
2358 std::vector<std::string> paths;
2359 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2360 i != m_mods.end(); ++i) {
2361 const ModSpec &mod = *i;
2362 paths.push_back(mod.path + DIR_DELIM + "textures");
2363 paths.push_back(mod.path + DIR_DELIM + "sounds");
2364 paths.push_back(mod.path + DIR_DELIM + "media");
2365 paths.push_back(mod.path + DIR_DELIM + "models");
2367 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2369 // Collect media file information from paths into cache
2370 for(std::vector<std::string>::iterator i = paths.begin();
2371 i != paths.end(); ++i) {
2372 std::string mediapath = *i;
2373 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2374 for (u32 j = 0; j < dirlist.size(); j++) {
2375 if (dirlist[j].dir) // Ignode dirs
2377 std::string filename = dirlist[j].name;
2378 // If name contains illegal characters, ignore the file
2379 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2380 infostream<<"Server: ignoring illegal file name: \""
2381 << filename << "\"" << std::endl;
2384 // If name is not in a supported format, ignore it
2385 const char *supported_ext[] = {
2386 ".png", ".jpg", ".bmp", ".tga",
2387 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2389 ".x", ".b3d", ".md2", ".obj",
2392 if (removeStringEnd(filename, supported_ext) == ""){
2393 infostream << "Server: ignoring unsupported file extension: \""
2394 << filename << "\"" << std::endl;
2397 // Ok, attempt to load the file and add to cache
2398 std::string filepath = mediapath + DIR_DELIM + filename;
2400 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2402 errorstream << "Server::fillMediaCache(): Could not open \""
2403 << filename << "\" for reading" << std::endl;
2406 std::ostringstream tmp_os(std::ios_base::binary);
2410 fis.read(buf, 1024);
2411 std::streamsize len = fis.gcount();
2412 tmp_os.write(buf, len);
2421 errorstream<<"Server::fillMediaCache(): Failed to read \""
2422 << filename << "\"" << std::endl;
2425 if(tmp_os.str().length() == 0) {
2426 errorstream << "Server::fillMediaCache(): Empty file \""
2427 << filepath << "\"" << std::endl;
2432 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2434 unsigned char *digest = sha1.getDigest();
2435 std::string sha1_base64 = base64_encode(digest, 20);
2436 std::string sha1_hex = hex_encode((char*)digest, 20);
2440 m_media[filename] = MediaInfo(filepath, sha1_base64);
2441 verbosestream << "Server: " << sha1_hex << " is " << filename
2447 void Server::sendMediaAnnouncement(u16 peer_id)
2449 DSTACK(FUNCTION_NAME);
2451 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2455 std::ostringstream os(std::ios_base::binary);
2457 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2458 pkt << (u16) m_media.size();
2460 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2461 i != m_media.end(); ++i) {
2462 pkt << i->first << i->second.sha1_digest;
2465 pkt << g_settings->get("remote_media");
2469 struct SendableMedia
2475 SendableMedia(const std::string &name_="", const std::string &path_="",
2476 const std::string &data_=""):
2483 void Server::sendRequestedMedia(u16 peer_id,
2484 const std::vector<std::string> &tosend)
2486 DSTACK(FUNCTION_NAME);
2488 verbosestream<<"Server::sendRequestedMedia(): "
2489 <<"Sending files to client"<<std::endl;
2493 // Put 5kB in one bunch (this is not accurate)
2494 u32 bytes_per_bunch = 5000;
2496 std::vector< std::vector<SendableMedia> > file_bunches;
2497 file_bunches.push_back(std::vector<SendableMedia>());
2499 u32 file_size_bunch_total = 0;
2501 for(std::vector<std::string>::const_iterator i = tosend.begin();
2502 i != tosend.end(); ++i) {
2503 const std::string &name = *i;
2505 if (m_media.find(name) == m_media.end()) {
2506 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2507 <<"unknown file \""<<(name)<<"\""<<std::endl;
2511 //TODO get path + name
2512 std::string tpath = m_media[name].path;
2515 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2516 if(fis.good() == false){
2517 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2518 <<tpath<<"\" for reading"<<std::endl;
2521 std::ostringstream tmp_os(std::ios_base::binary);
2525 fis.read(buf, 1024);
2526 std::streamsize len = fis.gcount();
2527 tmp_os.write(buf, len);
2528 file_size_bunch_total += len;
2537 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2538 <<name<<"\""<<std::endl;
2541 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2542 <<tname<<"\""<<std::endl;*/
2544 file_bunches[file_bunches.size()-1].push_back(
2545 SendableMedia(name, tpath, tmp_os.str()));
2547 // Start next bunch if got enough data
2548 if(file_size_bunch_total >= bytes_per_bunch) {
2549 file_bunches.push_back(std::vector<SendableMedia>());
2550 file_size_bunch_total = 0;
2555 /* Create and send packets */
2557 u16 num_bunches = file_bunches.size();
2558 for(u16 i = 0; i < num_bunches; i++) {
2561 u16 total number of texture bunches
2562 u16 index of this bunch
2563 u32 number of files in this bunch
2572 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2573 pkt << num_bunches << i << (u32) file_bunches[i].size();
2575 for(std::vector<SendableMedia>::iterator
2576 j = file_bunches[i].begin();
2577 j != file_bunches[i].end(); ++j) {
2579 pkt.putLongString(j->data);
2582 verbosestream << "Server::sendRequestedMedia(): bunch "
2583 << i << "/" << num_bunches
2584 << " files=" << file_bunches[i].size()
2585 << " size=" << pkt.getSize() << std::endl;
2590 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2592 if(m_detached_inventories.count(name) == 0) {
2593 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2596 Inventory *inv = m_detached_inventories[name];
2597 std::ostringstream os(std::ios_base::binary);
2599 os << serializeString(name);
2603 std::string s = os.str();
2605 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2606 pkt.putRawString(s.c_str(), s.size());
2608 const std::string &check = m_detached_inventories_player[name];
2609 if (peer_id == PEER_ID_INEXISTENT) {
2611 return m_clients.sendToAll(&pkt);
2612 RemotePlayer *p = m_env->getPlayer(check.c_str());
2614 m_clients.send(p->peer_id, 0, &pkt, true);
2616 if (check == "" || getPlayerName(peer_id) == check)
2621 void Server::sendDetachedInventories(u16 peer_id)
2623 DSTACK(FUNCTION_NAME);
2625 for(std::map<std::string, Inventory*>::iterator
2626 i = m_detached_inventories.begin();
2627 i != m_detached_inventories.end(); ++i) {
2628 const std::string &name = i->first;
2629 //Inventory *inv = i->second;
2630 sendDetachedInventory(name, peer_id);
2638 void Server::DiePlayer(u16 peer_id)
2640 DSTACK(FUNCTION_NAME);
2641 PlayerSAO *playersao = getPlayerSAO(peer_id);
2642 // In some rare cases this can be NULL -- if the player is disconnected
2643 // when a Lua function modifies l_punch, for example
2647 infostream << "Server::DiePlayer(): Player "
2648 << playersao->getPlayer()->getName()
2649 << " dies" << std::endl;
2651 playersao->setHP(0);
2653 // Trigger scripted stuff
2654 m_script->on_dieplayer(playersao);
2656 SendPlayerHP(peer_id);
2657 SendDeathscreen(peer_id, false, v3f(0,0,0));
2660 void Server::RespawnPlayer(u16 peer_id)
2662 DSTACK(FUNCTION_NAME);
2664 PlayerSAO *playersao = getPlayerSAO(peer_id);
2667 infostream << "Server::RespawnPlayer(): Player "
2668 << playersao->getPlayer()->getName()
2669 << " respawns" << std::endl;
2671 playersao->setHP(PLAYER_MAX_HP);
2672 playersao->setBreath(PLAYER_MAX_BREATH);
2674 bool repositioned = m_script->on_respawnplayer(playersao);
2675 if (!repositioned) {
2676 // setPos will send the new position to client
2677 playersao->setPos(findSpawnPos());
2680 SendPlayerHP(peer_id);
2684 void Server::DenySudoAccess(u16 peer_id)
2686 DSTACK(FUNCTION_NAME);
2688 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2693 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2694 const std::string &str_reason, bool reconnect)
2696 if (proto_ver >= 25) {
2697 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2699 std::wstring wreason = utf8_to_wide(
2700 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2701 accessDeniedStrings[(u8)reason]);
2702 SendAccessDenied_Legacy(peer_id, wreason);
2705 m_clients.event(peer_id, CSE_SetDenied);
2706 m_con.DisconnectPeer(peer_id);
2710 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2712 DSTACK(FUNCTION_NAME);
2714 SendAccessDenied(peer_id, reason, custom_reason);
2715 m_clients.event(peer_id, CSE_SetDenied);
2716 m_con.DisconnectPeer(peer_id);
2719 // 13/03/15: remove this function when protocol version 25 will become
2720 // the minimum version for MT users, maybe in 1 year
2721 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2723 DSTACK(FUNCTION_NAME);
2725 SendAccessDenied_Legacy(peer_id, reason);
2726 m_clients.event(peer_id, CSE_SetDenied);
2727 m_con.DisconnectPeer(peer_id);
2730 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2732 DSTACK(FUNCTION_NAME);
2735 RemoteClient* client = getClient(peer_id, CS_Invalid);
2737 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2739 // Right now, the auth mechs don't change between login and sudo mode.
2740 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2741 client->allowed_sudo_mechs = sudo_auth_mechs;
2743 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2744 << g_settings->getFloat("dedicated_server_step")
2748 m_clients.event(peer_id, CSE_AuthAccept);
2750 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2752 // We only support SRP right now
2753 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2755 resp_pkt << sudo_auth_mechs;
2757 m_clients.event(peer_id, CSE_SudoSuccess);
2761 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2763 DSTACK(FUNCTION_NAME);
2764 std::wstring message;
2767 Clear references to playing sounds
2769 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2770 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2771 ServerPlayingSound &psound = i->second;
2772 psound.clients.erase(peer_id);
2773 if (psound.clients.empty())
2774 m_playing_sounds.erase(i++);
2779 RemotePlayer *player = m_env->getPlayer(peer_id);
2781 /* Run scripts and remove from environment */
2782 if (player != NULL) {
2783 PlayerSAO *playersao = player->getPlayerSAO();
2786 // inform connected clients
2787 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2788 // (u16) 1 + std::string represents a vector serialization representation
2789 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2790 m_clients.sendToAll(¬ice);
2792 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2794 playersao->disconnected();
2801 if(player != NULL && reason != CDR_DENY) {
2802 std::ostringstream os(std::ios_base::binary);
2803 std::vector<u16> clients = m_clients.getClientIDs();
2805 for(std::vector<u16>::iterator i = clients.begin();
2806 i != clients.end(); ++i) {
2808 RemotePlayer *player = m_env->getPlayer(*i);
2812 // Get name of player
2813 os << player->getName() << " ";
2816 std::string name = player->getName();
2817 actionstream << name << " "
2818 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2819 << " List of players: " << os.str() << std::endl;
2821 m_admin_chat->outgoing_queue.push_back(
2822 new ChatEventNick(CET_NICK_REMOVE, name));
2826 MutexAutoLock env_lock(m_env_mutex);
2827 m_clients.DeleteClient(peer_id);
2831 // Send leave chat message to all remaining clients
2832 if (!message.empty()) {
2833 SendChatMessage(PEER_ID_INEXISTENT,
2834 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2838 void Server::UpdateCrafting(RemotePlayer *player)
2840 DSTACK(FUNCTION_NAME);
2842 // Get a preview for crafting
2844 InventoryLocation loc;
2845 loc.setPlayer(player->getName());
2846 std::vector<ItemStack> output_replacements;
2847 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2848 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2849 (&player->inventory)->getList("craft"), loc);
2851 // Put the new preview in
2852 InventoryList *plist = player->inventory.getList("craftpreview");
2853 sanity_check(plist);
2854 sanity_check(plist->getSize() >= 1);
2855 plist->changeItem(0, preview);
2858 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2860 if (evt->type == CET_NICK_ADD) {
2861 // The terminal informed us of its nick choice
2862 m_admin_nick = ((ChatEventNick *)evt)->nick;
2863 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2864 errorstream << "You haven't set up an account." << std::endl
2865 << "Please log in using the client as '"
2866 << m_admin_nick << "' with a secure password." << std::endl
2867 << "Until then, you can't execute admin tasks via the console," << std::endl
2868 << "and everybody can claim the user account instead of you," << std::endl
2869 << "giving them full control over this server." << std::endl;
2872 assert(evt->type == CET_CHAT);
2873 handleAdminChat((ChatEventChat *)evt);
2877 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2878 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2880 // If something goes wrong, this player is to blame
2881 RollbackScopeActor rollback_scope(m_rollback,
2882 std::string("player:") + name);
2884 if (g_settings->getBool("strip_color_codes"))
2885 wmessage = unescape_enriched(wmessage);
2888 switch (player->canSendChatMessage()) {
2889 case RPLAYER_CHATRESULT_FLOODING: {
2890 std::wstringstream ws;
2891 ws << L"You cannot send more messages. You are limited to "
2892 << g_settings->getFloat("chat_message_limit_per_10sec")
2893 << L" messages per 10 seconds.";
2896 case RPLAYER_CHATRESULT_KICK:
2897 DenyAccess_Legacy(player->peer_id,
2898 L"You have been kicked due to message flooding.");
2900 case RPLAYER_CHATRESULT_OK:
2903 FATAL_ERROR("Unhandled chat filtering result found.");
2907 if (m_max_chatmessage_length > 0
2908 && wmessage.length() > m_max_chatmessage_length) {
2909 return L"Your message exceed the maximum chat message limit set on the server. "
2910 L"It was refused. Send a shorter message";
2913 // Run script hook, exit if script ate the chat message
2914 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2919 // Whether to send line to the player that sent the message, or to all players
2920 bool broadcast_line = true;
2922 if (check_shout_priv && !checkPriv(name, "shout")) {
2923 line += L"-!- You don't have permission to shout.";
2924 broadcast_line = false;
2933 Tell calling method to send the message to sender
2935 if (!broadcast_line) {
2939 Send the message to others
2941 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2943 std::vector<u16> clients = m_clients.getClientIDs();
2946 Send the message back to the inital sender
2947 if they are using protocol version >= 29
2950 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2951 if (player && player->protocol_version >= 29)
2952 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2954 for (u16 i = 0; i < clients.size(); i++) {
2955 u16 cid = clients[i];
2956 if (cid != peer_id_to_avoid_sending)
2957 SendChatMessage(cid, ChatMessage(line));
2963 void Server::handleAdminChat(const ChatEventChat *evt)
2965 std::string name = evt->nick;
2966 std::wstring wname = utf8_to_wide(name);
2967 std::wstring wmessage = evt->evt_msg;
2969 std::wstring answer = handleChat(name, wname, wmessage);
2971 // If asked to send answer to sender
2972 if (!answer.empty()) {
2973 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2977 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2979 RemoteClient *client = getClientNoEx(peer_id,state_min);
2981 throw ClientNotFoundException("Client not found");
2985 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2987 return m_clients.getClientNoEx(peer_id, state_min);
2990 std::string Server::getPlayerName(u16 peer_id)
2992 RemotePlayer *player = m_env->getPlayer(peer_id);
2994 return "[id="+itos(peer_id)+"]";
2995 return player->getName();
2998 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3000 RemotePlayer *player = m_env->getPlayer(peer_id);
3003 return player->getPlayerSAO();
3006 std::wstring Server::getStatusString()
3008 std::wostringstream os(std::ios_base::binary);
3011 os<<L"version="<<narrow_to_wide(g_version_string);
3013 os<<L", uptime="<<m_uptime.get();
3015 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3016 // Information about clients
3019 std::vector<u16> clients = m_clients.getClientIDs();
3020 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3022 RemotePlayer *player = m_env->getPlayer(*i);
3023 // Get name of player
3024 std::wstring name = L"unknown";
3026 name = narrow_to_wide(player->getName());
3027 // Add name to information string
3035 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3036 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3037 if(g_settings->get("motd") != "")
3038 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3042 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3044 std::set<std::string> privs;
3045 m_script->getAuth(name, NULL, &privs);
3049 bool Server::checkPriv(const std::string &name, const std::string &priv)
3051 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3052 return (privs.count(priv) != 0);
3055 void Server::reportPrivsModified(const std::string &name)
3058 std::vector<u16> clients = m_clients.getClientIDs();
3059 for(std::vector<u16>::iterator i = clients.begin();
3060 i != clients.end(); ++i) {
3061 RemotePlayer *player = m_env->getPlayer(*i);
3062 reportPrivsModified(player->getName());
3065 RemotePlayer *player = m_env->getPlayer(name.c_str());
3068 SendPlayerPrivileges(player->peer_id);
3069 PlayerSAO *sao = player->getPlayerSAO();
3072 sao->updatePrivileges(
3073 getPlayerEffectivePrivs(name),
3078 void Server::reportInventoryFormspecModified(const std::string &name)
3080 RemotePlayer *player = m_env->getPlayer(name.c_str());
3083 SendPlayerInventoryFormspec(player->peer_id);
3086 void Server::setIpBanned(const std::string &ip, const std::string &name)
3088 m_banmanager->add(ip, name);
3091 void Server::unsetIpBanned(const std::string &ip_or_name)
3093 m_banmanager->remove(ip_or_name);
3096 std::string Server::getBanDescription(const std::string &ip_or_name)
3098 return m_banmanager->getBanDescription(ip_or_name);
3101 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3103 // m_env will be NULL if the server is initializing
3107 if (m_admin_nick == name && !m_admin_nick.empty()) {
3108 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3111 RemotePlayer *player = m_env->getPlayer(name);
3116 if (player->peer_id == PEER_ID_INEXISTENT)
3119 SendChatMessage(player->peer_id, ChatMessage(msg));
3122 bool Server::showFormspec(const char *playername, const std::string &formspec,
3123 const std::string &formname)
3125 // m_env will be NULL if the server is initializing
3129 RemotePlayer *player = m_env->getPlayer(playername);
3133 SendShowFormspecMessage(player->peer_id, formspec, formname);
3137 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3142 u32 id = player->addHud(form);
3144 SendHUDAdd(player->peer_id, id, form);
3149 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3153 HudElement* todel = player->removeHud(id);
3160 SendHUDRemove(player->peer_id, id);
3164 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3169 SendHUDChange(player->peer_id, id, stat, data);
3173 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3178 SendHUDSetFlags(player->peer_id, flags, mask);
3179 player->hud_flags &= ~mask;
3180 player->hud_flags |= flags;
3182 PlayerSAO* playersao = player->getPlayerSAO();
3184 if (playersao == NULL)
3187 m_script->player_event(playersao, "hud_changed");
3191 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3196 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3199 player->setHotbarItemcount(hotbar_itemcount);
3200 std::ostringstream os(std::ios::binary);
3201 writeS32(os, hotbar_itemcount);
3202 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3206 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3211 player->setHotbarImage(name);
3212 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3215 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3219 return player->getHotbarImage();
3222 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3227 player->setHotbarSelectedImage(name);
3228 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3231 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3232 v2s32 animation_frames[4], f32 frame_speed)
3237 player->setLocalAnimations(animation_frames, frame_speed);
3238 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3242 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3247 player->eye_offset_first = first;
3248 player->eye_offset_third = third;
3249 SendEyeOffset(player->peer_id, first, third);
3253 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3254 const std::string &type, const std::vector<std::string> ¶ms,
3260 player->setSky(bgcolor, type, params, clouds);
3261 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3265 bool Server::setClouds(RemotePlayer *player, float density,
3266 const video::SColor &color_bright,
3267 const video::SColor &color_ambient,
3275 SendCloudParams(player->peer_id, density,
3276 color_bright, color_ambient, height,
3281 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3287 player->overrideDayNightRatio(do_override, ratio);
3288 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3292 void Server::notifyPlayers(const std::wstring &msg)
3294 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3297 void Server::spawnParticle(const std::string &playername, v3f pos,
3298 v3f velocity, v3f acceleration,
3299 float expirationtime, float size, bool
3300 collisiondetection, bool collision_removal,
3301 bool vertical, const std::string &texture,
3302 const struct TileAnimationParams &animation, u8 glow)
3304 // m_env will be NULL if the server is initializing
3308 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3309 if (playername != "") {
3310 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3313 peer_id = player->peer_id;
3314 proto_ver = player->protocol_version;
3317 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3318 expirationtime, size, collisiondetection,
3319 collision_removal, vertical, texture, animation, glow);
3322 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3323 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3324 float minexptime, float maxexptime, float minsize, float maxsize,
3325 bool collisiondetection, bool collision_removal,
3326 ServerActiveObject *attached, bool vertical, const std::string &texture,
3327 const std::string &playername, const struct TileAnimationParams &animation,
3330 // m_env will be NULL if the server is initializing
3334 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3335 if (playername != "") {
3336 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3339 peer_id = player->peer_id;
3340 proto_ver = player->protocol_version;
3343 u16 attached_id = attached ? attached->getId() : 0;
3346 if (attached_id == 0)
3347 id = m_env->addParticleSpawner(spawntime);
3349 id = m_env->addParticleSpawner(spawntime, attached_id);
3351 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3352 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3353 minexptime, maxexptime, minsize, maxsize,
3354 collisiondetection, collision_removal, attached_id, vertical,
3355 texture, id, animation, glow);
3360 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3362 // m_env will be NULL if the server is initializing
3364 throw ServerError("Can't delete particle spawners during initialisation!");
3366 u16 peer_id = PEER_ID_INEXISTENT;
3367 if (playername != "") {
3368 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3371 peer_id = player->peer_id;
3374 m_env->deleteParticleSpawner(id);
3375 SendDeleteParticleSpawner(peer_id, id);
3378 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3380 if(m_detached_inventories.count(name) > 0){
3381 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3382 delete m_detached_inventories[name];
3384 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3386 Inventory *inv = new Inventory(m_itemdef);
3388 m_detached_inventories[name] = inv;
3389 m_detached_inventories_player[name] = player;
3390 //TODO find a better way to do this
3391 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3395 // actions: time-reversed list
3396 // Return value: success/failure
3397 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3398 std::list<std::string> *log)
3400 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3401 ServerMap *map = (ServerMap*)(&m_env->getMap());
3403 // Fail if no actions to handle
3404 if(actions.empty()){
3405 log->push_back("Nothing to do.");
3412 for(std::list<RollbackAction>::const_iterator
3413 i = actions.begin();
3414 i != actions.end(); ++i)
3416 const RollbackAction &action = *i;
3418 bool success = action.applyRevert(map, this, this);
3421 std::ostringstream os;
3422 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3423 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3425 log->push_back(os.str());
3427 std::ostringstream os;
3428 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3429 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3431 log->push_back(os.str());
3435 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3436 <<" failed"<<std::endl;
3438 // Call it done if less than half failed
3439 return num_failed <= num_tried/2;
3442 // IGameDef interface
3444 IItemDefManager *Server::getItemDefManager()
3449 INodeDefManager *Server::getNodeDefManager()
3454 ICraftDefManager *Server::getCraftDefManager()
3459 u16 Server::allocateUnknownNodeId(const std::string &name)
3461 return m_nodedef->allocateDummy(name);
3464 MtEventManager *Server::getEventManager()
3469 IWritableItemDefManager *Server::getWritableItemDefManager()
3474 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3479 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3484 const ModSpec *Server::getModSpec(const std::string &modname) const
3486 std::vector<ModSpec>::const_iterator it;
3487 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3488 const ModSpec &mod = *it;
3489 if (mod.name == modname)
3495 void Server::getModNames(std::vector<std::string> &modlist)
3497 std::vector<ModSpec>::iterator it;
3498 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3499 modlist.push_back(it->name);
3502 std::string Server::getBuiltinLuaPath()
3504 return porting::path_share + DIR_DELIM + "builtin";
3507 std::string Server::getModStoragePath() const
3509 return m_path_world + DIR_DELIM + "mod_storage";
3512 v3f Server::findSpawnPos()
3514 ServerMap &map = m_env->getServerMap();
3516 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3517 return nodeposf * BS;
3520 bool is_good = false;
3521 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3522 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3524 // Try to find a good place a few times
3525 for(s32 i = 0; i < 4000 && !is_good; i++) {
3526 s32 range = MYMIN(1 + i, range_max);
3527 // We're going to try to throw the player to this position
3528 v2s16 nodepos2d = v2s16(
3529 -range + (myrand() % (range * 2)),
3530 -range + (myrand() % (range * 2)));
3532 // Get spawn level at point
3533 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3534 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3535 // the mapgen to signify an unsuitable spawn position
3536 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3539 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3542 for (s32 i = 0; i < 10; i++) {
3543 v3s16 blockpos = getNodeBlockPos(nodepos);
3544 map.emergeBlock(blockpos, true);
3545 content_t c = map.getNodeNoEx(nodepos).getContent();
3546 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3548 if (air_count >= 2) {
3549 nodeposf = intToFloat(nodepos, BS);
3550 // Don't spawn the player outside map boundaries
3551 if (objectpos_over_limit(nodeposf))
3564 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3566 m_shutdown_timer = delay;
3567 m_shutdown_msg = msg;
3568 m_shutdown_ask_reconnect = reconnect;
3570 if (delay == 0.0f) {
3571 // No delay, shutdown immediately
3572 m_shutdown_requested = true;
3573 // only print to the infostream, a chat message saying
3574 // "Server Shutting Down" is sent when the server destructs.
3575 infostream << "*** Immediate Server shutdown requested." << std::endl;
3576 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3577 // Negative delay, cancel shutdown if requested
3578 m_shutdown_timer = 0.0f;
3579 m_shutdown_msg = "";
3580 m_shutdown_ask_reconnect = false;
3581 m_shutdown_requested = false;
3582 std::wstringstream ws;
3584 ws << L"*** Server shutdown canceled.";
3586 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3587 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3588 } else if (delay > 0.0f) {
3589 // Positive delay, tell the clients when the server will shut down
3590 std::wstringstream ws;
3592 ws << L"*** Server shutting down in "
3593 << duration_to_string(myround(m_shutdown_timer)).c_str()
3596 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3597 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3601 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3604 Try to get an existing player
3606 RemotePlayer *player = m_env->getPlayer(name);
3608 // If player is already connected, cancel
3609 if (player != NULL && player->peer_id != 0) {
3610 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3615 If player with the wanted peer_id already exists, cancel.
3617 if (m_env->getPlayer(peer_id) != NULL) {
3618 infostream<<"emergePlayer(): Player with wrong name but same"
3619 " peer_id already exists"<<std::endl;
3624 player = new RemotePlayer(name, idef());
3627 bool newplayer = false;
3630 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3632 // Complete init with server parts
3633 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3634 player->protocol_version = proto_version;
3638 m_script->on_newplayer(playersao);
3644 bool Server::registerModStorage(ModMetadata *storage)
3646 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3647 errorstream << "Unable to register same mod storage twice. Storage name: "
3648 << storage->getModName() << std::endl;
3652 m_mod_storages[storage->getModName()] = storage;
3656 void Server::unregisterModStorage(const std::string &name)
3658 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3659 if (it != m_mod_storages.end()) {
3660 // Save unconditionaly on unregistration
3661 it->second->save(getModStoragePath());
3662 m_mod_storages.erase(name);
3666 void dedicated_server_loop(Server &server, bool &kill)
3668 DSTACK(FUNCTION_NAME);
3670 verbosestream<<"dedicated_server_loop()"<<std::endl;
3672 IntervalLimiter m_profiler_interval;
3674 static thread_local const float steplen =
3675 g_settings->getFloat("dedicated_server_step");
3676 static thread_local const float profiler_print_interval =
3677 g_settings->getFloat("profiler_print_interval");
3680 // This is kind of a hack but can be done like this
3681 // because server.step() is very light
3683 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3684 sleep_ms((int)(steplen*1000.0));
3686 server.step(steplen);
3688 if (server.getShutdownRequested() || kill)
3694 if (profiler_print_interval != 0) {
3695 if(m_profiler_interval.step(steplen, profiler_print_interval))
3697 infostream<<"Profiler:"<<std::endl;
3698 g_profiler->print(infostream);
3699 g_profiler->clear();
3704 infostream << "Dedicated server quitting" << std::endl;
3706 if (g_settings->getBool("server_announce"))
3707 ServerList::sendAnnounce(ServerList::AA_DELETE,
3708 server.m_bind_addr.getPort());