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);
1025 SharedBuffer<u8> data;
1029 m_con.Receive(&pkt);
1030 peer_id = pkt.getPeerId();
1033 catch(con::InvalidIncomingDataException &e) {
1034 infostream<<"Server::Receive(): "
1035 "InvalidIncomingDataException: what()="
1036 <<e.what()<<std::endl;
1038 catch(SerializationError &e) {
1039 infostream<<"Server::Receive(): "
1040 "SerializationError: what()="
1041 <<e.what()<<std::endl;
1043 catch(ClientStateError &e) {
1044 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1045 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1046 L"Try reconnecting or updating your client");
1048 catch(con::PeerNotFoundException &e) {
1053 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1055 std::string playername = "";
1056 PlayerSAO *playersao = NULL;
1059 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1060 if (client != NULL) {
1061 playername = client->getName();
1062 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1064 } catch (std::exception &e) {
1070 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1072 // If failed, cancel
1073 if ((playersao == NULL) || (player == NULL)) {
1074 if (player && player->peer_id != 0) {
1075 actionstream << "Server: Failed to emerge player \"" << playername
1076 << "\" (player allocated to an another client)" << std::endl;
1077 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1078 L"name. If your client closed unexpectedly, try again in "
1081 errorstream << "Server: " << playername << ": Failed to emerge player"
1083 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1089 Send complete position information
1091 SendMovePlayer(peer_id);
1094 SendPlayerPrivileges(peer_id);
1096 // Send inventory formspec
1097 SendPlayerInventoryFormspec(peer_id);
1100 SendInventory(playersao);
1102 // Send HP or death screen
1103 if (playersao->isDead())
1104 SendDeathscreen(peer_id, false, v3f(0,0,0));
1106 SendPlayerHPOrDie(playersao);
1109 SendPlayerBreath(playersao);
1111 // Note things in chat if not in simple singleplayer mode
1112 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1113 // Send information about server to player in chat
1114 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1116 Address addr = getPeerAddress(player->peer_id);
1117 std::string ip_str = addr.serializeString();
1118 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1123 const std::vector<std::string> &names = m_clients.getPlayerNames();
1125 actionstream << player->getName() << " joins game. List of players: ";
1127 for (std::vector<std::string>::const_iterator i = names.begin();
1128 i != names.end(); ++i) {
1129 actionstream << *i << " ";
1132 actionstream << player->getName() <<std::endl;
1137 inline void Server::handleCommand(NetworkPacket* pkt)
1139 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1140 (this->*opHandle.handler)(pkt);
1143 void Server::ProcessData(NetworkPacket *pkt)
1145 DSTACK(FUNCTION_NAME);
1146 // Environment is locked first.
1147 MutexAutoLock envlock(m_env_mutex);
1149 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1150 u32 peer_id = pkt->getPeerId();
1153 Address address = getPeerAddress(peer_id);
1154 std::string addr_s = address.serializeString();
1156 if(m_banmanager->isIpBanned(addr_s)) {
1157 std::string ban_name = m_banmanager->getBanName(addr_s);
1158 infostream << "Server: A banned client tried to connect from "
1159 << addr_s << "; banned name was "
1160 << ban_name << std::endl;
1161 // This actually doesn't seem to transfer to the client
1162 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1163 + utf8_to_wide(ban_name));
1167 catch(con::PeerNotFoundException &e) {
1169 * no peer for this packet found
1170 * most common reason is peer timeout, e.g. peer didn't
1171 * respond for some time, your server was overloaded or
1174 infostream << "Server::ProcessData(): Canceling: peer "
1175 << peer_id << " not found" << std::endl;
1180 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1182 // Command must be handled into ToServerCommandHandler
1183 if (command >= TOSERVER_NUM_MSG_TYPES) {
1184 infostream << "Server: Ignoring unknown command "
1185 << command << std::endl;
1189 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1194 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1196 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1197 errorstream << "Server::ProcessData(): Cancelling: Peer"
1198 " serialization format invalid or not initialized."
1199 " Skipping incoming command=" << command << std::endl;
1203 /* Handle commands related to client startup */
1204 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1209 if (m_clients.getClientState(peer_id) < CS_Active) {
1210 if (command == TOSERVER_PLAYERPOS) return;
1212 errorstream << "Got packet command: " << command << " for peer id "
1213 << peer_id << " but client isn't active yet. Dropping packet "
1219 } catch (SendFailedException &e) {
1220 errorstream << "Server::ProcessData(): SendFailedException: "
1221 << "what=" << e.what()
1223 } catch (PacketError &e) {
1224 actionstream << "Server::ProcessData(): PacketError: "
1225 << "what=" << e.what()
1230 void Server::setTimeOfDay(u32 time)
1232 m_env->setTimeOfDay(time);
1233 m_time_of_day_send_timer = 0;
1236 void Server::onMapEditEvent(MapEditEvent *event)
1238 if(m_ignore_map_edit_events)
1240 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1242 MapEditEvent *e = event->clone();
1243 m_unsent_map_edit_queue.push(e);
1246 Inventory* Server::getInventory(const InventoryLocation &loc)
1249 case InventoryLocation::UNDEFINED:
1250 case InventoryLocation::CURRENT_PLAYER:
1252 case InventoryLocation::PLAYER:
1254 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1257 PlayerSAO *playersao = player->getPlayerSAO();
1260 return playersao->getInventory();
1263 case InventoryLocation::NODEMETA:
1265 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1268 return meta->getInventory();
1271 case InventoryLocation::DETACHED:
1273 if(m_detached_inventories.count(loc.name) == 0)
1275 return m_detached_inventories[loc.name];
1279 sanity_check(false); // abort
1284 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1287 case InventoryLocation::UNDEFINED:
1289 case InventoryLocation::PLAYER:
1294 RemotePlayer *player =
1295 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1300 PlayerSAO *playersao = player->getPlayerSAO();
1304 SendInventory(playersao);
1307 case InventoryLocation::NODEMETA:
1309 v3s16 blockpos = getNodeBlockPos(loc.p);
1311 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1313 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1315 setBlockNotSent(blockpos);
1318 case InventoryLocation::DETACHED:
1320 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1324 sanity_check(false); // abort
1329 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1331 std::vector<u16> clients = m_clients.getClientIDs();
1333 // Set the modified blocks unsent for all the clients
1334 for (std::vector<u16>::iterator i = clients.begin();
1335 i != clients.end(); ++i) {
1336 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1337 client->SetBlocksNotSent(block);
1342 void Server::peerAdded(con::Peer *peer)
1344 DSTACK(FUNCTION_NAME);
1345 verbosestream<<"Server::peerAdded(): peer->id="
1346 <<peer->id<<std::endl;
1349 c.type = con::PEER_ADDED;
1350 c.peer_id = peer->id;
1352 m_peer_change_queue.push(c);
1355 void Server::deletingPeer(con::Peer *peer, bool timeout)
1357 DSTACK(FUNCTION_NAME);
1358 verbosestream<<"Server::deletingPeer(): peer->id="
1359 <<peer->id<<", timeout="<<timeout<<std::endl;
1361 m_clients.event(peer->id, CSE_Disconnect);
1363 c.type = con::PEER_REMOVED;
1364 c.peer_id = peer->id;
1365 c.timeout = timeout;
1366 m_peer_change_queue.push(c);
1369 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1371 *retval = m_con.getPeerStat(peer_id,type);
1372 if (*retval == -1) return false;
1376 bool Server::getClientInfo(
1385 std::string* vers_string
1388 *state = m_clients.getClientState(peer_id);
1390 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1392 if (client == NULL) {
1397 *uptime = client->uptime();
1398 *ser_vers = client->serialization_version;
1399 *prot_vers = client->net_proto_version;
1401 *major = client->getMajor();
1402 *minor = client->getMinor();
1403 *patch = client->getPatch();
1404 *vers_string = client->getPatch();
1411 void Server::handlePeerChanges()
1413 while(m_peer_change_queue.size() > 0)
1415 con::PeerChange c = m_peer_change_queue.front();
1416 m_peer_change_queue.pop();
1418 verbosestream<<"Server: Handling peer change: "
1419 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1424 case con::PEER_ADDED:
1425 m_clients.CreateClient(c.peer_id);
1428 case con::PEER_REMOVED:
1429 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1433 FATAL_ERROR("Invalid peer change event received!");
1439 void Server::printToConsoleOnly(const std::string &text)
1442 m_admin_chat->outgoing_queue.push_back(
1443 new ChatEventChat("", utf8_to_wide(text)));
1445 std::cout << text << std::endl;
1449 void Server::Send(NetworkPacket* pkt)
1451 m_clients.send(pkt->getPeerId(),
1452 clientCommandFactoryTable[pkt->getCommand()].channel,
1454 clientCommandFactoryTable[pkt->getCommand()].reliable);
1457 void Server::SendMovement(u16 peer_id)
1459 DSTACK(FUNCTION_NAME);
1460 std::ostringstream os(std::ios_base::binary);
1462 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1464 pkt << g_settings->getFloat("movement_acceleration_default");
1465 pkt << g_settings->getFloat("movement_acceleration_air");
1466 pkt << g_settings->getFloat("movement_acceleration_fast");
1467 pkt << g_settings->getFloat("movement_speed_walk");
1468 pkt << g_settings->getFloat("movement_speed_crouch");
1469 pkt << g_settings->getFloat("movement_speed_fast");
1470 pkt << g_settings->getFloat("movement_speed_climb");
1471 pkt << g_settings->getFloat("movement_speed_jump");
1472 pkt << g_settings->getFloat("movement_liquid_fluidity");
1473 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1474 pkt << g_settings->getFloat("movement_liquid_sink");
1475 pkt << g_settings->getFloat("movement_gravity");
1480 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1482 if (!g_settings->getBool("enable_damage"))
1485 u16 peer_id = playersao->getPeerID();
1486 bool is_alive = playersao->getHP() > 0;
1489 SendPlayerHP(peer_id);
1494 void Server::SendHP(u16 peer_id, u8 hp)
1496 DSTACK(FUNCTION_NAME);
1498 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1503 void Server::SendBreath(u16 peer_id, u16 breath)
1505 DSTACK(FUNCTION_NAME);
1507 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1508 pkt << (u16) breath;
1512 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1513 const std::string &custom_reason, bool reconnect)
1515 assert(reason < SERVER_ACCESSDENIED_MAX);
1517 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1519 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1520 pkt << custom_reason;
1521 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1522 reason == SERVER_ACCESSDENIED_CRASH)
1523 pkt << custom_reason << (u8)reconnect;
1527 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1529 DSTACK(FUNCTION_NAME);
1531 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1536 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1537 v3f camera_point_target)
1539 DSTACK(FUNCTION_NAME);
1541 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1542 pkt << set_camera_point_target << camera_point_target;
1546 void Server::SendItemDef(u16 peer_id,
1547 IItemDefManager *itemdef, u16 protocol_version)
1549 DSTACK(FUNCTION_NAME);
1551 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1555 u32 length of the next item
1556 zlib-compressed serialized ItemDefManager
1558 std::ostringstream tmp_os(std::ios::binary);
1559 itemdef->serialize(tmp_os, protocol_version);
1560 std::ostringstream tmp_os2(std::ios::binary);
1561 compressZlib(tmp_os.str(), tmp_os2);
1562 pkt.putLongString(tmp_os2.str());
1565 verbosestream << "Server: Sending item definitions to id(" << peer_id
1566 << "): size=" << pkt.getSize() << std::endl;
1571 void Server::SendNodeDef(u16 peer_id,
1572 INodeDefManager *nodedef, u16 protocol_version)
1574 DSTACK(FUNCTION_NAME);
1576 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1580 u32 length of the next item
1581 zlib-compressed serialized NodeDefManager
1583 std::ostringstream tmp_os(std::ios::binary);
1584 nodedef->serialize(tmp_os, protocol_version);
1585 std::ostringstream tmp_os2(std::ios::binary);
1586 compressZlib(tmp_os.str(), tmp_os2);
1588 pkt.putLongString(tmp_os2.str());
1591 verbosestream << "Server: Sending node definitions to id(" << peer_id
1592 << "): size=" << pkt.getSize() << std::endl;
1598 Non-static send methods
1601 void Server::SendInventory(PlayerSAO* playerSAO)
1603 DSTACK(FUNCTION_NAME);
1605 UpdateCrafting(playerSAO->getPlayer());
1611 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1613 std::ostringstream os;
1614 playerSAO->getInventory()->serialize(os);
1616 std::string s = os.str();
1618 pkt.putRawString(s.c_str(), s.size());
1622 void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
1624 DSTACK(FUNCTION_NAME);
1626 NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
1627 legacypkt << message.message;
1629 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1631 u8 type = message.type;
1632 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1634 if (peer_id != PEER_ID_INEXISTENT) {
1635 RemotePlayer *player = m_env->getPlayer(peer_id);
1639 if (player->protocol_version < 35)
1644 m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
1648 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1649 const std::string &formname)
1651 DSTACK(FUNCTION_NAME);
1653 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1654 if (formspec == "" ){
1655 //the client should close the formspec
1656 pkt.putLongString("");
1658 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1665 // Spawns a particle on peer with peer_id
1666 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1667 v3f pos, v3f velocity, v3f acceleration,
1668 float expirationtime, float size, bool collisiondetection,
1669 bool collision_removal,
1670 bool vertical, const std::string &texture,
1671 const struct TileAnimationParams &animation, u8 glow)
1673 DSTACK(FUNCTION_NAME);
1674 static thread_local const float radius =
1675 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1677 if (peer_id == PEER_ID_INEXISTENT) {
1678 std::vector<u16> clients = m_clients.getClientIDs();
1680 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1681 RemotePlayer *player = m_env->getPlayer(*i);
1685 PlayerSAO *sao = player->getPlayerSAO();
1689 // Do not send to distant clients
1690 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1693 SendSpawnParticle(*i, player->protocol_version,
1694 pos, velocity, acceleration,
1695 expirationtime, size, collisiondetection,
1696 collision_removal, vertical, texture, animation, glow);
1701 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1703 pkt << pos << velocity << acceleration << expirationtime
1704 << size << collisiondetection;
1705 pkt.putLongString(texture);
1707 pkt << collision_removal;
1708 // This is horrible but required (why are there two ways to serialize pkts?)
1709 std::ostringstream os(std::ios_base::binary);
1710 animation.serialize(os, protocol_version);
1711 pkt.putRawString(os.str());
1717 // Adds a ParticleSpawner on peer with peer_id
1718 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1719 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1720 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1721 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1722 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1723 const struct TileAnimationParams &animation, u8 glow)
1725 DSTACK(FUNCTION_NAME);
1726 if (peer_id == PEER_ID_INEXISTENT) {
1727 // This sucks and should be replaced:
1728 std::vector<u16> clients = m_clients.getClientIDs();
1729 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1730 RemotePlayer *player = m_env->getPlayer(*i);
1733 SendAddParticleSpawner(*i, player->protocol_version,
1734 amount, spawntime, minpos, maxpos,
1735 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1736 minsize, maxsize, collisiondetection, collision_removal,
1737 attached_id, vertical, texture, id, animation, glow);
1742 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1744 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1745 << minacc << maxacc << minexptime << maxexptime << minsize
1746 << maxsize << collisiondetection;
1748 pkt.putLongString(texture);
1750 pkt << id << vertical;
1751 pkt << collision_removal;
1753 // This is horrible but required
1754 std::ostringstream os(std::ios_base::binary);
1755 animation.serialize(os, protocol_version);
1756 pkt.putRawString(os.str());
1762 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1764 DSTACK(FUNCTION_NAME);
1766 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1768 // Ugly error in this packet
1771 if (peer_id != PEER_ID_INEXISTENT) {
1775 m_clients.sendToAll(&pkt);
1780 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1782 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1784 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1785 << form->text << form->number << form->item << form->dir
1786 << form->align << form->offset << form->world_pos << form->size;
1791 void Server::SendHUDRemove(u16 peer_id, u32 id)
1793 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1798 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1800 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1801 pkt << id << (u8) stat;
1805 case HUD_STAT_SCALE:
1806 case HUD_STAT_ALIGN:
1807 case HUD_STAT_OFFSET:
1808 pkt << *(v2f *) value;
1812 pkt << *(std::string *) value;
1814 case HUD_STAT_WORLD_POS:
1815 pkt << *(v3f *) value;
1818 pkt << *(v2s32 *) value;
1820 case HUD_STAT_NUMBER:
1824 pkt << *(u32 *) value;
1831 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1833 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1835 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1837 pkt << flags << mask;
1842 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1844 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1845 pkt << param << value;
1849 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1850 const std::string &type, const std::vector<std::string> ¶ms,
1853 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1854 pkt << bgcolor << type << (u16) params.size();
1856 for(size_t i=0; i<params.size(); i++)
1864 void Server::SendCloudParams(u16 peer_id, float density,
1865 const video::SColor &color_bright,
1866 const video::SColor &color_ambient,
1871 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1872 pkt << density << color_bright << color_ambient
1873 << height << thickness << speed;
1878 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1881 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1884 pkt << do_override << (u16) (ratio * 65535);
1889 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1891 DSTACK(FUNCTION_NAME);
1893 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1894 pkt << time << time_speed;
1896 if (peer_id == PEER_ID_INEXISTENT) {
1897 m_clients.sendToAll(&pkt);
1904 void Server::SendPlayerHP(u16 peer_id)
1906 DSTACK(FUNCTION_NAME);
1907 PlayerSAO *playersao = getPlayerSAO(peer_id);
1908 // In some rare case if the player is disconnected
1909 // while Lua call l_punch, for example, this can be NULL
1913 SendHP(peer_id, playersao->getHP());
1914 m_script->player_event(playersao,"health_changed");
1916 // Send to other clients
1917 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1918 ActiveObjectMessage aom(playersao->getId(), true, str);
1919 playersao->m_messages_out.push(aom);
1922 void Server::SendPlayerBreath(PlayerSAO *sao)
1924 DSTACK(FUNCTION_NAME);
1927 m_script->player_event(sao, "breath_changed");
1928 SendBreath(sao->getPeerID(), sao->getBreath());
1931 void Server::SendMovePlayer(u16 peer_id)
1933 DSTACK(FUNCTION_NAME);
1934 RemotePlayer *player = m_env->getPlayer(peer_id);
1936 PlayerSAO *sao = player->getPlayerSAO();
1939 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1940 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1943 v3f pos = sao->getBasePosition();
1944 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1945 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1946 << " pitch=" << sao->getPitch()
1947 << " yaw=" << sao->getYaw()
1954 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1956 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1959 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1960 << animation_frames[3] << animation_speed;
1965 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1967 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1968 pkt << first << third;
1971 void Server::SendPlayerPrivileges(u16 peer_id)
1973 RemotePlayer *player = m_env->getPlayer(peer_id);
1975 if(player->peer_id == PEER_ID_INEXISTENT)
1978 std::set<std::string> privs;
1979 m_script->getAuth(player->getName(), NULL, &privs);
1981 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1982 pkt << (u16) privs.size();
1984 for(std::set<std::string>::const_iterator i = privs.begin();
1985 i != privs.end(); ++i) {
1992 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1994 RemotePlayer *player = m_env->getPlayer(peer_id);
1996 if(player->peer_id == PEER_ID_INEXISTENT)
1999 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2000 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2004 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2006 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2007 pkt.putRawString(datas.c_str(), datas.size());
2009 return pkt.getSize();
2012 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2014 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2015 datas.size(), peer_id);
2017 pkt.putRawString(datas.c_str(), datas.size());
2019 m_clients.send(pkt.getPeerId(),
2020 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2024 void Server::SendCSMFlavourLimits(u16 peer_id)
2026 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
2027 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
2028 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
2032 s32 Server::playSound(const SimpleSoundSpec &spec,
2033 const ServerSoundParams ¶ms)
2035 // Find out initial position of sound
2036 bool pos_exists = false;
2037 v3f pos = params.getPos(m_env, &pos_exists);
2038 // If position is not found while it should be, cancel sound
2039 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2042 // Filter destination clients
2043 std::vector<u16> dst_clients;
2044 if(params.to_player != "")
2046 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2048 infostream<<"Server::playSound: Player \""<<params.to_player
2049 <<"\" not found"<<std::endl;
2052 if(player->peer_id == PEER_ID_INEXISTENT){
2053 infostream<<"Server::playSound: Player \""<<params.to_player
2054 <<"\" not connected"<<std::endl;
2057 dst_clients.push_back(player->peer_id);
2060 std::vector<u16> clients = m_clients.getClientIDs();
2062 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2063 RemotePlayer *player = m_env->getPlayer(*i);
2067 PlayerSAO *sao = player->getPlayerSAO();
2072 if(sao->getBasePosition().getDistanceFrom(pos) >
2073 params.max_hear_distance)
2076 dst_clients.push_back(*i);
2080 if(dst_clients.empty())
2084 s32 id = m_next_sound_id++;
2085 // The sound will exist as a reference in m_playing_sounds
2086 m_playing_sounds[id] = ServerPlayingSound();
2087 ServerPlayingSound &psound = m_playing_sounds[id];
2088 psound.params = params;
2091 float gain = params.gain * spec.gain;
2092 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2093 pkt << id << spec.name << gain
2094 << (u8) params.type << pos << params.object
2095 << params.loop << params.fade << params.pitch;
2097 // Backwards compability
2098 bool play_sound = gain > 0;
2100 for (std::vector<u16>::iterator i = dst_clients.begin();
2101 i != dst_clients.end(); ++i) {
2102 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2103 psound.clients.insert(*i);
2104 m_clients.send(*i, 0, &pkt, true);
2109 void Server::stopSound(s32 handle)
2111 // Get sound reference
2112 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2113 m_playing_sounds.find(handle);
2114 if (i == m_playing_sounds.end())
2116 ServerPlayingSound &psound = i->second;
2118 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2121 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2122 si != psound.clients.end(); ++si) {
2124 m_clients.send(*si, 0, &pkt, true);
2126 // Remove sound reference
2127 m_playing_sounds.erase(i);
2130 void Server::fadeSound(s32 handle, float step, float gain)
2132 // Get sound reference
2133 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2134 m_playing_sounds.find(handle);
2135 if (i == m_playing_sounds.end())
2138 ServerPlayingSound &psound = i->second;
2139 psound.params.gain = gain;
2141 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2142 pkt << handle << step << gain;
2144 // Backwards compability
2145 bool play_sound = gain > 0;
2146 ServerPlayingSound compat_psound = psound;
2147 compat_psound.clients.clear();
2149 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2150 compat_pkt << handle;
2152 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2153 it != psound.clients.end();) {
2154 if (m_clients.getProtocolVersion(*it) >= 32) {
2156 m_clients.send(*it, 0, &pkt, true);
2159 compat_psound.clients.insert(*it);
2161 m_clients.send(*it, 0, &compat_pkt, true);
2162 psound.clients.erase(it++);
2166 // Remove sound reference
2167 if (!play_sound || psound.clients.size() == 0)
2168 m_playing_sounds.erase(i);
2170 if (play_sound && compat_psound.clients.size() > 0) {
2171 // Play new sound volume on older clients
2172 playSound(compat_psound.spec, compat_psound.params);
2176 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2177 std::vector<u16> *far_players, float far_d_nodes)
2179 float maxd = far_d_nodes*BS;
2180 v3f p_f = intToFloat(p, BS);
2182 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2185 std::vector<u16> clients = m_clients.getClientIDs();
2186 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2189 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2190 PlayerSAO *sao = player->getPlayerSAO();
2194 // If player is far away, only set modified blocks not sent
2195 v3f player_pos = sao->getBasePosition();
2196 if (player_pos.getDistanceFrom(p_f) > maxd) {
2197 far_players->push_back(*i);
2204 m_clients.send(*i, 0, &pkt, true);
2208 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2209 std::vector<u16> *far_players, float far_d_nodes,
2210 bool remove_metadata)
2212 float maxd = far_d_nodes*BS;
2213 v3f p_f = intToFloat(p, BS);
2215 std::vector<u16> clients = m_clients.getClientIDs();
2216 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2219 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2220 PlayerSAO *sao = player->getPlayerSAO();
2224 // If player is far away, only set modified blocks not sent
2225 v3f player_pos = sao->getBasePosition();
2226 if(player_pos.getDistanceFrom(p_f) > maxd) {
2227 far_players->push_back(*i);
2233 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2235 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2237 pkt << p << n.param0 << n.param1 << n.param2
2238 << (u8) (remove_metadata ? 0 : 1);
2243 if (pkt.getSize() > 0)
2244 m_clients.send(*i, 0, &pkt, true);
2248 void Server::setBlockNotSent(v3s16 p)
2250 std::vector<u16> clients = m_clients.getClientIDs();
2252 for(std::vector<u16>::iterator i = clients.begin();
2253 i != clients.end(); ++i) {
2254 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2255 client->SetBlockNotSent(p);
2260 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2262 DSTACK(FUNCTION_NAME);
2264 v3s16 p = block->getPos();
2267 Create a packet with the block in the right format
2270 std::ostringstream os(std::ios_base::binary);
2271 block->serialize(os, ver, false);
2272 block->serializeNetworkSpecific(os);
2273 std::string s = os.str();
2275 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2278 pkt.putRawString(s.c_str(), s.size());
2282 void Server::SendBlocks(float dtime)
2284 DSTACK(FUNCTION_NAME);
2286 MutexAutoLock envlock(m_env_mutex);
2287 //TODO check if one big lock could be faster then multiple small ones
2289 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2291 std::vector<PrioritySortedBlockTransfer> queue;
2293 s32 total_sending = 0;
2296 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2298 std::vector<u16> clients = m_clients.getClientIDs();
2301 for(std::vector<u16>::iterator i = clients.begin();
2302 i != clients.end(); ++i) {
2303 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2308 total_sending += client->SendingCount();
2309 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2315 // Lowest priority number comes first.
2316 // Lowest is most important.
2317 std::sort(queue.begin(), queue.end());
2320 for(u32 i=0; i<queue.size(); i++)
2322 //TODO: Calculate limit dynamically
2323 if(total_sending >= g_settings->getS32
2324 ("max_simultaneous_block_sends_server_total"))
2327 PrioritySortedBlockTransfer q = queue[i];
2329 MapBlock *block = NULL;
2332 block = m_env->getMap().getBlockNoCreate(q.pos);
2334 catch(InvalidPositionException &e)
2339 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2344 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2346 client->SentBlock(q.pos);
2352 void Server::fillMediaCache()
2354 DSTACK(FUNCTION_NAME);
2356 infostream<<"Server: Calculating media file checksums"<<std::endl;
2358 // Collect all media file paths
2359 std::vector<std::string> paths;
2360 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2361 i != m_mods.end(); ++i) {
2362 const ModSpec &mod = *i;
2363 paths.push_back(mod.path + DIR_DELIM + "textures");
2364 paths.push_back(mod.path + DIR_DELIM + "sounds");
2365 paths.push_back(mod.path + DIR_DELIM + "media");
2366 paths.push_back(mod.path + DIR_DELIM + "models");
2368 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2370 // Collect media file information from paths into cache
2371 for(std::vector<std::string>::iterator i = paths.begin();
2372 i != paths.end(); ++i) {
2373 std::string mediapath = *i;
2374 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2375 for (u32 j = 0; j < dirlist.size(); j++) {
2376 if (dirlist[j].dir) // Ignode dirs
2378 std::string filename = dirlist[j].name;
2379 // If name contains illegal characters, ignore the file
2380 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2381 infostream<<"Server: ignoring illegal file name: \""
2382 << filename << "\"" << std::endl;
2385 // If name is not in a supported format, ignore it
2386 const char *supported_ext[] = {
2387 ".png", ".jpg", ".bmp", ".tga",
2388 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2390 ".x", ".b3d", ".md2", ".obj",
2393 if (removeStringEnd(filename, supported_ext) == ""){
2394 infostream << "Server: ignoring unsupported file extension: \""
2395 << filename << "\"" << std::endl;
2398 // Ok, attempt to load the file and add to cache
2399 std::string filepath = mediapath + DIR_DELIM + filename;
2401 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2403 errorstream << "Server::fillMediaCache(): Could not open \""
2404 << filename << "\" for reading" << std::endl;
2407 std::ostringstream tmp_os(std::ios_base::binary);
2411 fis.read(buf, 1024);
2412 std::streamsize len = fis.gcount();
2413 tmp_os.write(buf, len);
2422 errorstream<<"Server::fillMediaCache(): Failed to read \""
2423 << filename << "\"" << std::endl;
2426 if(tmp_os.str().length() == 0) {
2427 errorstream << "Server::fillMediaCache(): Empty file \""
2428 << filepath << "\"" << std::endl;
2433 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2435 unsigned char *digest = sha1.getDigest();
2436 std::string sha1_base64 = base64_encode(digest, 20);
2437 std::string sha1_hex = hex_encode((char*)digest, 20);
2441 m_media[filename] = MediaInfo(filepath, sha1_base64);
2442 verbosestream << "Server: " << sha1_hex << " is " << filename
2448 void Server::sendMediaAnnouncement(u16 peer_id)
2450 DSTACK(FUNCTION_NAME);
2452 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2456 std::ostringstream os(std::ios_base::binary);
2458 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2459 pkt << (u16) m_media.size();
2461 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2462 i != m_media.end(); ++i) {
2463 pkt << i->first << i->second.sha1_digest;
2466 pkt << g_settings->get("remote_media");
2470 struct SendableMedia
2476 SendableMedia(const std::string &name_="", const std::string &path_="",
2477 const std::string &data_=""):
2484 void Server::sendRequestedMedia(u16 peer_id,
2485 const std::vector<std::string> &tosend)
2487 DSTACK(FUNCTION_NAME);
2489 verbosestream<<"Server::sendRequestedMedia(): "
2490 <<"Sending files to client"<<std::endl;
2494 // Put 5kB in one bunch (this is not accurate)
2495 u32 bytes_per_bunch = 5000;
2497 std::vector< std::vector<SendableMedia> > file_bunches;
2498 file_bunches.push_back(std::vector<SendableMedia>());
2500 u32 file_size_bunch_total = 0;
2502 for(std::vector<std::string>::const_iterator i = tosend.begin();
2503 i != tosend.end(); ++i) {
2504 const std::string &name = *i;
2506 if (m_media.find(name) == m_media.end()) {
2507 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2508 <<"unknown file \""<<(name)<<"\""<<std::endl;
2512 //TODO get path + name
2513 std::string tpath = m_media[name].path;
2516 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2517 if(fis.good() == false){
2518 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2519 <<tpath<<"\" for reading"<<std::endl;
2522 std::ostringstream tmp_os(std::ios_base::binary);
2526 fis.read(buf, 1024);
2527 std::streamsize len = fis.gcount();
2528 tmp_os.write(buf, len);
2529 file_size_bunch_total += len;
2538 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2539 <<name<<"\""<<std::endl;
2542 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2543 <<tname<<"\""<<std::endl;*/
2545 file_bunches[file_bunches.size()-1].push_back(
2546 SendableMedia(name, tpath, tmp_os.str()));
2548 // Start next bunch if got enough data
2549 if(file_size_bunch_total >= bytes_per_bunch) {
2550 file_bunches.push_back(std::vector<SendableMedia>());
2551 file_size_bunch_total = 0;
2556 /* Create and send packets */
2558 u16 num_bunches = file_bunches.size();
2559 for(u16 i = 0; i < num_bunches; i++) {
2562 u16 total number of texture bunches
2563 u16 index of this bunch
2564 u32 number of files in this bunch
2573 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2574 pkt << num_bunches << i << (u32) file_bunches[i].size();
2576 for(std::vector<SendableMedia>::iterator
2577 j = file_bunches[i].begin();
2578 j != file_bunches[i].end(); ++j) {
2580 pkt.putLongString(j->data);
2583 verbosestream << "Server::sendRequestedMedia(): bunch "
2584 << i << "/" << num_bunches
2585 << " files=" << file_bunches[i].size()
2586 << " size=" << pkt.getSize() << std::endl;
2591 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2593 if(m_detached_inventories.count(name) == 0) {
2594 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2597 Inventory *inv = m_detached_inventories[name];
2598 std::ostringstream os(std::ios_base::binary);
2600 os << serializeString(name);
2604 std::string s = os.str();
2606 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2607 pkt.putRawString(s.c_str(), s.size());
2609 const std::string &check = m_detached_inventories_player[name];
2610 if (peer_id == PEER_ID_INEXISTENT) {
2612 return m_clients.sendToAll(&pkt);
2613 RemotePlayer *p = m_env->getPlayer(check.c_str());
2615 m_clients.send(p->peer_id, 0, &pkt, true);
2617 if (check == "" || getPlayerName(peer_id) == check)
2622 void Server::sendDetachedInventories(u16 peer_id)
2624 DSTACK(FUNCTION_NAME);
2626 for(std::map<std::string, Inventory*>::iterator
2627 i = m_detached_inventories.begin();
2628 i != m_detached_inventories.end(); ++i) {
2629 const std::string &name = i->first;
2630 //Inventory *inv = i->second;
2631 sendDetachedInventory(name, peer_id);
2639 void Server::DiePlayer(u16 peer_id)
2641 DSTACK(FUNCTION_NAME);
2642 PlayerSAO *playersao = getPlayerSAO(peer_id);
2643 // In some rare cases this can be NULL -- if the player is disconnected
2644 // when a Lua function modifies l_punch, for example
2648 infostream << "Server::DiePlayer(): Player "
2649 << playersao->getPlayer()->getName()
2650 << " dies" << std::endl;
2652 playersao->setHP(0);
2654 // Trigger scripted stuff
2655 m_script->on_dieplayer(playersao);
2657 SendPlayerHP(peer_id);
2658 SendDeathscreen(peer_id, false, v3f(0,0,0));
2661 void Server::RespawnPlayer(u16 peer_id)
2663 DSTACK(FUNCTION_NAME);
2665 PlayerSAO *playersao = getPlayerSAO(peer_id);
2668 infostream << "Server::RespawnPlayer(): Player "
2669 << playersao->getPlayer()->getName()
2670 << " respawns" << std::endl;
2672 playersao->setHP(PLAYER_MAX_HP);
2673 playersao->setBreath(PLAYER_MAX_BREATH);
2675 bool repositioned = m_script->on_respawnplayer(playersao);
2676 if (!repositioned) {
2677 // setPos will send the new position to client
2678 playersao->setPos(findSpawnPos());
2681 SendPlayerHP(peer_id);
2685 void Server::DenySudoAccess(u16 peer_id)
2687 DSTACK(FUNCTION_NAME);
2689 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2694 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2695 const std::string &str_reason, bool reconnect)
2697 if (proto_ver >= 25) {
2698 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2700 std::wstring wreason = utf8_to_wide(
2701 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2702 accessDeniedStrings[(u8)reason]);
2703 SendAccessDenied_Legacy(peer_id, wreason);
2706 m_clients.event(peer_id, CSE_SetDenied);
2707 m_con.DisconnectPeer(peer_id);
2711 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2713 DSTACK(FUNCTION_NAME);
2715 SendAccessDenied(peer_id, reason, custom_reason);
2716 m_clients.event(peer_id, CSE_SetDenied);
2717 m_con.DisconnectPeer(peer_id);
2720 // 13/03/15: remove this function when protocol version 25 will become
2721 // the minimum version for MT users, maybe in 1 year
2722 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2724 DSTACK(FUNCTION_NAME);
2726 SendAccessDenied_Legacy(peer_id, reason);
2727 m_clients.event(peer_id, CSE_SetDenied);
2728 m_con.DisconnectPeer(peer_id);
2731 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2733 DSTACK(FUNCTION_NAME);
2736 RemoteClient* client = getClient(peer_id, CS_Invalid);
2738 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2740 // Right now, the auth mechs don't change between login and sudo mode.
2741 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2742 client->allowed_sudo_mechs = sudo_auth_mechs;
2744 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2745 << g_settings->getFloat("dedicated_server_step")
2749 m_clients.event(peer_id, CSE_AuthAccept);
2751 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2753 // We only support SRP right now
2754 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2756 resp_pkt << sudo_auth_mechs;
2758 m_clients.event(peer_id, CSE_SudoSuccess);
2762 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2764 DSTACK(FUNCTION_NAME);
2765 std::wstring message;
2768 Clear references to playing sounds
2770 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2771 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2772 ServerPlayingSound &psound = i->second;
2773 psound.clients.erase(peer_id);
2774 if (psound.clients.empty())
2775 m_playing_sounds.erase(i++);
2780 RemotePlayer *player = m_env->getPlayer(peer_id);
2782 /* Run scripts and remove from environment */
2783 if (player != NULL) {
2784 PlayerSAO *playersao = player->getPlayerSAO();
2787 // inform connected clients
2788 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2789 // (u16) 1 + std::string represents a vector serialization representation
2790 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2791 m_clients.sendToAll(¬ice);
2793 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2795 playersao->disconnected();
2802 if(player != NULL && reason != CDR_DENY) {
2803 std::ostringstream os(std::ios_base::binary);
2804 std::vector<u16> clients = m_clients.getClientIDs();
2806 for(std::vector<u16>::iterator i = clients.begin();
2807 i != clients.end(); ++i) {
2809 RemotePlayer *player = m_env->getPlayer(*i);
2813 // Get name of player
2814 os << player->getName() << " ";
2817 std::string name = player->getName();
2818 actionstream << name << " "
2819 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2820 << " List of players: " << os.str() << std::endl;
2822 m_admin_chat->outgoing_queue.push_back(
2823 new ChatEventNick(CET_NICK_REMOVE, name));
2827 MutexAutoLock env_lock(m_env_mutex);
2828 m_clients.DeleteClient(peer_id);
2832 // Send leave chat message to all remaining clients
2833 if (!message.empty()) {
2834 SendChatMessage(PEER_ID_INEXISTENT,
2835 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2839 void Server::UpdateCrafting(RemotePlayer *player)
2841 DSTACK(FUNCTION_NAME);
2843 // Get a preview for crafting
2845 InventoryLocation loc;
2846 loc.setPlayer(player->getName());
2847 std::vector<ItemStack> output_replacements;
2848 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2849 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2850 (&player->inventory)->getList("craft"), loc);
2852 // Put the new preview in
2853 InventoryList *plist = player->inventory.getList("craftpreview");
2854 sanity_check(plist);
2855 sanity_check(plist->getSize() >= 1);
2856 plist->changeItem(0, preview);
2859 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2861 if (evt->type == CET_NICK_ADD) {
2862 // The terminal informed us of its nick choice
2863 m_admin_nick = ((ChatEventNick *)evt)->nick;
2864 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2865 errorstream << "You haven't set up an account." << std::endl
2866 << "Please log in using the client as '"
2867 << m_admin_nick << "' with a secure password." << std::endl
2868 << "Until then, you can't execute admin tasks via the console," << std::endl
2869 << "and everybody can claim the user account instead of you," << std::endl
2870 << "giving them full control over this server." << std::endl;
2873 assert(evt->type == CET_CHAT);
2874 handleAdminChat((ChatEventChat *)evt);
2878 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2879 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2881 // If something goes wrong, this player is to blame
2882 RollbackScopeActor rollback_scope(m_rollback,
2883 std::string("player:") + name);
2885 if (g_settings->getBool("strip_color_codes"))
2886 wmessage = unescape_enriched(wmessage);
2889 switch (player->canSendChatMessage()) {
2890 case RPLAYER_CHATRESULT_FLOODING: {
2891 std::wstringstream ws;
2892 ws << L"You cannot send more messages. You are limited to "
2893 << g_settings->getFloat("chat_message_limit_per_10sec")
2894 << L" messages per 10 seconds.";
2897 case RPLAYER_CHATRESULT_KICK:
2898 DenyAccess_Legacy(player->peer_id,
2899 L"You have been kicked due to message flooding.");
2901 case RPLAYER_CHATRESULT_OK:
2904 FATAL_ERROR("Unhandled chat filtering result found.");
2908 if (m_max_chatmessage_length > 0
2909 && wmessage.length() > m_max_chatmessage_length) {
2910 return L"Your message exceed the maximum chat message limit set on the server. "
2911 L"It was refused. Send a shorter message";
2914 // Run script hook, exit if script ate the chat message
2915 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2920 // Whether to send line to the player that sent the message, or to all players
2921 bool broadcast_line = true;
2923 if (check_shout_priv && !checkPriv(name, "shout")) {
2924 line += L"-!- You don't have permission to shout.";
2925 broadcast_line = false;
2934 Tell calling method to send the message to sender
2936 if (!broadcast_line) {
2940 Send the message to others
2942 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2944 std::vector<u16> clients = m_clients.getClientIDs();
2947 Send the message back to the inital sender
2948 if they are using protocol version >= 29
2951 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2952 if (player && player->protocol_version >= 29)
2953 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2955 for (u16 i = 0; i < clients.size(); i++) {
2956 u16 cid = clients[i];
2957 if (cid != peer_id_to_avoid_sending)
2958 SendChatMessage(cid, ChatMessage(line));
2964 void Server::handleAdminChat(const ChatEventChat *evt)
2966 std::string name = evt->nick;
2967 std::wstring wname = utf8_to_wide(name);
2968 std::wstring wmessage = evt->evt_msg;
2970 std::wstring answer = handleChat(name, wname, wmessage);
2972 // If asked to send answer to sender
2973 if (!answer.empty()) {
2974 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2978 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2980 RemoteClient *client = getClientNoEx(peer_id,state_min);
2982 throw ClientNotFoundException("Client not found");
2986 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2988 return m_clients.getClientNoEx(peer_id, state_min);
2991 std::string Server::getPlayerName(u16 peer_id)
2993 RemotePlayer *player = m_env->getPlayer(peer_id);
2995 return "[id="+itos(peer_id)+"]";
2996 return player->getName();
2999 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3001 RemotePlayer *player = m_env->getPlayer(peer_id);
3004 return player->getPlayerSAO();
3007 std::wstring Server::getStatusString()
3009 std::wostringstream os(std::ios_base::binary);
3012 os<<L"version="<<narrow_to_wide(g_version_string);
3014 os<<L", uptime="<<m_uptime.get();
3016 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3017 // Information about clients
3020 std::vector<u16> clients = m_clients.getClientIDs();
3021 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3023 RemotePlayer *player = m_env->getPlayer(*i);
3024 // Get name of player
3025 std::wstring name = L"unknown";
3027 name = narrow_to_wide(player->getName());
3028 // Add name to information string
3036 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3037 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3038 if(g_settings->get("motd") != "")
3039 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3043 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3045 std::set<std::string> privs;
3046 m_script->getAuth(name, NULL, &privs);
3050 bool Server::checkPriv(const std::string &name, const std::string &priv)
3052 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3053 return (privs.count(priv) != 0);
3056 void Server::reportPrivsModified(const std::string &name)
3059 std::vector<u16> clients = m_clients.getClientIDs();
3060 for(std::vector<u16>::iterator i = clients.begin();
3061 i != clients.end(); ++i) {
3062 RemotePlayer *player = m_env->getPlayer(*i);
3063 reportPrivsModified(player->getName());
3066 RemotePlayer *player = m_env->getPlayer(name.c_str());
3069 SendPlayerPrivileges(player->peer_id);
3070 PlayerSAO *sao = player->getPlayerSAO();
3073 sao->updatePrivileges(
3074 getPlayerEffectivePrivs(name),
3079 void Server::reportInventoryFormspecModified(const std::string &name)
3081 RemotePlayer *player = m_env->getPlayer(name.c_str());
3084 SendPlayerInventoryFormspec(player->peer_id);
3087 void Server::setIpBanned(const std::string &ip, const std::string &name)
3089 m_banmanager->add(ip, name);
3092 void Server::unsetIpBanned(const std::string &ip_or_name)
3094 m_banmanager->remove(ip_or_name);
3097 std::string Server::getBanDescription(const std::string &ip_or_name)
3099 return m_banmanager->getBanDescription(ip_or_name);
3102 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3104 // m_env will be NULL if the server is initializing
3108 if (m_admin_nick == name && !m_admin_nick.empty()) {
3109 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3112 RemotePlayer *player = m_env->getPlayer(name);
3117 if (player->peer_id == PEER_ID_INEXISTENT)
3120 SendChatMessage(player->peer_id, ChatMessage(msg));
3123 bool Server::showFormspec(const char *playername, const std::string &formspec,
3124 const std::string &formname)
3126 // m_env will be NULL if the server is initializing
3130 RemotePlayer *player = m_env->getPlayer(playername);
3134 SendShowFormspecMessage(player->peer_id, formspec, formname);
3138 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3143 u32 id = player->addHud(form);
3145 SendHUDAdd(player->peer_id, id, form);
3150 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3154 HudElement* todel = player->removeHud(id);
3161 SendHUDRemove(player->peer_id, id);
3165 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3170 SendHUDChange(player->peer_id, id, stat, data);
3174 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3179 SendHUDSetFlags(player->peer_id, flags, mask);
3180 player->hud_flags &= ~mask;
3181 player->hud_flags |= flags;
3183 PlayerSAO* playersao = player->getPlayerSAO();
3185 if (playersao == NULL)
3188 m_script->player_event(playersao, "hud_changed");
3192 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3197 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3200 player->setHotbarItemcount(hotbar_itemcount);
3201 std::ostringstream os(std::ios::binary);
3202 writeS32(os, hotbar_itemcount);
3203 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3207 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3212 player->setHotbarImage(name);
3213 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3216 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3220 return player->getHotbarImage();
3223 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3228 player->setHotbarSelectedImage(name);
3229 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3232 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3233 v2s32 animation_frames[4], f32 frame_speed)
3238 player->setLocalAnimations(animation_frames, frame_speed);
3239 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3243 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3248 player->eye_offset_first = first;
3249 player->eye_offset_third = third;
3250 SendEyeOffset(player->peer_id, first, third);
3254 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3255 const std::string &type, const std::vector<std::string> ¶ms,
3261 player->setSky(bgcolor, type, params, clouds);
3262 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3266 bool Server::setClouds(RemotePlayer *player, float density,
3267 const video::SColor &color_bright,
3268 const video::SColor &color_ambient,
3276 SendCloudParams(player->peer_id, density,
3277 color_bright, color_ambient, height,
3282 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3288 player->overrideDayNightRatio(do_override, ratio);
3289 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3293 void Server::notifyPlayers(const std::wstring &msg)
3295 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3298 void Server::spawnParticle(const std::string &playername, v3f pos,
3299 v3f velocity, v3f acceleration,
3300 float expirationtime, float size, bool
3301 collisiondetection, bool collision_removal,
3302 bool vertical, const std::string &texture,
3303 const struct TileAnimationParams &animation, u8 glow)
3305 // m_env will be NULL if the server is initializing
3309 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3310 if (playername != "") {
3311 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3314 peer_id = player->peer_id;
3315 proto_ver = player->protocol_version;
3318 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3319 expirationtime, size, collisiondetection,
3320 collision_removal, vertical, texture, animation, glow);
3323 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3324 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3325 float minexptime, float maxexptime, float minsize, float maxsize,
3326 bool collisiondetection, bool collision_removal,
3327 ServerActiveObject *attached, bool vertical, const std::string &texture,
3328 const std::string &playername, const struct TileAnimationParams &animation,
3331 // m_env will be NULL if the server is initializing
3335 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3336 if (playername != "") {
3337 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3340 peer_id = player->peer_id;
3341 proto_ver = player->protocol_version;
3344 u16 attached_id = attached ? attached->getId() : 0;
3347 if (attached_id == 0)
3348 id = m_env->addParticleSpawner(spawntime);
3350 id = m_env->addParticleSpawner(spawntime, attached_id);
3352 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3353 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3354 minexptime, maxexptime, minsize, maxsize,
3355 collisiondetection, collision_removal, attached_id, vertical,
3356 texture, id, animation, glow);
3361 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3363 // m_env will be NULL if the server is initializing
3365 throw ServerError("Can't delete particle spawners during initialisation!");
3367 u16 peer_id = PEER_ID_INEXISTENT;
3368 if (playername != "") {
3369 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3372 peer_id = player->peer_id;
3375 m_env->deleteParticleSpawner(id);
3376 SendDeleteParticleSpawner(peer_id, id);
3379 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3381 if(m_detached_inventories.count(name) > 0){
3382 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3383 delete m_detached_inventories[name];
3385 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3387 Inventory *inv = new Inventory(m_itemdef);
3389 m_detached_inventories[name] = inv;
3390 m_detached_inventories_player[name] = player;
3391 //TODO find a better way to do this
3392 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3396 // actions: time-reversed list
3397 // Return value: success/failure
3398 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3399 std::list<std::string> *log)
3401 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3402 ServerMap *map = (ServerMap*)(&m_env->getMap());
3404 // Fail if no actions to handle
3405 if(actions.empty()){
3406 log->push_back("Nothing to do.");
3413 for(std::list<RollbackAction>::const_iterator
3414 i = actions.begin();
3415 i != actions.end(); ++i)
3417 const RollbackAction &action = *i;
3419 bool success = action.applyRevert(map, this, this);
3422 std::ostringstream os;
3423 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3424 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3426 log->push_back(os.str());
3428 std::ostringstream os;
3429 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3430 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3432 log->push_back(os.str());
3436 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3437 <<" failed"<<std::endl;
3439 // Call it done if less than half failed
3440 return num_failed <= num_tried/2;
3443 // IGameDef interface
3445 IItemDefManager *Server::getItemDefManager()
3450 INodeDefManager *Server::getNodeDefManager()
3455 ICraftDefManager *Server::getCraftDefManager()
3460 u16 Server::allocateUnknownNodeId(const std::string &name)
3462 return m_nodedef->allocateDummy(name);
3465 MtEventManager *Server::getEventManager()
3470 IWritableItemDefManager *Server::getWritableItemDefManager()
3475 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3480 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3485 const ModSpec *Server::getModSpec(const std::string &modname) const
3487 std::vector<ModSpec>::const_iterator it;
3488 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3489 const ModSpec &mod = *it;
3490 if (mod.name == modname)
3496 void Server::getModNames(std::vector<std::string> &modlist)
3498 std::vector<ModSpec>::iterator it;
3499 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3500 modlist.push_back(it->name);
3503 std::string Server::getBuiltinLuaPath()
3505 return porting::path_share + DIR_DELIM + "builtin";
3508 std::string Server::getModStoragePath() const
3510 return m_path_world + DIR_DELIM + "mod_storage";
3513 v3f Server::findSpawnPos()
3515 ServerMap &map = m_env->getServerMap();
3517 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3518 return nodeposf * BS;
3521 bool is_good = false;
3522 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3523 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3525 // Try to find a good place a few times
3526 for(s32 i = 0; i < 4000 && !is_good; i++) {
3527 s32 range = MYMIN(1 + i, range_max);
3528 // We're going to try to throw the player to this position
3529 v2s16 nodepos2d = v2s16(
3530 -range + (myrand() % (range * 2)),
3531 -range + (myrand() % (range * 2)));
3533 // Get spawn level at point
3534 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3535 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3536 // the mapgen to signify an unsuitable spawn position
3537 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3540 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3543 for (s32 i = 0; i < 10; i++) {
3544 v3s16 blockpos = getNodeBlockPos(nodepos);
3545 map.emergeBlock(blockpos, true);
3546 content_t c = map.getNodeNoEx(nodepos).getContent();
3547 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3549 if (air_count >= 2) {
3550 nodeposf = intToFloat(nodepos, BS);
3551 // Don't spawn the player outside map boundaries
3552 if (objectpos_over_limit(nodeposf))
3565 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3567 m_shutdown_timer = delay;
3568 m_shutdown_msg = msg;
3569 m_shutdown_ask_reconnect = reconnect;
3571 if (delay == 0.0f) {
3572 // No delay, shutdown immediately
3573 m_shutdown_requested = true;
3574 // only print to the infostream, a chat message saying
3575 // "Server Shutting Down" is sent when the server destructs.
3576 infostream << "*** Immediate Server shutdown requested." << std::endl;
3577 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3578 // Negative delay, cancel shutdown if requested
3579 m_shutdown_timer = 0.0f;
3580 m_shutdown_msg = "";
3581 m_shutdown_ask_reconnect = false;
3582 m_shutdown_requested = false;
3583 std::wstringstream ws;
3585 ws << L"*** Server shutdown canceled.";
3587 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3588 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3589 } else if (delay > 0.0f) {
3590 // Positive delay, tell the clients when the server will shut down
3591 std::wstringstream ws;
3593 ws << L"*** Server shutting down in "
3594 << duration_to_string(myround(m_shutdown_timer)).c_str()
3597 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3598 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3602 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3605 Try to get an existing player
3607 RemotePlayer *player = m_env->getPlayer(name);
3609 // If player is already connected, cancel
3610 if (player != NULL && player->peer_id != 0) {
3611 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3616 If player with the wanted peer_id already exists, cancel.
3618 if (m_env->getPlayer(peer_id) != NULL) {
3619 infostream<<"emergePlayer(): Player with wrong name but same"
3620 " peer_id already exists"<<std::endl;
3625 player = new RemotePlayer(name, idef());
3628 bool newplayer = false;
3631 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3633 // Complete init with server parts
3634 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3635 player->protocol_version = proto_version;
3639 m_script->on_newplayer(playersao);
3645 bool Server::registerModStorage(ModMetadata *storage)
3647 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3648 errorstream << "Unable to register same mod storage twice. Storage name: "
3649 << storage->getModName() << std::endl;
3653 m_mod_storages[storage->getModName()] = storage;
3657 void Server::unregisterModStorage(const std::string &name)
3659 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3660 if (it != m_mod_storages.end()) {
3661 // Save unconditionaly on unregistration
3662 it->second->save(getModStoragePath());
3663 m_mod_storages.erase(name);
3667 void dedicated_server_loop(Server &server, bool &kill)
3669 DSTACK(FUNCTION_NAME);
3671 verbosestream<<"dedicated_server_loop()"<<std::endl;
3673 IntervalLimiter m_profiler_interval;
3675 static thread_local const float steplen =
3676 g_settings->getFloat("dedicated_server_step");
3677 static thread_local const float profiler_print_interval =
3678 g_settings->getFloat("profiler_print_interval");
3681 // This is kind of a hack but can be done like this
3682 // because server.step() is very light
3684 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3685 sleep_ms((int)(steplen*1000.0));
3687 server.step(steplen);
3689 if (server.getShutdownRequested() || kill)
3695 if (profiler_print_interval != 0) {
3696 if(m_profiler_interval.step(steplen, profiler_print_interval))
3698 infostream<<"Profiler:"<<std::endl;
3699 g_profiler->print(infostream);
3700 g_profiler->clear();
3705 infostream << "Dedicated server quitting" << std::endl;
3707 if (g_settings->getBool("server_announce"))
3708 ServerList::sendAnnounce(ServerList::AA_DELETE,
3709 server.m_bind_addr.getPort());