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"
64 class ClientNotFoundException : public BaseException
67 ClientNotFoundException(const char *s):
72 class ServerThread : public Thread
76 ServerThread(Server *server):
87 void *ServerThread::run()
89 DSTACK(FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
92 m_server->AsyncRunStep(true);
94 while (!stopRequested()) {
96 //TimeTaker timer("AsyncRunStep() + Receive()");
98 m_server->AsyncRunStep();
102 } catch (con::NoIncomingDataException &e) {
103 } catch (con::PeerNotFoundException &e) {
104 infostream<<"Server: PeerNotFoundException"<<std::endl;
105 } catch (ClientNotFoundException &e) {
106 } catch (con::ConnectionBindFailed &e) {
107 m_server->setAsyncFatalError(e.what());
108 } catch (LuaError &e) {
109 m_server->setAsyncFatalError(
110 "ServerThread::run Lua: " + std::string(e.what()));
114 END_DEBUG_EXCEPTION_HANDLER
119 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
121 if(pos_exists) *pos_exists = false;
126 if(pos_exists) *pos_exists = true;
131 ServerActiveObject *sao = env->getActiveObject(object);
134 if(pos_exists) *pos_exists = true;
135 return sao->getBasePosition(); }
147 const std::string &path_world,
148 const SubgameSpec &gamespec,
149 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_dedicated(dedicated),
158 m_async_fatal_error(""),
167 m_enable_rollback_recording(false),
170 m_itemdef(createItemDefManager()),
171 m_nodedef(createNodeDefManager()),
172 m_craftdef(createCraftDefManager()),
173 m_event(new EventManager()),
175 m_time_of_day_send_timer(0),
178 m_shutdown_requested(false),
179 m_shutdown_ask_reconnect(false),
180 m_shutdown_timer(0.0f),
182 m_ignore_map_edit_events(false),
183 m_ignore_map_edit_events_peer_id(0),
185 m_mod_storage_save_timer(10.0f)
187 m_liquid_transform_timer = 0.0;
188 m_liquid_transform_every = 1.0;
189 m_masterserver_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ServerModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if (!modconf.isConsistent()) {
229 modconf.printUnsatisfiedModsError();
233 MutexAutoLock envlock(m_env_mutex);
235 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
236 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
238 // Initialize scripting
239 infostream<<"Server: Initializing Lua"<<std::endl;
241 m_script = new ServerScripting(this);
243 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
246 infostream << "Server: Loading mods: ";
247 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
248 i != m_mods.end(); ++i) {
249 infostream << (*i).name << " ";
251 infostream << std::endl;
252 // Load and run "mod" scripts
253 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
254 it != m_mods.end(); ++it) {
255 const ModSpec &mod = *it;
256 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
257 throw ModError("Error loading mod \"" + mod.name +
258 "\": Mod name does not follow naming conventions: "
259 "Only characters [a-z0-9_] are allowed.");
261 std::string script_path = mod.path + DIR_DELIM + "init.lua";
262 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
263 << script_path << "\"]" << std::endl;
264 m_script->loadMod(script_path, mod.name);
267 // Read Textures and calculate sha1 sums
270 // Apply item aliases in the node definition manager
271 m_nodedef->updateAliases(m_itemdef);
273 // Apply texture overrides from texturepack/override.txt
274 std::string texture_path = g_settings->get("texture_path");
275 if (texture_path != "" && fs::IsDir(texture_path))
276 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
278 m_nodedef->setNodeRegistrationStatus(true);
280 // Perform pending node name resolutions
281 m_nodedef->runNodeResolveCallbacks();
283 // unmap node names for connected nodeboxes
284 m_nodedef->mapNodeboxConnections();
286 // init the recipe hashes to speed up crafting
287 m_craftdef->initHashes(this);
289 // Initialize Environment
290 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
292 m_clients.setEnv(m_env);
294 if (!servermap->settings_mgr.makeMapgenParams())
295 FATAL_ERROR("Couldn't create any mapgen type");
297 // Initialize mapgens
298 m_emerge->initMapgens(servermap->getMapgenParams());
300 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
301 if (m_enable_rollback_recording) {
302 // Create rollback manager
303 m_rollback = new RollbackManager(m_path_world, this);
306 // Give environment reference to scripting api
307 m_script->initializeEnvironment(m_env);
309 // Register us to receive map edit events
310 servermap->addEventReceiver(this);
312 // If file exists, load environment metadata
313 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
314 infostream << "Server: Loading environment metadata" << std::endl;
317 m_env->loadDefaultMeta();
320 m_liquid_transform_every = g_settings->getFloat("liquid_update");
321 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
326 infostream<<"Server destructing"<<std::endl;
328 // Send shutdown message
329 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
332 MutexAutoLock envlock(m_env_mutex);
334 // Execute script shutdown hooks
335 m_script->on_shutdown();
337 infostream << "Server: Saving players" << std::endl;
338 m_env->saveLoadedPlayers();
340 infostream << "Server: Kicking players" << std::endl;
341 std::string kick_msg;
342 bool reconnect = false;
343 if (getShutdownRequested()) {
344 reconnect = m_shutdown_ask_reconnect;
345 kick_msg = m_shutdown_msg;
347 if (kick_msg == "") {
348 kick_msg = g_settings->get("kick_msg_shutdown");
350 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
351 kick_msg, reconnect);
353 infostream << "Server: Saving environment metadata" << std::endl;
361 // stop all emerge threads before deleting players that may have
362 // requested blocks to be emerged
363 m_emerge->stopThreads();
365 // Delete things in the reverse order of creation
375 // Deinitialize scripting
376 infostream<<"Server: Deinitializing scripting"<<std::endl;
379 // Delete detached inventories
380 for (std::map<std::string, Inventory*>::iterator
381 i = m_detached_inventories.begin();
382 i != m_detached_inventories.end(); ++i) {
387 void Server::start(Address bind_addr)
389 DSTACK(FUNCTION_NAME);
391 m_bind_addr = bind_addr;
393 infostream<<"Starting server on "
394 << bind_addr.serializeString() <<"..."<<std::endl;
396 // Stop thread if already running
399 // Initialize connection
400 m_con.SetTimeoutMs(30);
401 m_con.Serve(bind_addr);
406 // ASCII art for the win!
408 <<" .__ __ __ "<<std::endl
409 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
410 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
411 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
412 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
413 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
414 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
415 actionstream<<"Server for gameid=\""<<m_gamespec.id
416 <<"\" listening on "<<bind_addr.serializeString()<<":"
417 <<bind_addr.getPort() << "."<<std::endl;
422 DSTACK(FUNCTION_NAME);
424 infostream<<"Server: Stopping and waiting threads"<<std::endl;
426 // Stop threads (set run=false first so both start stopping)
428 //m_emergethread.setRun(false);
430 //m_emergethread.stop();
432 infostream<<"Server: Threads stopped"<<std::endl;
435 void Server::step(float dtime)
437 DSTACK(FUNCTION_NAME);
442 MutexAutoLock lock(m_step_dtime_mutex);
443 m_step_dtime += dtime;
445 // Throw if fatal error occurred in thread
446 std::string async_err = m_async_fatal_error.get();
447 if (!async_err.empty()) {
448 if (!m_simple_singleplayer_mode) {
449 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
450 g_settings->get("kick_msg_crash"),
451 g_settings->getBool("ask_reconnect_on_crash"));
453 throw ServerError("AsyncErr: " + async_err);
457 void Server::AsyncRunStep(bool initial_step)
459 DSTACK(FUNCTION_NAME);
461 g_profiler->add("Server::AsyncRunStep (num)", 1);
465 MutexAutoLock lock1(m_step_dtime_mutex);
466 dtime = m_step_dtime;
470 // Send blocks to clients
474 if((dtime < 0.001) && (initial_step == false))
477 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
479 //infostream<<"Server steps "<<dtime<<std::endl;
480 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
483 MutexAutoLock lock1(m_step_dtime_mutex);
484 m_step_dtime -= dtime;
491 m_uptime.set(m_uptime.get() + dtime);
497 Update time of day and overall game time
499 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
502 Send to clients at constant intervals
505 m_time_of_day_send_timer -= dtime;
506 if(m_time_of_day_send_timer < 0.0) {
507 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
508 u16 time = m_env->getTimeOfDay();
509 float time_speed = g_settings->getFloat("time_speed");
510 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
514 MutexAutoLock lock(m_env_mutex);
515 // Figure out and report maximum lag to environment
516 float max_lag = m_env->getMaxLagEstimate();
517 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
519 if(dtime > 0.1 && dtime > max_lag * 2.0)
520 infostream<<"Server: Maximum lag peaked to "<<dtime
524 m_env->reportMaxLagEstimate(max_lag);
526 ScopeProfiler sp(g_profiler, "SEnv step");
527 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
531 static const float map_timer_and_unload_dtime = 2.92;
532 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
534 MutexAutoLock lock(m_env_mutex);
535 // Run Map's timers and unload unused data
536 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
537 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
538 g_settings->getFloat("server_unload_unused_data_timeout"),
543 Listen to the admin chat, if available
546 if (!m_admin_chat->command_queue.empty()) {
547 MutexAutoLock lock(m_env_mutex);
548 while (!m_admin_chat->command_queue.empty()) {
549 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
550 handleChatInterfaceEvent(evt);
554 m_admin_chat->outgoing_queue.push_back(
555 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
562 /* Transform liquids */
563 m_liquid_transform_timer += dtime;
564 if(m_liquid_transform_timer >= m_liquid_transform_every)
566 m_liquid_transform_timer -= m_liquid_transform_every;
568 MutexAutoLock lock(m_env_mutex);
570 ScopeProfiler sp(g_profiler, "Server: liquid transform");
572 std::map<v3s16, MapBlock*> modified_blocks;
573 m_env->getMap().transformLiquids(modified_blocks, m_env);
578 core::map<v3s16, MapBlock*> lighting_modified_blocks;
579 ServerMap &map = ((ServerMap&)m_env->getMap());
580 map.updateLighting(modified_blocks, lighting_modified_blocks);
582 // Add blocks modified by lighting to modified_blocks
583 for(core::map<v3s16, MapBlock*>::Iterator
584 i = lighting_modified_blocks.getIterator();
585 i.atEnd() == false; i++)
587 MapBlock *block = i.getNode()->getValue();
588 modified_blocks.insert(block->getPos(), block);
592 Set the modified blocks unsent for all the clients
594 if(!modified_blocks.empty())
596 SetBlocksNotSent(modified_blocks);
599 m_clients.step(dtime);
601 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
603 // send masterserver announce
605 float &counter = m_masterserver_timer;
606 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
607 g_settings->getBool("server_announce")) {
608 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
609 ServerList::AA_START,
610 m_bind_addr.getPort(),
611 m_clients.getPlayerNames(),
613 m_env->getGameTime(),
616 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
626 Check added and deleted active objects
629 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
630 MutexAutoLock envlock(m_env_mutex);
633 RemoteClientMap clients = m_clients.getClientList();
634 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
636 // Radius inside which objects are active
637 static thread_local const s16 radius =
638 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
640 // Radius inside which players are active
641 static thread_local const bool is_transfer_limited =
642 g_settings->exists("unlimited_player_transfer_distance") &&
643 !g_settings->getBool("unlimited_player_transfer_distance");
644 static thread_local const s16 player_transfer_dist =
645 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
646 s16 player_radius = player_transfer_dist;
647 if (player_radius == 0 && is_transfer_limited)
648 player_radius = radius;
650 for (RemoteClientMap::iterator i = clients.begin();
651 i != clients.end(); ++i) {
652 RemoteClient *client = i->second;
654 // If definitions and textures have not been sent, don't
655 // send objects either
656 if (client->getState() < CS_DefinitionsSent)
659 RemotePlayer *player = m_env->getPlayer(client->peer_id);
660 if (player == NULL) {
661 // This can happen if the client timeouts somehow
662 /*warningstream<<FUNCTION_NAME<<": Client "
664 <<" has no associated player"<<std::endl;*/
668 PlayerSAO *playersao = player->getPlayerSAO();
669 if (playersao == NULL)
672 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
673 if (my_radius <= 0) my_radius = radius;
674 //infostream << "Server: Active Radius " << my_radius << std::endl;
676 std::queue<u16> removed_objects;
677 std::queue<u16> added_objects;
678 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
679 client->m_known_objects, removed_objects);
680 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
681 client->m_known_objects, added_objects);
683 // Ignore if nothing happened
684 if (removed_objects.empty() && added_objects.empty()) {
688 std::string data_buffer;
692 // Handle removed objects
693 writeU16((u8*)buf, removed_objects.size());
694 data_buffer.append(buf, 2);
695 while (!removed_objects.empty()) {
697 u16 id = removed_objects.front();
698 ServerActiveObject* obj = m_env->getActiveObject(id);
700 // Add to data buffer for sending
701 writeU16((u8*)buf, id);
702 data_buffer.append(buf, 2);
704 // Remove from known objects
705 client->m_known_objects.erase(id);
707 if(obj && obj->m_known_by_count > 0)
708 obj->m_known_by_count--;
709 removed_objects.pop();
712 // Handle added objects
713 writeU16((u8*)buf, added_objects.size());
714 data_buffer.append(buf, 2);
715 while (!added_objects.empty()) {
717 u16 id = added_objects.front();
718 ServerActiveObject* obj = m_env->getActiveObject(id);
721 u8 type = ACTIVEOBJECT_TYPE_INVALID;
723 warningstream<<FUNCTION_NAME
724 <<": NULL object"<<std::endl;
726 type = obj->getSendType();
728 // Add to data buffer for sending
729 writeU16((u8*)buf, id);
730 data_buffer.append(buf, 2);
731 writeU8((u8*)buf, type);
732 data_buffer.append(buf, 1);
735 data_buffer.append(serializeLongString(
736 obj->getClientInitializationData(client->net_proto_version)));
738 data_buffer.append(serializeLongString(""));
740 // Add to known objects
741 client->m_known_objects.insert(id);
744 obj->m_known_by_count++;
749 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
750 verbosestream << "Server: Sent object remove/add: "
751 << removed_objects.size() << " removed, "
752 << added_objects.size() << " added, "
753 << "packet size is " << pktSize << std::endl;
757 m_mod_storage_save_timer -= dtime;
758 if (m_mod_storage_save_timer <= 0.0f) {
759 infostream << "Saving registered mod storages." << std::endl;
760 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
761 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
762 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
763 if (it->second->isModified()) {
764 it->second->save(getModStoragePath());
774 MutexAutoLock envlock(m_env_mutex);
775 ScopeProfiler sp(g_profiler, "Server: sending object messages");
778 // Value = data sent by object
779 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
781 // Get active object messages from environment
783 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
787 std::vector<ActiveObjectMessage>* message_list = NULL;
788 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
789 n = buffered_messages.find(aom.id);
790 if (n == buffered_messages.end()) {
791 message_list = new std::vector<ActiveObjectMessage>;
792 buffered_messages[aom.id] = message_list;
795 message_list = n->second;
797 message_list->push_back(aom);
801 RemoteClientMap clients = m_clients.getClientList();
802 // Route data to every client
803 for (std::unordered_map<u16, RemoteClient*>::iterator i = clients.begin();
804 i != clients.end(); ++i) {
805 RemoteClient *client = i->second;
806 std::string reliable_data;
807 std::string unreliable_data;
808 // Go through all objects in message buffer
809 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
810 j = buffered_messages.begin();
811 j != buffered_messages.end(); ++j) {
812 // If object is not known by client, skip it
814 if (client->m_known_objects.find(id) == client->m_known_objects.end())
817 // Get message list of object
818 std::vector<ActiveObjectMessage>* list = j->second;
819 // Go through every message
820 for (std::vector<ActiveObjectMessage>::iterator
821 k = list->begin(); k != list->end(); ++k) {
822 // Compose the full new data with header
823 ActiveObjectMessage aom = *k;
824 std::string new_data;
827 writeU16((u8*)&buf[0], aom.id);
828 new_data.append(buf, 2);
830 new_data += serializeString(aom.datastring);
831 // Add data to buffer
833 reliable_data += new_data;
835 unreliable_data += new_data;
839 reliable_data and unreliable_data are now ready.
842 if(reliable_data.size() > 0) {
843 SendActiveObjectMessages(client->peer_id, reliable_data);
846 if(unreliable_data.size() > 0) {
847 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
852 // Clear buffered_messages
853 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
854 i = buffered_messages.begin();
855 i != buffered_messages.end(); ++i) {
861 Send queued-for-sending map edit events.
864 // We will be accessing the environment
865 MutexAutoLock lock(m_env_mutex);
867 // Don't send too many at a time
870 // Single change sending is disabled if queue size is not small
871 bool disable_single_change_sending = false;
872 if(m_unsent_map_edit_queue.size() >= 4)
873 disable_single_change_sending = true;
875 int event_count = m_unsent_map_edit_queue.size();
877 // We'll log the amount of each
880 while(m_unsent_map_edit_queue.size() != 0)
882 MapEditEvent* event = m_unsent_map_edit_queue.front();
883 m_unsent_map_edit_queue.pop();
885 // Players far away from the change are stored here.
886 // Instead of sending the changes, MapBlocks are set not sent
888 std::vector<u16> far_players;
890 switch (event->type) {
893 prof.add("MEET_ADDNODE", 1);
894 sendAddNode(event->p, event->n, event->already_known_by_peer,
895 &far_players, disable_single_change_sending ? 5 : 30,
896 event->type == MEET_ADDNODE);
898 case MEET_REMOVENODE:
899 prof.add("MEET_REMOVENODE", 1);
900 sendRemoveNode(event->p, event->already_known_by_peer,
901 &far_players, disable_single_change_sending ? 5 : 30);
903 case MEET_BLOCK_NODE_METADATA_CHANGED:
904 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
905 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
906 setBlockNotSent(event->p);
909 infostream << "Server: MEET_OTHER" << std::endl;
910 prof.add("MEET_OTHER", 1);
911 for(std::set<v3s16>::iterator
912 i = event->modified_blocks.begin();
913 i != event->modified_blocks.end(); ++i) {
918 prof.add("unknown", 1);
919 warningstream << "Server: Unknown MapEditEvent "
920 << ((u32)event->type) << std::endl;
925 Set blocks not sent to far players
927 if(!far_players.empty()) {
928 // Convert list format to that wanted by SetBlocksNotSent
929 std::map<v3s16, MapBlock*> modified_blocks2;
930 for(std::set<v3s16>::iterator
931 i = event->modified_blocks.begin();
932 i != event->modified_blocks.end(); ++i) {
933 modified_blocks2[*i] =
934 m_env->getMap().getBlockNoCreateNoEx(*i);
937 // Set blocks not sent
938 for(std::vector<u16>::iterator
939 i = far_players.begin();
940 i != far_players.end(); ++i) {
941 if(RemoteClient *client = getClient(*i))
942 client->SetBlocksNotSent(modified_blocks2);
948 /*// Don't send too many at a time
950 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
954 if(event_count >= 5){
955 infostream<<"Server: MapEditEvents:"<<std::endl;
956 prof.print(infostream);
957 } else if(event_count != 0){
958 verbosestream<<"Server: MapEditEvents:"<<std::endl;
959 prof.print(verbosestream);
965 Trigger emergethread (it somehow gets to a non-triggered but
966 bysy state sometimes)
969 float &counter = m_emergethread_trigger_timer;
971 if (counter >= 2.0) {
974 m_emerge->startThreads();
978 // Save map, players and auth stuff
980 float &counter = m_savemap_timer;
982 static thread_local const float save_interval =
983 g_settings->getFloat("server_map_save_interval");
984 if (counter >= save_interval) {
986 MutexAutoLock lock(m_env_mutex);
988 ScopeProfiler sp(g_profiler, "Server: saving stuff");
991 if (m_banmanager->isModified()) {
992 m_banmanager->save();
995 // Save changed parts of map
996 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
999 m_env->saveLoadedPlayers();
1001 // Save environment metadata
1007 static const float shutdown_msg_times[] =
1009 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
1012 if (m_shutdown_timer > 0.0f) {
1013 // Automated messages
1014 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
1015 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
1016 // If shutdown timer matches an automessage, shot it
1017 if (m_shutdown_timer > shutdown_msg_times[i] &&
1018 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1019 std::wstringstream ws;
1021 ws << L"*** Server shutting down in "
1022 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1025 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1026 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1032 m_shutdown_timer -= dtime;
1033 if (m_shutdown_timer < 0.0f) {
1034 m_shutdown_timer = 0.0f;
1035 m_shutdown_requested = true;
1040 void Server::Receive()
1042 DSTACK(FUNCTION_NAME);
1043 SharedBuffer<u8> data;
1047 m_con.Receive(&pkt);
1048 peer_id = pkt.getPeerId();
1051 catch(con::InvalidIncomingDataException &e) {
1052 infostream<<"Server::Receive(): "
1053 "InvalidIncomingDataException: what()="
1054 <<e.what()<<std::endl;
1056 catch(SerializationError &e) {
1057 infostream<<"Server::Receive(): "
1058 "SerializationError: what()="
1059 <<e.what()<<std::endl;
1061 catch(ClientStateError &e) {
1062 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1063 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1064 L"Try reconnecting or updating your client");
1066 catch(con::PeerNotFoundException &e) {
1071 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1073 std::string playername = "";
1074 PlayerSAO *playersao = NULL;
1077 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1078 if (client != NULL) {
1079 playername = client->getName();
1080 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1082 } catch (std::exception &e) {
1088 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1090 // If failed, cancel
1091 if ((playersao == NULL) || (player == NULL)) {
1092 if (player && player->peer_id != 0) {
1093 actionstream << "Server: Failed to emerge player \"" << playername
1094 << "\" (player allocated to an another client)" << std::endl;
1095 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1096 L"name. If your client closed unexpectedly, try again in "
1099 errorstream << "Server: " << playername << ": Failed to emerge player"
1101 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1107 Send complete position information
1109 SendMovePlayer(peer_id);
1112 SendPlayerPrivileges(peer_id);
1114 // Send inventory formspec
1115 SendPlayerInventoryFormspec(peer_id);
1118 SendInventory(playersao);
1120 // Send HP or death screen
1121 if (playersao->isDead())
1122 SendDeathscreen(peer_id, false, v3f(0,0,0));
1124 SendPlayerHPOrDie(playersao);
1127 SendPlayerBreath(playersao);
1129 // Note things in chat if not in simple singleplayer mode
1130 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1131 // Send information about server to player in chat
1132 SendChatMessage(peer_id, getStatusString());
1134 Address addr = getPeerAddress(player->peer_id);
1135 std::string ip_str = addr.serializeString();
1136 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1141 const std::vector<std::string> &names = m_clients.getPlayerNames();
1143 actionstream << player->getName() << " joins game. List of players: ";
1145 for (std::vector<std::string>::const_iterator i = names.begin();
1146 i != names.end(); ++i) {
1147 actionstream << *i << " ";
1150 actionstream << player->getName() <<std::endl;
1155 inline void Server::handleCommand(NetworkPacket* pkt)
1157 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1158 (this->*opHandle.handler)(pkt);
1161 void Server::ProcessData(NetworkPacket *pkt)
1163 DSTACK(FUNCTION_NAME);
1164 // Environment is locked first.
1165 MutexAutoLock envlock(m_env_mutex);
1167 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1168 u32 peer_id = pkt->getPeerId();
1171 Address address = getPeerAddress(peer_id);
1172 std::string addr_s = address.serializeString();
1174 if(m_banmanager->isIpBanned(addr_s)) {
1175 std::string ban_name = m_banmanager->getBanName(addr_s);
1176 infostream << "Server: A banned client tried to connect from "
1177 << addr_s << "; banned name was "
1178 << ban_name << std::endl;
1179 // This actually doesn't seem to transfer to the client
1180 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1181 + utf8_to_wide(ban_name));
1185 catch(con::PeerNotFoundException &e) {
1187 * no peer for this packet found
1188 * most common reason is peer timeout, e.g. peer didn't
1189 * respond for some time, your server was overloaded or
1192 infostream << "Server::ProcessData(): Canceling: peer "
1193 << peer_id << " not found" << std::endl;
1198 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1200 // Command must be handled into ToServerCommandHandler
1201 if (command >= TOSERVER_NUM_MSG_TYPES) {
1202 infostream << "Server: Ignoring unknown command "
1203 << command << std::endl;
1207 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1212 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1214 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1215 errorstream << "Server::ProcessData(): Cancelling: Peer"
1216 " serialization format invalid or not initialized."
1217 " Skipping incoming command=" << command << std::endl;
1221 /* Handle commands related to client startup */
1222 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1227 if (m_clients.getClientState(peer_id) < CS_Active) {
1228 if (command == TOSERVER_PLAYERPOS) return;
1230 errorstream << "Got packet command: " << command << " for peer id "
1231 << peer_id << " but client isn't active yet. Dropping packet "
1237 } catch (SendFailedException &e) {
1238 errorstream << "Server::ProcessData(): SendFailedException: "
1239 << "what=" << e.what()
1241 } catch (PacketError &e) {
1242 actionstream << "Server::ProcessData(): PacketError: "
1243 << "what=" << e.what()
1248 void Server::setTimeOfDay(u32 time)
1250 m_env->setTimeOfDay(time);
1251 m_time_of_day_send_timer = 0;
1254 void Server::onMapEditEvent(MapEditEvent *event)
1256 if(m_ignore_map_edit_events)
1258 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1260 MapEditEvent *e = event->clone();
1261 m_unsent_map_edit_queue.push(e);
1264 Inventory* Server::getInventory(const InventoryLocation &loc)
1267 case InventoryLocation::UNDEFINED:
1268 case InventoryLocation::CURRENT_PLAYER:
1270 case InventoryLocation::PLAYER:
1272 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1275 PlayerSAO *playersao = player->getPlayerSAO();
1278 return playersao->getInventory();
1281 case InventoryLocation::NODEMETA:
1283 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1286 return meta->getInventory();
1289 case InventoryLocation::DETACHED:
1291 if(m_detached_inventories.count(loc.name) == 0)
1293 return m_detached_inventories[loc.name];
1297 sanity_check(false); // abort
1302 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1305 case InventoryLocation::UNDEFINED:
1307 case InventoryLocation::PLAYER:
1312 RemotePlayer *player =
1313 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1318 PlayerSAO *playersao = player->getPlayerSAO();
1322 SendInventory(playersao);
1325 case InventoryLocation::NODEMETA:
1327 v3s16 blockpos = getNodeBlockPos(loc.p);
1329 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1331 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1333 setBlockNotSent(blockpos);
1336 case InventoryLocation::DETACHED:
1338 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1342 sanity_check(false); // abort
1347 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1349 std::vector<u16> clients = m_clients.getClientIDs();
1351 // Set the modified blocks unsent for all the clients
1352 for (std::vector<u16>::iterator i = clients.begin();
1353 i != clients.end(); ++i) {
1354 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1355 client->SetBlocksNotSent(block);
1360 void Server::peerAdded(con::Peer *peer)
1362 DSTACK(FUNCTION_NAME);
1363 verbosestream<<"Server::peerAdded(): peer->id="
1364 <<peer->id<<std::endl;
1367 c.type = con::PEER_ADDED;
1368 c.peer_id = peer->id;
1370 m_peer_change_queue.push(c);
1373 void Server::deletingPeer(con::Peer *peer, bool timeout)
1375 DSTACK(FUNCTION_NAME);
1376 verbosestream<<"Server::deletingPeer(): peer->id="
1377 <<peer->id<<", timeout="<<timeout<<std::endl;
1379 m_clients.event(peer->id, CSE_Disconnect);
1381 c.type = con::PEER_REMOVED;
1382 c.peer_id = peer->id;
1383 c.timeout = timeout;
1384 m_peer_change_queue.push(c);
1387 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1389 *retval = m_con.getPeerStat(peer_id,type);
1390 if (*retval == -1) return false;
1394 bool Server::getClientInfo(
1403 std::string* vers_string
1406 *state = m_clients.getClientState(peer_id);
1408 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1410 if (client == NULL) {
1415 *uptime = client->uptime();
1416 *ser_vers = client->serialization_version;
1417 *prot_vers = client->net_proto_version;
1419 *major = client->getMajor();
1420 *minor = client->getMinor();
1421 *patch = client->getPatch();
1422 *vers_string = client->getPatch();
1429 void Server::handlePeerChanges()
1431 while(m_peer_change_queue.size() > 0)
1433 con::PeerChange c = m_peer_change_queue.front();
1434 m_peer_change_queue.pop();
1436 verbosestream<<"Server: Handling peer change: "
1437 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1442 case con::PEER_ADDED:
1443 m_clients.CreateClient(c.peer_id);
1446 case con::PEER_REMOVED:
1447 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1451 FATAL_ERROR("Invalid peer change event received!");
1457 void Server::printToConsoleOnly(const std::string &text)
1460 m_admin_chat->outgoing_queue.push_back(
1461 new ChatEventChat("", utf8_to_wide(text)));
1463 std::cout << text << std::endl;
1467 void Server::Send(NetworkPacket* pkt)
1469 m_clients.send(pkt->getPeerId(),
1470 clientCommandFactoryTable[pkt->getCommand()].channel,
1472 clientCommandFactoryTable[pkt->getCommand()].reliable);
1475 void Server::SendMovement(u16 peer_id)
1477 DSTACK(FUNCTION_NAME);
1478 std::ostringstream os(std::ios_base::binary);
1480 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1482 pkt << g_settings->getFloat("movement_acceleration_default");
1483 pkt << g_settings->getFloat("movement_acceleration_air");
1484 pkt << g_settings->getFloat("movement_acceleration_fast");
1485 pkt << g_settings->getFloat("movement_speed_walk");
1486 pkt << g_settings->getFloat("movement_speed_crouch");
1487 pkt << g_settings->getFloat("movement_speed_fast");
1488 pkt << g_settings->getFloat("movement_speed_climb");
1489 pkt << g_settings->getFloat("movement_speed_jump");
1490 pkt << g_settings->getFloat("movement_liquid_fluidity");
1491 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1492 pkt << g_settings->getFloat("movement_liquid_sink");
1493 pkt << g_settings->getFloat("movement_gravity");
1498 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1500 if (!g_settings->getBool("enable_damage"))
1503 u16 peer_id = playersao->getPeerID();
1504 bool is_alive = playersao->getHP() > 0;
1507 SendPlayerHP(peer_id);
1512 void Server::SendHP(u16 peer_id, u8 hp)
1514 DSTACK(FUNCTION_NAME);
1516 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1521 void Server::SendBreath(u16 peer_id, u16 breath)
1523 DSTACK(FUNCTION_NAME);
1525 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1526 pkt << (u16) breath;
1530 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1531 const std::string &custom_reason, bool reconnect)
1533 assert(reason < SERVER_ACCESSDENIED_MAX);
1535 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1537 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1538 pkt << custom_reason;
1539 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1540 reason == SERVER_ACCESSDENIED_CRASH)
1541 pkt << custom_reason << (u8)reconnect;
1545 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1547 DSTACK(FUNCTION_NAME);
1549 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1554 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1555 v3f camera_point_target)
1557 DSTACK(FUNCTION_NAME);
1559 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1560 pkt << set_camera_point_target << camera_point_target;
1564 void Server::SendItemDef(u16 peer_id,
1565 IItemDefManager *itemdef, u16 protocol_version)
1567 DSTACK(FUNCTION_NAME);
1569 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1573 u32 length of the next item
1574 zlib-compressed serialized ItemDefManager
1576 std::ostringstream tmp_os(std::ios::binary);
1577 itemdef->serialize(tmp_os, protocol_version);
1578 std::ostringstream tmp_os2(std::ios::binary);
1579 compressZlib(tmp_os.str(), tmp_os2);
1580 pkt.putLongString(tmp_os2.str());
1583 verbosestream << "Server: Sending item definitions to id(" << peer_id
1584 << "): size=" << pkt.getSize() << std::endl;
1589 void Server::SendNodeDef(u16 peer_id,
1590 INodeDefManager *nodedef, u16 protocol_version)
1592 DSTACK(FUNCTION_NAME);
1594 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1598 u32 length of the next item
1599 zlib-compressed serialized NodeDefManager
1601 std::ostringstream tmp_os(std::ios::binary);
1602 nodedef->serialize(tmp_os, protocol_version);
1603 std::ostringstream tmp_os2(std::ios::binary);
1604 compressZlib(tmp_os.str(), tmp_os2);
1606 pkt.putLongString(tmp_os2.str());
1609 verbosestream << "Server: Sending node definitions to id(" << peer_id
1610 << "): size=" << pkt.getSize() << std::endl;
1616 Non-static send methods
1619 void Server::SendInventory(PlayerSAO* playerSAO)
1621 DSTACK(FUNCTION_NAME);
1623 UpdateCrafting(playerSAO->getPlayer());
1629 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1631 std::ostringstream os;
1632 playerSAO->getInventory()->serialize(os);
1634 std::string s = os.str();
1636 pkt.putRawString(s.c_str(), s.size());
1640 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1642 DSTACK(FUNCTION_NAME);
1643 if (peer_id != PEER_ID_INEXISTENT) {
1644 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1646 if (m_clients.getProtocolVersion(peer_id) < 27)
1647 pkt << unescape_enriched(message);
1653 for (u16 id : m_clients.getClientIDs())
1654 SendChatMessage(id, message);
1658 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1659 const std::string &formname)
1661 DSTACK(FUNCTION_NAME);
1663 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1664 if (formspec == "" ){
1665 //the client should close the formspec
1666 pkt.putLongString("");
1668 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1675 // Spawns a particle on peer with peer_id
1676 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1677 v3f pos, v3f velocity, v3f acceleration,
1678 float expirationtime, float size, bool collisiondetection,
1679 bool collision_removal,
1680 bool vertical, const std::string &texture,
1681 const struct TileAnimationParams &animation, u8 glow)
1683 DSTACK(FUNCTION_NAME);
1684 static thread_local const float radius =
1685 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1687 if (peer_id == PEER_ID_INEXISTENT) {
1688 std::vector<u16> clients = m_clients.getClientIDs();
1690 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1691 RemotePlayer *player = m_env->getPlayer(*i);
1695 PlayerSAO *sao = player->getPlayerSAO();
1699 // Do not send to distant clients
1700 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1703 SendSpawnParticle(*i, player->protocol_version,
1704 pos, velocity, acceleration,
1705 expirationtime, size, collisiondetection,
1706 collision_removal, vertical, texture, animation, glow);
1711 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1713 pkt << pos << velocity << acceleration << expirationtime
1714 << size << collisiondetection;
1715 pkt.putLongString(texture);
1717 pkt << collision_removal;
1718 // This is horrible but required (why are there two ways to serialize pkts?)
1719 std::ostringstream os(std::ios_base::binary);
1720 animation.serialize(os, protocol_version);
1721 pkt.putRawString(os.str());
1727 // Adds a ParticleSpawner on peer with peer_id
1728 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1729 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1730 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1731 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1732 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1733 const struct TileAnimationParams &animation, u8 glow)
1735 DSTACK(FUNCTION_NAME);
1736 if (peer_id == PEER_ID_INEXISTENT) {
1737 // This sucks and should be replaced:
1738 std::vector<u16> clients = m_clients.getClientIDs();
1739 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1740 RemotePlayer *player = m_env->getPlayer(*i);
1743 SendAddParticleSpawner(*i, player->protocol_version,
1744 amount, spawntime, minpos, maxpos,
1745 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1746 minsize, maxsize, collisiondetection, collision_removal,
1747 attached_id, vertical, texture, id, animation, glow);
1752 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1754 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1755 << minacc << maxacc << minexptime << maxexptime << minsize
1756 << maxsize << collisiondetection;
1758 pkt.putLongString(texture);
1760 pkt << id << vertical;
1761 pkt << collision_removal;
1763 // This is horrible but required
1764 std::ostringstream os(std::ios_base::binary);
1765 animation.serialize(os, protocol_version);
1766 pkt.putRawString(os.str());
1772 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1774 DSTACK(FUNCTION_NAME);
1776 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1778 // Ugly error in this packet
1781 if (peer_id != PEER_ID_INEXISTENT) {
1785 m_clients.sendToAll(&pkt);
1790 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1792 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1794 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1795 << form->text << form->number << form->item << form->dir
1796 << form->align << form->offset << form->world_pos << form->size;
1801 void Server::SendHUDRemove(u16 peer_id, u32 id)
1803 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1808 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1810 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1811 pkt << id << (u8) stat;
1815 case HUD_STAT_SCALE:
1816 case HUD_STAT_ALIGN:
1817 case HUD_STAT_OFFSET:
1818 pkt << *(v2f *) value;
1822 pkt << *(std::string *) value;
1824 case HUD_STAT_WORLD_POS:
1825 pkt << *(v3f *) value;
1828 pkt << *(v2s32 *) value;
1830 case HUD_STAT_NUMBER:
1834 pkt << *(u32 *) value;
1841 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1843 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1845 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1847 pkt << flags << mask;
1852 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1854 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1855 pkt << param << value;
1859 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1860 const std::string &type, const std::vector<std::string> ¶ms,
1863 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1864 pkt << bgcolor << type << (u16) params.size();
1866 for(size_t i=0; i<params.size(); i++)
1874 void Server::SendCloudParams(u16 peer_id, float density,
1875 const video::SColor &color_bright,
1876 const video::SColor &color_ambient,
1881 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1882 pkt << density << color_bright << color_ambient
1883 << height << thickness << speed;
1888 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1891 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1894 pkt << do_override << (u16) (ratio * 65535);
1899 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1901 DSTACK(FUNCTION_NAME);
1903 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1904 pkt << time << time_speed;
1906 if (peer_id == PEER_ID_INEXISTENT) {
1907 m_clients.sendToAll(&pkt);
1914 void Server::SendPlayerHP(u16 peer_id)
1916 DSTACK(FUNCTION_NAME);
1917 PlayerSAO *playersao = getPlayerSAO(peer_id);
1918 // In some rare case if the player is disconnected
1919 // while Lua call l_punch, for example, this can be NULL
1923 SendHP(peer_id, playersao->getHP());
1924 m_script->player_event(playersao,"health_changed");
1926 // Send to other clients
1927 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1928 ActiveObjectMessage aom(playersao->getId(), true, str);
1929 playersao->m_messages_out.push(aom);
1932 void Server::SendPlayerBreath(PlayerSAO *sao)
1934 DSTACK(FUNCTION_NAME);
1937 m_script->player_event(sao, "breath_changed");
1938 SendBreath(sao->getPeerID(), sao->getBreath());
1941 void Server::SendMovePlayer(u16 peer_id)
1943 DSTACK(FUNCTION_NAME);
1944 RemotePlayer *player = m_env->getPlayer(peer_id);
1946 PlayerSAO *sao = player->getPlayerSAO();
1949 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1950 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1953 v3f pos = sao->getBasePosition();
1954 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1955 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1956 << " pitch=" << sao->getPitch()
1957 << " yaw=" << sao->getYaw()
1964 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1966 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1969 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1970 << animation_frames[3] << animation_speed;
1975 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1977 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1978 pkt << first << third;
1981 void Server::SendPlayerPrivileges(u16 peer_id)
1983 RemotePlayer *player = m_env->getPlayer(peer_id);
1985 if(player->peer_id == PEER_ID_INEXISTENT)
1988 std::set<std::string> privs;
1989 m_script->getAuth(player->getName(), NULL, &privs);
1991 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1992 pkt << (u16) privs.size();
1994 for(std::set<std::string>::const_iterator i = privs.begin();
1995 i != privs.end(); ++i) {
2002 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2004 RemotePlayer *player = m_env->getPlayer(peer_id);
2006 if(player->peer_id == PEER_ID_INEXISTENT)
2009 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2010 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2014 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2016 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2017 pkt.putRawString(datas.c_str(), datas.size());
2019 return pkt.getSize();
2022 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2024 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2025 datas.size(), peer_id);
2027 pkt.putRawString(datas.c_str(), datas.size());
2029 m_clients.send(pkt.getPeerId(),
2030 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2035 s32 Server::playSound(const SimpleSoundSpec &spec,
2036 const ServerSoundParams ¶ms)
2038 // Find out initial position of sound
2039 bool pos_exists = false;
2040 v3f pos = params.getPos(m_env, &pos_exists);
2041 // If position is not found while it should be, cancel sound
2042 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2045 // Filter destination clients
2046 std::vector<u16> dst_clients;
2047 if(params.to_player != "")
2049 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2051 infostream<<"Server::playSound: Player \""<<params.to_player
2052 <<"\" not found"<<std::endl;
2055 if(player->peer_id == PEER_ID_INEXISTENT){
2056 infostream<<"Server::playSound: Player \""<<params.to_player
2057 <<"\" not connected"<<std::endl;
2060 dst_clients.push_back(player->peer_id);
2063 std::vector<u16> clients = m_clients.getClientIDs();
2065 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2066 RemotePlayer *player = m_env->getPlayer(*i);
2070 PlayerSAO *sao = player->getPlayerSAO();
2075 if(sao->getBasePosition().getDistanceFrom(pos) >
2076 params.max_hear_distance)
2079 dst_clients.push_back(*i);
2083 if(dst_clients.empty())
2087 s32 id = m_next_sound_id++;
2088 // The sound will exist as a reference in m_playing_sounds
2089 m_playing_sounds[id] = ServerPlayingSound();
2090 ServerPlayingSound &psound = m_playing_sounds[id];
2091 psound.params = params;
2094 float gain = params.gain * spec.gain;
2095 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2096 pkt << id << spec.name << gain
2097 << (u8) params.type << pos << params.object
2098 << params.loop << params.fade << params.pitch;
2100 // Backwards compability
2101 bool play_sound = gain > 0;
2103 for (std::vector<u16>::iterator i = dst_clients.begin();
2104 i != dst_clients.end(); ++i) {
2105 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2106 psound.clients.insert(*i);
2107 m_clients.send(*i, 0, &pkt, true);
2112 void Server::stopSound(s32 handle)
2114 // Get sound reference
2115 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2116 m_playing_sounds.find(handle);
2117 if (i == m_playing_sounds.end())
2119 ServerPlayingSound &psound = i->second;
2121 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2124 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2125 si != psound.clients.end(); ++si) {
2127 m_clients.send(*si, 0, &pkt, true);
2129 // Remove sound reference
2130 m_playing_sounds.erase(i);
2133 void Server::fadeSound(s32 handle, float step, float gain)
2135 // Get sound reference
2136 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2137 m_playing_sounds.find(handle);
2138 if (i == m_playing_sounds.end())
2141 ServerPlayingSound &psound = i->second;
2142 psound.params.gain = gain;
2144 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2145 pkt << handle << step << gain;
2147 // Backwards compability
2148 bool play_sound = gain > 0;
2149 ServerPlayingSound compat_psound = psound;
2150 compat_psound.clients.clear();
2152 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2153 compat_pkt << handle;
2155 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2156 it != psound.clients.end();) {
2157 if (m_clients.getProtocolVersion(*it) >= 32) {
2159 m_clients.send(*it, 0, &pkt, true);
2162 compat_psound.clients.insert(*it);
2164 m_clients.send(*it, 0, &compat_pkt, true);
2165 psound.clients.erase(it++);
2169 // Remove sound reference
2170 if (!play_sound || psound.clients.size() == 0)
2171 m_playing_sounds.erase(i);
2173 if (play_sound && compat_psound.clients.size() > 0) {
2174 // Play new sound volume on older clients
2175 playSound(compat_psound.spec, compat_psound.params);
2179 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2180 std::vector<u16> *far_players, float far_d_nodes)
2182 float maxd = far_d_nodes*BS;
2183 v3f p_f = intToFloat(p, BS);
2185 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2188 std::vector<u16> clients = m_clients.getClientIDs();
2189 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2192 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2193 PlayerSAO *sao = player->getPlayerSAO();
2197 // If player is far away, only set modified blocks not sent
2198 v3f player_pos = sao->getBasePosition();
2199 if (player_pos.getDistanceFrom(p_f) > maxd) {
2200 far_players->push_back(*i);
2207 m_clients.send(*i, 0, &pkt, true);
2211 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2212 std::vector<u16> *far_players, float far_d_nodes,
2213 bool remove_metadata)
2215 float maxd = far_d_nodes*BS;
2216 v3f p_f = intToFloat(p, BS);
2218 std::vector<u16> clients = m_clients.getClientIDs();
2219 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2222 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2223 PlayerSAO *sao = player->getPlayerSAO();
2227 // If player is far away, only set modified blocks not sent
2228 v3f player_pos = sao->getBasePosition();
2229 if(player_pos.getDistanceFrom(p_f) > maxd) {
2230 far_players->push_back(*i);
2236 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2238 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2240 pkt << p << n.param0 << n.param1 << n.param2
2241 << (u8) (remove_metadata ? 0 : 1);
2246 if (pkt.getSize() > 0)
2247 m_clients.send(*i, 0, &pkt, true);
2251 void Server::setBlockNotSent(v3s16 p)
2253 std::vector<u16> clients = m_clients.getClientIDs();
2255 for(std::vector<u16>::iterator i = clients.begin();
2256 i != clients.end(); ++i) {
2257 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2258 client->SetBlockNotSent(p);
2263 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2265 DSTACK(FUNCTION_NAME);
2267 v3s16 p = block->getPos();
2270 Create a packet with the block in the right format
2273 std::ostringstream os(std::ios_base::binary);
2274 block->serialize(os, ver, false);
2275 block->serializeNetworkSpecific(os);
2276 std::string s = os.str();
2278 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2281 pkt.putRawString(s.c_str(), s.size());
2285 void Server::SendBlocks(float dtime)
2287 DSTACK(FUNCTION_NAME);
2289 MutexAutoLock envlock(m_env_mutex);
2290 //TODO check if one big lock could be faster then multiple small ones
2292 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2294 std::vector<PrioritySortedBlockTransfer> queue;
2296 s32 total_sending = 0;
2299 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2301 std::vector<u16> clients = m_clients.getClientIDs();
2304 for(std::vector<u16>::iterator i = clients.begin();
2305 i != clients.end(); ++i) {
2306 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2311 total_sending += client->SendingCount();
2312 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2318 // Lowest priority number comes first.
2319 // Lowest is most important.
2320 std::sort(queue.begin(), queue.end());
2323 for(u32 i=0; i<queue.size(); i++)
2325 //TODO: Calculate limit dynamically
2326 if(total_sending >= g_settings->getS32
2327 ("max_simultaneous_block_sends_server_total"))
2330 PrioritySortedBlockTransfer q = queue[i];
2332 MapBlock *block = NULL;
2335 block = m_env->getMap().getBlockNoCreate(q.pos);
2337 catch(InvalidPositionException &e)
2342 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2347 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2349 client->SentBlock(q.pos);
2355 void Server::fillMediaCache()
2357 DSTACK(FUNCTION_NAME);
2359 infostream<<"Server: Calculating media file checksums"<<std::endl;
2361 // Collect all media file paths
2362 std::vector<std::string> paths;
2363 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2364 i != m_mods.end(); ++i) {
2365 const ModSpec &mod = *i;
2366 paths.push_back(mod.path + DIR_DELIM + "textures");
2367 paths.push_back(mod.path + DIR_DELIM + "sounds");
2368 paths.push_back(mod.path + DIR_DELIM + "media");
2369 paths.push_back(mod.path + DIR_DELIM + "models");
2371 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2373 // Collect media file information from paths into cache
2374 for(std::vector<std::string>::iterator i = paths.begin();
2375 i != paths.end(); ++i) {
2376 std::string mediapath = *i;
2377 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2378 for (u32 j = 0; j < dirlist.size(); j++) {
2379 if (dirlist[j].dir) // Ignode dirs
2381 std::string filename = dirlist[j].name;
2382 // If name contains illegal characters, ignore the file
2383 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2384 infostream<<"Server: ignoring illegal file name: \""
2385 << filename << "\"" << std::endl;
2388 // If name is not in a supported format, ignore it
2389 const char *supported_ext[] = {
2390 ".png", ".jpg", ".bmp", ".tga",
2391 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2393 ".x", ".b3d", ".md2", ".obj",
2396 if (removeStringEnd(filename, supported_ext) == ""){
2397 infostream << "Server: ignoring unsupported file extension: \""
2398 << filename << "\"" << std::endl;
2401 // Ok, attempt to load the file and add to cache
2402 std::string filepath = mediapath + DIR_DELIM + filename;
2404 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2406 errorstream << "Server::fillMediaCache(): Could not open \""
2407 << filename << "\" for reading" << std::endl;
2410 std::ostringstream tmp_os(std::ios_base::binary);
2414 fis.read(buf, 1024);
2415 std::streamsize len = fis.gcount();
2416 tmp_os.write(buf, len);
2425 errorstream<<"Server::fillMediaCache(): Failed to read \""
2426 << filename << "\"" << std::endl;
2429 if(tmp_os.str().length() == 0) {
2430 errorstream << "Server::fillMediaCache(): Empty file \""
2431 << filepath << "\"" << std::endl;
2436 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2438 unsigned char *digest = sha1.getDigest();
2439 std::string sha1_base64 = base64_encode(digest, 20);
2440 std::string sha1_hex = hex_encode((char*)digest, 20);
2444 m_media[filename] = MediaInfo(filepath, sha1_base64);
2445 verbosestream << "Server: " << sha1_hex << " is " << filename
2451 void Server::sendMediaAnnouncement(u16 peer_id)
2453 DSTACK(FUNCTION_NAME);
2455 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2459 std::ostringstream os(std::ios_base::binary);
2461 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2462 pkt << (u16) m_media.size();
2464 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2465 i != m_media.end(); ++i) {
2466 pkt << i->first << i->second.sha1_digest;
2469 pkt << g_settings->get("remote_media");
2473 struct SendableMedia
2479 SendableMedia(const std::string &name_="", const std::string &path_="",
2480 const std::string &data_=""):
2487 void Server::sendRequestedMedia(u16 peer_id,
2488 const std::vector<std::string> &tosend)
2490 DSTACK(FUNCTION_NAME);
2492 verbosestream<<"Server::sendRequestedMedia(): "
2493 <<"Sending files to client"<<std::endl;
2497 // Put 5kB in one bunch (this is not accurate)
2498 u32 bytes_per_bunch = 5000;
2500 std::vector< std::vector<SendableMedia> > file_bunches;
2501 file_bunches.push_back(std::vector<SendableMedia>());
2503 u32 file_size_bunch_total = 0;
2505 for(std::vector<std::string>::const_iterator i = tosend.begin();
2506 i != tosend.end(); ++i) {
2507 const std::string &name = *i;
2509 if (m_media.find(name) == m_media.end()) {
2510 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2511 <<"unknown file \""<<(name)<<"\""<<std::endl;
2515 //TODO get path + name
2516 std::string tpath = m_media[name].path;
2519 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2520 if(fis.good() == false){
2521 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2522 <<tpath<<"\" for reading"<<std::endl;
2525 std::ostringstream tmp_os(std::ios_base::binary);
2529 fis.read(buf, 1024);
2530 std::streamsize len = fis.gcount();
2531 tmp_os.write(buf, len);
2532 file_size_bunch_total += len;
2541 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2542 <<name<<"\""<<std::endl;
2545 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2546 <<tname<<"\""<<std::endl;*/
2548 file_bunches[file_bunches.size()-1].push_back(
2549 SendableMedia(name, tpath, tmp_os.str()));
2551 // Start next bunch if got enough data
2552 if(file_size_bunch_total >= bytes_per_bunch) {
2553 file_bunches.push_back(std::vector<SendableMedia>());
2554 file_size_bunch_total = 0;
2559 /* Create and send packets */
2561 u16 num_bunches = file_bunches.size();
2562 for(u16 i = 0; i < num_bunches; i++) {
2565 u16 total number of texture bunches
2566 u16 index of this bunch
2567 u32 number of files in this bunch
2576 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2577 pkt << num_bunches << i << (u32) file_bunches[i].size();
2579 for(std::vector<SendableMedia>::iterator
2580 j = file_bunches[i].begin();
2581 j != file_bunches[i].end(); ++j) {
2583 pkt.putLongString(j->data);
2586 verbosestream << "Server::sendRequestedMedia(): bunch "
2587 << i << "/" << num_bunches
2588 << " files=" << file_bunches[i].size()
2589 << " size=" << pkt.getSize() << std::endl;
2594 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2596 if(m_detached_inventories.count(name) == 0) {
2597 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2600 Inventory *inv = m_detached_inventories[name];
2601 std::ostringstream os(std::ios_base::binary);
2603 os << serializeString(name);
2607 std::string s = os.str();
2609 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2610 pkt.putRawString(s.c_str(), s.size());
2612 const std::string &check = m_detached_inventories_player[name];
2613 if (peer_id == PEER_ID_INEXISTENT) {
2615 return m_clients.sendToAll(&pkt);
2616 RemotePlayer *p = m_env->getPlayer(check.c_str());
2618 m_clients.send(p->peer_id, 0, &pkt, true);
2620 if (check == "" || getPlayerName(peer_id) == check)
2625 void Server::sendDetachedInventories(u16 peer_id)
2627 DSTACK(FUNCTION_NAME);
2629 for(std::map<std::string, Inventory*>::iterator
2630 i = m_detached_inventories.begin();
2631 i != m_detached_inventories.end(); ++i) {
2632 const std::string &name = i->first;
2633 //Inventory *inv = i->second;
2634 sendDetachedInventory(name, peer_id);
2642 void Server::DiePlayer(u16 peer_id)
2644 DSTACK(FUNCTION_NAME);
2645 PlayerSAO *playersao = getPlayerSAO(peer_id);
2646 // In some rare cases this can be NULL -- if the player is disconnected
2647 // when a Lua function modifies l_punch, for example
2651 infostream << "Server::DiePlayer(): Player "
2652 << playersao->getPlayer()->getName()
2653 << " dies" << std::endl;
2655 playersao->setHP(0);
2657 // Trigger scripted stuff
2658 m_script->on_dieplayer(playersao);
2660 SendPlayerHP(peer_id);
2661 SendDeathscreen(peer_id, false, v3f(0,0,0));
2664 void Server::RespawnPlayer(u16 peer_id)
2666 DSTACK(FUNCTION_NAME);
2668 PlayerSAO *playersao = getPlayerSAO(peer_id);
2671 infostream << "Server::RespawnPlayer(): Player "
2672 << playersao->getPlayer()->getName()
2673 << " respawns" << std::endl;
2675 playersao->setHP(PLAYER_MAX_HP);
2676 playersao->setBreath(PLAYER_MAX_BREATH);
2678 bool repositioned = m_script->on_respawnplayer(playersao);
2679 if (!repositioned) {
2680 // setPos will send the new position to client
2681 playersao->setPos(findSpawnPos());
2684 SendPlayerHP(peer_id);
2688 void Server::DenySudoAccess(u16 peer_id)
2690 DSTACK(FUNCTION_NAME);
2692 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2697 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2698 const std::string &str_reason, bool reconnect)
2700 if (proto_ver >= 25) {
2701 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2703 std::wstring wreason = utf8_to_wide(
2704 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2705 accessDeniedStrings[(u8)reason]);
2706 SendAccessDenied_Legacy(peer_id, wreason);
2709 m_clients.event(peer_id, CSE_SetDenied);
2710 m_con.DisconnectPeer(peer_id);
2714 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2716 DSTACK(FUNCTION_NAME);
2718 SendAccessDenied(peer_id, reason, custom_reason);
2719 m_clients.event(peer_id, CSE_SetDenied);
2720 m_con.DisconnectPeer(peer_id);
2723 // 13/03/15: remove this function when protocol version 25 will become
2724 // the minimum version for MT users, maybe in 1 year
2725 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2727 DSTACK(FUNCTION_NAME);
2729 SendAccessDenied_Legacy(peer_id, reason);
2730 m_clients.event(peer_id, CSE_SetDenied);
2731 m_con.DisconnectPeer(peer_id);
2734 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2736 DSTACK(FUNCTION_NAME);
2739 RemoteClient* client = getClient(peer_id, CS_Invalid);
2741 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2743 // Right now, the auth mechs don't change between login and sudo mode.
2744 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2745 client->allowed_sudo_mechs = sudo_auth_mechs;
2747 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2748 << g_settings->getFloat("dedicated_server_step")
2752 m_clients.event(peer_id, CSE_AuthAccept);
2754 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2756 // We only support SRP right now
2757 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2759 resp_pkt << sudo_auth_mechs;
2761 m_clients.event(peer_id, CSE_SudoSuccess);
2765 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2767 DSTACK(FUNCTION_NAME);
2768 std::wstring message;
2771 Clear references to playing sounds
2773 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2774 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2775 ServerPlayingSound &psound = i->second;
2776 psound.clients.erase(peer_id);
2777 if (psound.clients.empty())
2778 m_playing_sounds.erase(i++);
2783 RemotePlayer *player = m_env->getPlayer(peer_id);
2785 /* Run scripts and remove from environment */
2786 if (player != NULL) {
2787 PlayerSAO *playersao = player->getPlayerSAO();
2790 // inform connected clients
2791 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2792 // (u16) 1 + std::string represents a vector serialization representation
2793 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2794 m_clients.sendToAll(¬ice);
2796 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2798 playersao->disconnected();
2805 if(player != NULL && reason != CDR_DENY) {
2806 std::ostringstream os(std::ios_base::binary);
2807 std::vector<u16> clients = m_clients.getClientIDs();
2809 for(std::vector<u16>::iterator i = clients.begin();
2810 i != clients.end(); ++i) {
2812 RemotePlayer *player = m_env->getPlayer(*i);
2816 // Get name of player
2817 os << player->getName() << " ";
2820 std::string name = player->getName();
2821 actionstream << name << " "
2822 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2823 << " List of players: " << os.str() << std::endl;
2825 m_admin_chat->outgoing_queue.push_back(
2826 new ChatEventNick(CET_NICK_REMOVE, name));
2830 MutexAutoLock env_lock(m_env_mutex);
2831 m_clients.DeleteClient(peer_id);
2835 // Send leave chat message to all remaining clients
2836 if(message.length() != 0)
2837 SendChatMessage(PEER_ID_INEXISTENT,message);
2840 void Server::UpdateCrafting(RemotePlayer *player)
2842 DSTACK(FUNCTION_NAME);
2844 // Get a preview for crafting
2846 InventoryLocation loc;
2847 loc.setPlayer(player->getName());
2848 std::vector<ItemStack> output_replacements;
2849 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2850 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2851 (&player->inventory)->getList("craft"), loc);
2853 // Put the new preview in
2854 InventoryList *plist = player->inventory.getList("craftpreview");
2855 sanity_check(plist);
2856 sanity_check(plist->getSize() >= 1);
2857 plist->changeItem(0, preview);
2860 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2862 if (evt->type == CET_NICK_ADD) {
2863 // The terminal informed us of its nick choice
2864 m_admin_nick = ((ChatEventNick *)evt)->nick;
2865 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2866 errorstream << "You haven't set up an account." << std::endl
2867 << "Please log in using the client as '"
2868 << m_admin_nick << "' with a secure password." << std::endl
2869 << "Until then, you can't execute admin tasks via the console," << std::endl
2870 << "and everybody can claim the user account instead of you," << std::endl
2871 << "giving them full control over this server." << std::endl;
2874 assert(evt->type == CET_CHAT);
2875 handleAdminChat((ChatEventChat *)evt);
2879 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2880 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2882 // If something goes wrong, this player is to blame
2883 RollbackScopeActor rollback_scope(m_rollback,
2884 std::string("player:") + name);
2886 if (g_settings->getBool("strip_color_codes"))
2887 wmessage = unescape_enriched(wmessage);
2890 switch (player->canSendChatMessage()) {
2891 case RPLAYER_CHATRESULT_FLOODING: {
2892 std::wstringstream ws;
2893 ws << L"You cannot send more messages. You are limited to "
2894 << g_settings->getFloat("chat_message_limit_per_10sec")
2895 << L" messages per 10 seconds.";
2898 case RPLAYER_CHATRESULT_KICK:
2899 DenyAccess_Legacy(player->peer_id,
2900 L"You have been kicked due to message flooding.");
2902 case RPLAYER_CHATRESULT_OK:
2905 FATAL_ERROR("Unhandled chat filtering result found.");
2909 if (m_max_chatmessage_length > 0
2910 && wmessage.length() > m_max_chatmessage_length) {
2911 return L"Your message exceed the maximum chat message limit set on the server. "
2912 L"It was refused. Send a shorter message";
2915 // Run script hook, exit if script ate the chat message
2916 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2921 // Whether to send line to the player that sent the message, or to all players
2922 bool broadcast_line = true;
2924 if (check_shout_priv && !checkPriv(name, "shout")) {
2925 line += L"-!- You don't have permission to shout.";
2926 broadcast_line = false;
2935 Tell calling method to send the message to sender
2937 if (!broadcast_line) {
2941 Send the message to others
2943 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2945 std::vector<u16> clients = m_clients.getClientIDs();
2948 Send the message back to the inital sender
2949 if they are using protocol version >= 29
2952 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2953 if (player && player->protocol_version >= 29)
2954 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2956 for (u16 i = 0; i < clients.size(); i++) {
2957 u16 cid = clients[i];
2958 if (cid != peer_id_to_avoid_sending)
2959 SendChatMessage(cid, line);
2965 void Server::handleAdminChat(const ChatEventChat *evt)
2967 std::string name = evt->nick;
2968 std::wstring wname = utf8_to_wide(name);
2969 std::wstring wmessage = evt->evt_msg;
2971 std::wstring answer = handleChat(name, wname, wmessage);
2973 // If asked to send answer to sender
2974 if (!answer.empty()) {
2975 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2979 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2981 RemoteClient *client = getClientNoEx(peer_id,state_min);
2983 throw ClientNotFoundException("Client not found");
2987 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2989 return m_clients.getClientNoEx(peer_id, state_min);
2992 std::string Server::getPlayerName(u16 peer_id)
2994 RemotePlayer *player = m_env->getPlayer(peer_id);
2996 return "[id="+itos(peer_id)+"]";
2997 return player->getName();
3000 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3002 RemotePlayer *player = m_env->getPlayer(peer_id);
3005 return player->getPlayerSAO();
3008 std::wstring Server::getStatusString()
3010 std::wostringstream os(std::ios_base::binary);
3013 os<<L"version="<<narrow_to_wide(g_version_string);
3015 os<<L", uptime="<<m_uptime.get();
3017 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3018 // Information about clients
3021 std::vector<u16> clients = m_clients.getClientIDs();
3022 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3024 RemotePlayer *player = m_env->getPlayer(*i);
3025 // Get name of player
3026 std::wstring name = L"unknown";
3028 name = narrow_to_wide(player->getName());
3029 // Add name to information string
3037 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3038 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3039 if(g_settings->get("motd") != "")
3040 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3044 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3046 std::set<std::string> privs;
3047 m_script->getAuth(name, NULL, &privs);
3051 bool Server::checkPriv(const std::string &name, const std::string &priv)
3053 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3054 return (privs.count(priv) != 0);
3057 void Server::reportPrivsModified(const std::string &name)
3060 std::vector<u16> clients = m_clients.getClientIDs();
3061 for(std::vector<u16>::iterator i = clients.begin();
3062 i != clients.end(); ++i) {
3063 RemotePlayer *player = m_env->getPlayer(*i);
3064 reportPrivsModified(player->getName());
3067 RemotePlayer *player = m_env->getPlayer(name.c_str());
3070 SendPlayerPrivileges(player->peer_id);
3071 PlayerSAO *sao = player->getPlayerSAO();
3074 sao->updatePrivileges(
3075 getPlayerEffectivePrivs(name),
3080 void Server::reportInventoryFormspecModified(const std::string &name)
3082 RemotePlayer *player = m_env->getPlayer(name.c_str());
3085 SendPlayerInventoryFormspec(player->peer_id);
3088 void Server::setIpBanned(const std::string &ip, const std::string &name)
3090 m_banmanager->add(ip, name);
3093 void Server::unsetIpBanned(const std::string &ip_or_name)
3095 m_banmanager->remove(ip_or_name);
3098 std::string Server::getBanDescription(const std::string &ip_or_name)
3100 return m_banmanager->getBanDescription(ip_or_name);
3103 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3105 // m_env will be NULL if the server is initializing
3109 if (m_admin_nick == name && !m_admin_nick.empty()) {
3110 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3113 RemotePlayer *player = m_env->getPlayer(name);
3118 if (player->peer_id == PEER_ID_INEXISTENT)
3121 SendChatMessage(player->peer_id, msg);
3124 bool Server::showFormspec(const char *playername, const std::string &formspec,
3125 const std::string &formname)
3127 // m_env will be NULL if the server is initializing
3131 RemotePlayer *player = m_env->getPlayer(playername);
3135 SendShowFormspecMessage(player->peer_id, formspec, formname);
3139 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3144 u32 id = player->addHud(form);
3146 SendHUDAdd(player->peer_id, id, form);
3151 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3155 HudElement* todel = player->removeHud(id);
3162 SendHUDRemove(player->peer_id, id);
3166 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3171 SendHUDChange(player->peer_id, id, stat, data);
3175 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3180 SendHUDSetFlags(player->peer_id, flags, mask);
3181 player->hud_flags &= ~mask;
3182 player->hud_flags |= flags;
3184 PlayerSAO* playersao = player->getPlayerSAO();
3186 if (playersao == NULL)
3189 m_script->player_event(playersao, "hud_changed");
3193 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3198 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3201 player->setHotbarItemcount(hotbar_itemcount);
3202 std::ostringstream os(std::ios::binary);
3203 writeS32(os, hotbar_itemcount);
3204 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3208 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3213 player->setHotbarImage(name);
3214 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3217 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3221 return player->getHotbarImage();
3224 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3229 player->setHotbarSelectedImage(name);
3230 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3233 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3234 v2s32 animation_frames[4], f32 frame_speed)
3239 player->setLocalAnimations(animation_frames, frame_speed);
3240 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3244 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3249 player->eye_offset_first = first;
3250 player->eye_offset_third = third;
3251 SendEyeOffset(player->peer_id, first, third);
3255 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3256 const std::string &type, const std::vector<std::string> ¶ms,
3262 player->setSky(bgcolor, type, params, clouds);
3263 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3267 bool Server::setClouds(RemotePlayer *player, float density,
3268 const video::SColor &color_bright,
3269 const video::SColor &color_ambient,
3277 SendCloudParams(player->peer_id, density,
3278 color_bright, color_ambient, height,
3283 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3289 player->overrideDayNightRatio(do_override, ratio);
3290 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3294 void Server::notifyPlayers(const std::wstring &msg)
3296 SendChatMessage(PEER_ID_INEXISTENT,msg);
3299 void Server::spawnParticle(const std::string &playername, v3f pos,
3300 v3f velocity, v3f acceleration,
3301 float expirationtime, float size, bool
3302 collisiondetection, bool collision_removal,
3303 bool vertical, const std::string &texture,
3304 const struct TileAnimationParams &animation, u8 glow)
3306 // m_env will be NULL if the server is initializing
3310 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3311 if (playername != "") {
3312 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3315 peer_id = player->peer_id;
3316 proto_ver = player->protocol_version;
3319 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3320 expirationtime, size, collisiondetection,
3321 collision_removal, vertical, texture, animation, glow);
3324 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3325 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3326 float minexptime, float maxexptime, float minsize, float maxsize,
3327 bool collisiondetection, bool collision_removal,
3328 ServerActiveObject *attached, bool vertical, const std::string &texture,
3329 const std::string &playername, const struct TileAnimationParams &animation,
3332 // m_env will be NULL if the server is initializing
3336 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3337 if (playername != "") {
3338 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3341 peer_id = player->peer_id;
3342 proto_ver = player->protocol_version;
3345 u16 attached_id = attached ? attached->getId() : 0;
3348 if (attached_id == 0)
3349 id = m_env->addParticleSpawner(spawntime);
3351 id = m_env->addParticleSpawner(spawntime, attached_id);
3353 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3354 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3355 minexptime, maxexptime, minsize, maxsize,
3356 collisiondetection, collision_removal, attached_id, vertical,
3357 texture, id, animation, glow);
3362 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3364 // m_env will be NULL if the server is initializing
3366 throw ServerError("Can't delete particle spawners during initialisation!");
3368 u16 peer_id = PEER_ID_INEXISTENT;
3369 if (playername != "") {
3370 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3373 peer_id = player->peer_id;
3376 m_env->deleteParticleSpawner(id);
3377 SendDeleteParticleSpawner(peer_id, id);
3380 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3382 if(m_detached_inventories.count(name) > 0){
3383 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3384 delete m_detached_inventories[name];
3386 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3388 Inventory *inv = new Inventory(m_itemdef);
3390 m_detached_inventories[name] = inv;
3391 m_detached_inventories_player[name] = player;
3392 //TODO find a better way to do this
3393 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3397 // actions: time-reversed list
3398 // Return value: success/failure
3399 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3400 std::list<std::string> *log)
3402 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3403 ServerMap *map = (ServerMap*)(&m_env->getMap());
3405 // Fail if no actions to handle
3406 if(actions.empty()){
3407 log->push_back("Nothing to do.");
3414 for(std::list<RollbackAction>::const_iterator
3415 i = actions.begin();
3416 i != actions.end(); ++i)
3418 const RollbackAction &action = *i;
3420 bool success = action.applyRevert(map, this, this);
3423 std::ostringstream os;
3424 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3425 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3427 log->push_back(os.str());
3429 std::ostringstream os;
3430 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3431 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3433 log->push_back(os.str());
3437 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3438 <<" failed"<<std::endl;
3440 // Call it done if less than half failed
3441 return num_failed <= num_tried/2;
3444 // IGameDef interface
3446 IItemDefManager *Server::getItemDefManager()
3451 INodeDefManager *Server::getNodeDefManager()
3456 ICraftDefManager *Server::getCraftDefManager()
3461 u16 Server::allocateUnknownNodeId(const std::string &name)
3463 return m_nodedef->allocateDummy(name);
3466 MtEventManager *Server::getEventManager()
3471 IWritableItemDefManager *Server::getWritableItemDefManager()
3476 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3481 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3486 const ModSpec *Server::getModSpec(const std::string &modname) const
3488 std::vector<ModSpec>::const_iterator it;
3489 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3490 const ModSpec &mod = *it;
3491 if (mod.name == modname)
3497 void Server::getModNames(std::vector<std::string> &modlist)
3499 std::vector<ModSpec>::iterator it;
3500 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3501 modlist.push_back(it->name);
3504 std::string Server::getBuiltinLuaPath()
3506 return porting::path_share + DIR_DELIM + "builtin";
3509 std::string Server::getModStoragePath() const
3511 return m_path_world + DIR_DELIM + "mod_storage";
3514 v3f Server::findSpawnPos()
3516 ServerMap &map = m_env->getServerMap();
3518 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3519 return nodeposf * BS;
3522 bool is_good = false;
3523 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3524 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3526 // Try to find a good place a few times
3527 for(s32 i = 0; i < 4000 && !is_good; i++) {
3528 s32 range = MYMIN(1 + i, range_max);
3529 // We're going to try to throw the player to this position
3530 v2s16 nodepos2d = v2s16(
3531 -range + (myrand() % (range * 2)),
3532 -range + (myrand() % (range * 2)));
3534 // Get spawn level at point
3535 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3536 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3537 // the mapgen to signify an unsuitable spawn position
3538 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3541 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3544 for (s32 i = 0; i < 10; i++) {
3545 v3s16 blockpos = getNodeBlockPos(nodepos);
3546 map.emergeBlock(blockpos, true);
3547 content_t c = map.getNodeNoEx(nodepos).getContent();
3548 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3550 if (air_count >= 2) {
3551 nodeposf = intToFloat(nodepos, BS);
3552 // Don't spawn the player outside map boundaries
3553 if (objectpos_over_limit(nodeposf))
3566 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3568 m_shutdown_timer = delay;
3569 m_shutdown_msg = msg;
3570 m_shutdown_ask_reconnect = reconnect;
3572 if (delay == 0.0f) {
3573 // No delay, shutdown immediately
3574 m_shutdown_requested = true;
3575 // only print to the infostream, a chat message saying
3576 // "Server Shutting Down" is sent when the server destructs.
3577 infostream << "*** Immediate Server shutdown requested." << std::endl;
3578 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3579 // Negative delay, cancel shutdown if requested
3580 m_shutdown_timer = 0.0f;
3581 m_shutdown_msg = "";
3582 m_shutdown_ask_reconnect = false;
3583 m_shutdown_requested = false;
3584 std::wstringstream ws;
3586 ws << L"*** Server shutdown canceled.";
3588 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3589 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3590 } else if (delay > 0.0f) {
3591 // Positive delay, tell the clients when the server will shut down
3592 std::wstringstream ws;
3594 ws << L"*** Server shutting down in "
3595 << duration_to_string(myround(m_shutdown_timer)).c_str()
3598 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3599 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3603 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3606 Try to get an existing player
3608 RemotePlayer *player = m_env->getPlayer(name);
3610 // If player is already connected, cancel
3611 if (player != NULL && player->peer_id != 0) {
3612 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3617 If player with the wanted peer_id already exists, cancel.
3619 if (m_env->getPlayer(peer_id) != NULL) {
3620 infostream<<"emergePlayer(): Player with wrong name but same"
3621 " peer_id already exists"<<std::endl;
3626 player = new RemotePlayer(name, idef());
3629 bool newplayer = false;
3632 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3634 // Complete init with server parts
3635 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3636 player->protocol_version = proto_version;
3640 m_script->on_newplayer(playersao);
3646 bool Server::registerModStorage(ModMetadata *storage)
3648 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3649 errorstream << "Unable to register same mod storage twice. Storage name: "
3650 << storage->getModName() << std::endl;
3654 m_mod_storages[storage->getModName()] = storage;
3658 void Server::unregisterModStorage(const std::string &name)
3660 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3661 if (it != m_mod_storages.end()) {
3662 // Save unconditionaly on unregistration
3663 it->second->save(getModStoragePath());
3664 m_mod_storages.erase(name);
3668 void dedicated_server_loop(Server &server, bool &kill)
3670 DSTACK(FUNCTION_NAME);
3672 verbosestream<<"dedicated_server_loop()"<<std::endl;
3674 IntervalLimiter m_profiler_interval;
3676 static thread_local const float steplen =
3677 g_settings->getFloat("dedicated_server_step");
3678 static thread_local const float profiler_print_interval =
3679 g_settings->getFloat("profiler_print_interval");
3682 // This is kind of a hack but can be done like this
3683 // because server.step() is very light
3685 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3686 sleep_ms((int)(steplen*1000.0));
3688 server.step(steplen);
3690 if (server.getShutdownRequested() || kill)
3696 if (profiler_print_interval != 0) {
3697 if(m_profiler_interval.step(steplen, profiler_print_interval))
3699 infostream<<"Profiler:"<<std::endl;
3700 g_profiler->print(infostream);
3701 g_profiler->clear();
3706 infostream << "Dedicated server quitting" << std::endl;
3708 if (g_settings->getBool("server_announce"))
3709 ServerList::sendAnnounce(ServerList::AA_DELETE,
3710 server.m_bind_addr.getPort());