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_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "event_manager.h"
54 #include "serverlist.h"
55 #include "util/string.h"
56 #include "util/mathconstants.h"
58 #include "util/serialize.h"
59 #include "util/thread.h"
60 #include "defaultsettings.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
65 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("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,
153 m_path_world(path_world),
154 m_gamespec(gamespec),
155 m_simple_singleplayer_mode(simple_singleplayer_mode),
156 m_async_fatal_error(""),
165 m_enable_rollback_recording(false),
168 m_itemdef(createItemDefManager()),
169 m_nodedef(createNodeDefManager()),
170 m_craftdef(createCraftDefManager()),
171 m_event(new EventManager()),
173 m_time_of_day_send_timer(0),
176 m_shutdown_requested(false),
177 m_shutdown_ask_reconnect(false),
179 m_ignore_map_edit_events(false),
180 m_ignore_map_edit_events_peer_id(0),
184 m_liquid_transform_timer = 0.0;
185 m_liquid_transform_every = 1.0;
186 m_masterserver_timer = 0.0;
187 m_emergethread_trigger_timer = 0.0;
188 m_savemap_timer = 0.0;
191 m_lag = g_settings->getFloat("dedicated_server_step");
194 throw ServerError("Supplied empty world path");
196 if(!gamespec.isValid())
197 throw ServerError("Supplied invalid gamespec");
199 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
200 if(m_simple_singleplayer_mode)
201 infostream<<" in simple singleplayer mode"<<std::endl;
203 infostream<<std::endl;
204 infostream<<"- world: "<<m_path_world<<std::endl;
205 infostream<<"- game: "<<m_gamespec.path<<std::endl;
207 // Create world if it doesn't exist
208 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
209 throw ServerError("Failed to initialize world");
211 // Create server thread
212 m_thread = new ServerThread(this);
214 // Create emerge manager
215 m_emerge = new EmergeManager(this);
217 // Create ban manager
218 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
219 m_banmanager = new BanManager(ban_path);
221 ModConfiguration modconf(m_path_world);
222 m_mods = modconf.getMods();
223 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
224 // complain about mods with unsatisfied dependencies
225 if(!modconf.isConsistent()) {
226 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
227 it != unsatisfied_mods.end(); ++it) {
229 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
230 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
231 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
232 errorstream << " \"" << *dep_it << "\"";
233 errorstream << std::endl;
237 Settings worldmt_settings;
238 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
239 worldmt_settings.readConfigFile(worldmt.c_str());
240 std::vector<std::string> names = worldmt_settings.getNames();
241 std::set<std::string> load_mod_names;
242 for(std::vector<std::string>::iterator it = names.begin();
243 it != names.end(); ++it) {
244 std::string name = *it;
245 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
246 load_mod_names.insert(name.substr(9));
248 // complain about mods declared to be loaded, but not found
249 for(std::vector<ModSpec>::iterator it = m_mods.begin();
250 it != m_mods.end(); ++it)
251 load_mod_names.erase((*it).name);
252 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
253 it != unsatisfied_mods.end(); ++it)
254 load_mod_names.erase((*it).name);
255 if(!load_mod_names.empty()) {
256 errorstream << "The following mods could not be found:";
257 for(std::set<std::string>::iterator it = load_mod_names.begin();
258 it != load_mod_names.end(); ++it)
259 errorstream << " \"" << (*it) << "\"";
260 errorstream << std::endl;
264 MutexAutoLock envlock(m_env_mutex);
266 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
267 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
269 // Initialize scripting
270 infostream<<"Server: Initializing Lua"<<std::endl;
272 m_script = new GameScripting(this);
274 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
276 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
279 infostream << "Server: Loading mods: ";
280 for(std::vector<ModSpec>::iterator i = m_mods.begin();
281 i != m_mods.end(); ++i) {
282 const ModSpec &mod = *i;
283 infostream << mod.name << " ";
285 infostream << std::endl;
286 // Load and run "mod" scripts
287 for (std::vector<ModSpec>::iterator it = m_mods.begin();
288 it != m_mods.end(); ++it) {
289 const ModSpec &mod = *it;
290 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
291 throw ModError("Error loading mod \"" + mod.name +
292 "\": Mod name does not follow naming conventions: "
293 "Only chararacters [a-z0-9_] are allowed.");
295 std::string script_path = mod.path + DIR_DELIM + "init.lua";
296 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
297 << script_path << "\"]" << std::endl;
298 m_script->loadMod(script_path, mod.name);
301 // Read Textures and calculate sha1 sums
304 // Apply item aliases in the node definition manager
305 m_nodedef->updateAliases(m_itemdef);
307 // Apply texture overrides from texturepack/override.txt
308 std::string texture_path = g_settings->get("texture_path");
309 if (texture_path != "" && fs::IsDir(texture_path))
310 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
312 m_nodedef->setNodeRegistrationStatus(true);
314 // Perform pending node name resolutions
315 m_nodedef->runNodeResolveCallbacks();
317 // unmap node names for connected nodeboxes
318 m_nodedef->mapNodeboxConnections();
320 // init the recipe hashes to speed up crafting
321 m_craftdef->initHashes(this);
323 // Initialize Environment
324 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
326 m_clients.setEnv(m_env);
328 if (!servermap->settings_mgr.makeMapgenParams())
329 FATAL_ERROR("Couldn't create any mapgen type");
331 // Initialize mapgens
332 m_emerge->initMapgens(servermap->getMapgenParams());
334 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
335 if (m_enable_rollback_recording) {
336 // Create rollback manager
337 m_rollback = new RollbackManager(m_path_world, this);
340 // Give environment reference to scripting api
341 m_script->initializeEnvironment(m_env);
343 // Register us to receive map edit events
344 servermap->addEventReceiver(this);
346 // If file exists, load environment metadata
347 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
348 infostream << "Server: Loading environment metadata" << std::endl;
351 m_env->loadDefaultMeta();
354 // Add some test ActiveBlockModifiers to environment
355 add_legacy_abms(m_env, m_nodedef);
357 m_liquid_transform_every = g_settings->getFloat("liquid_update");
358 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
363 infostream<<"Server destructing"<<std::endl;
365 // Send shutdown message
366 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
369 MutexAutoLock envlock(m_env_mutex);
371 // Execute script shutdown hooks
372 m_script->on_shutdown();
374 infostream << "Server: Saving players" << std::endl;
375 m_env->saveLoadedPlayers();
377 infostream << "Server: Kicking players" << std::endl;
378 std::string kick_msg;
379 bool reconnect = false;
380 if (getShutdownRequested()) {
381 reconnect = m_shutdown_ask_reconnect;
382 kick_msg = m_shutdown_msg;
384 if (kick_msg == "") {
385 kick_msg = g_settings->get("kick_msg_shutdown");
387 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
388 kick_msg, reconnect);
390 infostream << "Server: Saving environment metadata" << std::endl;
398 // stop all emerge threads before deleting players that may have
399 // requested blocks to be emerged
400 m_emerge->stopThreads();
402 // Delete things in the reverse order of creation
412 // Deinitialize scripting
413 infostream<<"Server: Deinitializing scripting"<<std::endl;
416 // Delete detached inventories
417 for (std::map<std::string, Inventory*>::iterator
418 i = m_detached_inventories.begin();
419 i != m_detached_inventories.end(); ++i) {
424 void Server::start(Address bind_addr)
426 DSTACK(FUNCTION_NAME);
428 m_bind_addr = bind_addr;
430 infostream<<"Starting server on "
431 << bind_addr.serializeString() <<"..."<<std::endl;
433 // Stop thread if already running
436 // Initialize connection
437 m_con.SetTimeoutMs(30);
438 m_con.Serve(bind_addr);
443 // ASCII art for the win!
445 <<" .__ __ __ "<<std::endl
446 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
447 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
448 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
449 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
450 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
451 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
452 actionstream<<"Server for gameid=\""<<m_gamespec.id
453 <<"\" listening on "<<bind_addr.serializeString()<<":"
454 <<bind_addr.getPort() << "."<<std::endl;
459 DSTACK(FUNCTION_NAME);
461 infostream<<"Server: Stopping and waiting threads"<<std::endl;
463 // Stop threads (set run=false first so both start stopping)
465 //m_emergethread.setRun(false);
467 //m_emergethread.stop();
469 infostream<<"Server: Threads stopped"<<std::endl;
472 void Server::step(float dtime)
474 DSTACK(FUNCTION_NAME);
479 MutexAutoLock lock(m_step_dtime_mutex);
480 m_step_dtime += dtime;
482 // Throw if fatal error occurred in thread
483 std::string async_err = m_async_fatal_error.get();
484 if (!async_err.empty()) {
485 if (!m_simple_singleplayer_mode) {
486 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
487 g_settings->get("kick_msg_crash"),
488 g_settings->getBool("ask_reconnect_on_crash"));
490 throw ServerError(async_err);
494 void Server::AsyncRunStep(bool initial_step)
496 DSTACK(FUNCTION_NAME);
498 g_profiler->add("Server::AsyncRunStep (num)", 1);
502 MutexAutoLock lock1(m_step_dtime_mutex);
503 dtime = m_step_dtime;
507 // Send blocks to clients
511 if((dtime < 0.001) && (initial_step == false))
514 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
516 //infostream<<"Server steps "<<dtime<<std::endl;
517 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
520 MutexAutoLock lock1(m_step_dtime_mutex);
521 m_step_dtime -= dtime;
528 m_uptime.set(m_uptime.get() + dtime);
534 Update time of day and overall game time
536 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
539 Send to clients at constant intervals
542 m_time_of_day_send_timer -= dtime;
543 if(m_time_of_day_send_timer < 0.0) {
544 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
545 u16 time = m_env->getTimeOfDay();
546 float time_speed = g_settings->getFloat("time_speed");
547 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
551 MutexAutoLock lock(m_env_mutex);
552 // Figure out and report maximum lag to environment
553 float max_lag = m_env->getMaxLagEstimate();
554 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
556 if(dtime > 0.1 && dtime > max_lag * 2.0)
557 infostream<<"Server: Maximum lag peaked to "<<dtime
561 m_env->reportMaxLagEstimate(max_lag);
563 ScopeProfiler sp(g_profiler, "SEnv step");
564 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
568 static const float map_timer_and_unload_dtime = 2.92;
569 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
571 MutexAutoLock lock(m_env_mutex);
572 // Run Map's timers and unload unused data
573 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
574 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
575 g_settings->getFloat("server_unload_unused_data_timeout"),
580 Listen to the admin chat, if available
583 if (!m_admin_chat->command_queue.empty()) {
584 MutexAutoLock lock(m_env_mutex);
585 while (!m_admin_chat->command_queue.empty()) {
586 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
587 handleChatInterfaceEvent(evt);
591 m_admin_chat->outgoing_queue.push_back(
592 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
599 /* Transform liquids */
600 m_liquid_transform_timer += dtime;
601 if(m_liquid_transform_timer >= m_liquid_transform_every)
603 m_liquid_transform_timer -= m_liquid_transform_every;
605 MutexAutoLock lock(m_env_mutex);
607 ScopeProfiler sp(g_profiler, "Server: liquid transform");
609 std::map<v3s16, MapBlock*> modified_blocks;
610 m_env->getMap().transformLiquids(modified_blocks);
615 core::map<v3s16, MapBlock*> lighting_modified_blocks;
616 ServerMap &map = ((ServerMap&)m_env->getMap());
617 map.updateLighting(modified_blocks, lighting_modified_blocks);
619 // Add blocks modified by lighting to modified_blocks
620 for(core::map<v3s16, MapBlock*>::Iterator
621 i = lighting_modified_blocks.getIterator();
622 i.atEnd() == false; i++)
624 MapBlock *block = i.getNode()->getValue();
625 modified_blocks.insert(block->getPos(), block);
629 Set the modified blocks unsent for all the clients
631 if(!modified_blocks.empty())
633 SetBlocksNotSent(modified_blocks);
636 m_clients.step(dtime);
638 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
640 // send masterserver announce
642 float &counter = m_masterserver_timer;
643 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
644 g_settings->getBool("server_announce"))
646 ServerList::sendAnnounce(counter ? "update" : "start",
647 m_bind_addr.getPort(),
648 m_clients.getPlayerNames(),
650 m_env->getGameTime(),
653 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
662 Check added and deleted active objects
665 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
666 MutexAutoLock envlock(m_env_mutex);
669 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
670 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
672 // Radius inside which objects are active
673 static const s16 radius =
674 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
676 // Radius inside which players are active
677 static const bool is_transfer_limited =
678 g_settings->exists("unlimited_player_transfer_distance") &&
679 !g_settings->getBool("unlimited_player_transfer_distance");
680 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
681 s16 player_radius = player_transfer_dist;
682 if (player_radius == 0 && is_transfer_limited)
683 player_radius = radius;
685 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
686 i != clients.end(); ++i) {
687 RemoteClient *client = i->second;
689 // If definitions and textures have not been sent, don't
690 // send objects either
691 if (client->getState() < CS_DefinitionsSent)
694 RemotePlayer *player = m_env->getPlayer(client->peer_id);
695 if (player == NULL) {
696 // This can happen if the client timeouts somehow
697 /*warningstream<<FUNCTION_NAME<<": Client "
699 <<" has no associated player"<<std::endl;*/
703 PlayerSAO *playersao = player->getPlayerSAO();
704 if (playersao == NULL)
707 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
708 if (my_radius <= 0) my_radius = radius;
709 //infostream << "Server: Active Radius " << my_radius << std::endl;
711 std::queue<u16> removed_objects;
712 std::queue<u16> added_objects;
713 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
714 client->m_known_objects, removed_objects);
715 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
716 client->m_known_objects, added_objects);
718 // Ignore if nothing happened
719 if (removed_objects.empty() && added_objects.empty()) {
723 std::string data_buffer;
727 // Handle removed objects
728 writeU16((u8*)buf, removed_objects.size());
729 data_buffer.append(buf, 2);
730 while (!removed_objects.empty()) {
732 u16 id = removed_objects.front();
733 ServerActiveObject* obj = m_env->getActiveObject(id);
735 // Add to data buffer for sending
736 writeU16((u8*)buf, id);
737 data_buffer.append(buf, 2);
739 // Remove from known objects
740 client->m_known_objects.erase(id);
742 if(obj && obj->m_known_by_count > 0)
743 obj->m_known_by_count--;
744 removed_objects.pop();
747 // Handle added objects
748 writeU16((u8*)buf, added_objects.size());
749 data_buffer.append(buf, 2);
750 while (!added_objects.empty()) {
752 u16 id = added_objects.front();
753 ServerActiveObject* obj = m_env->getActiveObject(id);
756 u8 type = ACTIVEOBJECT_TYPE_INVALID;
758 warningstream<<FUNCTION_NAME
759 <<": NULL object"<<std::endl;
761 type = obj->getSendType();
763 // Add to data buffer for sending
764 writeU16((u8*)buf, id);
765 data_buffer.append(buf, 2);
766 writeU8((u8*)buf, type);
767 data_buffer.append(buf, 1);
770 data_buffer.append(serializeLongString(
771 obj->getClientInitializationData(client->net_proto_version)));
773 data_buffer.append(serializeLongString(""));
775 // Add to known objects
776 client->m_known_objects.insert(id);
779 obj->m_known_by_count++;
784 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
785 verbosestream << "Server: Sent object remove/add: "
786 << removed_objects.size() << " removed, "
787 << added_objects.size() << " added, "
788 << "packet size is " << pktSize << std::endl;
797 MutexAutoLock envlock(m_env_mutex);
798 ScopeProfiler sp(g_profiler, "Server: sending object messages");
801 // Value = data sent by object
802 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
804 // Get active object messages from environment
806 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
810 std::vector<ActiveObjectMessage>* message_list = NULL;
811 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
812 n = buffered_messages.find(aom.id);
813 if (n == buffered_messages.end()) {
814 message_list = new std::vector<ActiveObjectMessage>;
815 buffered_messages[aom.id] = message_list;
818 message_list = n->second;
820 message_list->push_back(aom);
824 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
825 // Route data to every client
826 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
827 i != clients.end(); ++i) {
828 RemoteClient *client = i->second;
829 std::string reliable_data;
830 std::string unreliable_data;
831 // Go through all objects in message buffer
832 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
833 j = buffered_messages.begin();
834 j != buffered_messages.end(); ++j) {
835 // If object is not known by client, skip it
837 if (client->m_known_objects.find(id) == client->m_known_objects.end())
840 // Get message list of object
841 std::vector<ActiveObjectMessage>* list = j->second;
842 // Go through every message
843 for (std::vector<ActiveObjectMessage>::iterator
844 k = list->begin(); k != list->end(); ++k) {
845 // Compose the full new data with header
846 ActiveObjectMessage aom = *k;
847 std::string new_data;
850 writeU16((u8*)&buf[0], aom.id);
851 new_data.append(buf, 2);
853 new_data += serializeString(aom.datastring);
854 // Add data to buffer
856 reliable_data += new_data;
858 unreliable_data += new_data;
862 reliable_data and unreliable_data are now ready.
865 if(reliable_data.size() > 0) {
866 SendActiveObjectMessages(client->peer_id, reliable_data);
869 if(unreliable_data.size() > 0) {
870 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
875 // Clear buffered_messages
876 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
877 i = buffered_messages.begin();
878 i != buffered_messages.end(); ++i) {
884 Send queued-for-sending map edit events.
887 // We will be accessing the environment
888 MutexAutoLock lock(m_env_mutex);
890 // Don't send too many at a time
893 // Single change sending is disabled if queue size is not small
894 bool disable_single_change_sending = false;
895 if(m_unsent_map_edit_queue.size() >= 4)
896 disable_single_change_sending = true;
898 int event_count = m_unsent_map_edit_queue.size();
900 // We'll log the amount of each
903 while(m_unsent_map_edit_queue.size() != 0)
905 MapEditEvent* event = m_unsent_map_edit_queue.front();
906 m_unsent_map_edit_queue.pop();
908 // Players far away from the change are stored here.
909 // Instead of sending the changes, MapBlocks are set not sent
911 std::vector<u16> far_players;
913 switch (event->type) {
916 prof.add("MEET_ADDNODE", 1);
917 sendAddNode(event->p, event->n, event->already_known_by_peer,
918 &far_players, disable_single_change_sending ? 5 : 30,
919 event->type == MEET_ADDNODE);
921 case MEET_REMOVENODE:
922 prof.add("MEET_REMOVENODE", 1);
923 sendRemoveNode(event->p, event->already_known_by_peer,
924 &far_players, disable_single_change_sending ? 5 : 30);
926 case MEET_BLOCK_NODE_METADATA_CHANGED:
927 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
928 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
929 setBlockNotSent(event->p);
932 infostream << "Server: MEET_OTHER" << std::endl;
933 prof.add("MEET_OTHER", 1);
934 for(std::set<v3s16>::iterator
935 i = event->modified_blocks.begin();
936 i != event->modified_blocks.end(); ++i) {
941 prof.add("unknown", 1);
942 warningstream << "Server: Unknown MapEditEvent "
943 << ((u32)event->type) << std::endl;
948 Set blocks not sent to far players
950 if(!far_players.empty()) {
951 // Convert list format to that wanted by SetBlocksNotSent
952 std::map<v3s16, MapBlock*> modified_blocks2;
953 for(std::set<v3s16>::iterator
954 i = event->modified_blocks.begin();
955 i != event->modified_blocks.end(); ++i) {
956 modified_blocks2[*i] =
957 m_env->getMap().getBlockNoCreateNoEx(*i);
960 // Set blocks not sent
961 for(std::vector<u16>::iterator
962 i = far_players.begin();
963 i != far_players.end(); ++i) {
964 if(RemoteClient *client = getClient(*i))
965 client->SetBlocksNotSent(modified_blocks2);
971 /*// Don't send too many at a time
973 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
977 if(event_count >= 5){
978 infostream<<"Server: MapEditEvents:"<<std::endl;
979 prof.print(infostream);
980 } else if(event_count != 0){
981 verbosestream<<"Server: MapEditEvents:"<<std::endl;
982 prof.print(verbosestream);
988 Trigger emergethread (it somehow gets to a non-triggered but
989 bysy state sometimes)
992 float &counter = m_emergethread_trigger_timer;
994 if (counter >= 2.0) {
997 m_emerge->startThreads();
1001 // Save map, players and auth stuff
1003 float &counter = m_savemap_timer;
1005 static const float save_interval =
1006 g_settings->getFloat("server_map_save_interval");
1007 if (counter >= save_interval) {
1009 MutexAutoLock lock(m_env_mutex);
1011 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1014 if (m_banmanager->isModified()) {
1015 m_banmanager->save();
1018 // Save changed parts of map
1019 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1022 m_env->saveLoadedPlayers();
1024 // Save environment metadata
1030 void Server::Receive()
1032 DSTACK(FUNCTION_NAME);
1033 SharedBuffer<u8> data;
1037 m_con.Receive(&pkt);
1038 peer_id = pkt.getPeerId();
1041 catch(con::InvalidIncomingDataException &e) {
1042 infostream<<"Server::Receive(): "
1043 "InvalidIncomingDataException: what()="
1044 <<e.what()<<std::endl;
1046 catch(SerializationError &e) {
1047 infostream<<"Server::Receive(): "
1048 "SerializationError: what()="
1049 <<e.what()<<std::endl;
1051 catch(ClientStateError &e) {
1052 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1053 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1054 L"Try reconnecting or updating your client");
1056 catch(con::PeerNotFoundException &e) {
1061 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1063 std::string playername = "";
1064 PlayerSAO *playersao = NULL;
1067 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1068 if (client != NULL) {
1069 playername = client->getName();
1070 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1072 } catch (std::exception &e) {
1078 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1080 // If failed, cancel
1081 if ((playersao == NULL) || (player == NULL)) {
1082 if (player && player->peer_id != 0) {
1083 actionstream << "Server: Failed to emerge player \"" << playername
1084 << "\" (player allocated to an another client)" << std::endl;
1085 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1086 L"name. If your client closed unexpectedly, try again in "
1089 errorstream << "Server: " << playername << ": Failed to emerge player"
1091 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1097 Send complete position information
1099 SendMovePlayer(peer_id);
1102 SendPlayerPrivileges(peer_id);
1104 // Send inventory formspec
1105 SendPlayerInventoryFormspec(peer_id);
1108 SendInventory(playersao);
1111 SendPlayerHPOrDie(playersao);
1114 SendPlayerBreath(playersao);
1116 // Show death screen if necessary
1117 if (playersao->isDead())
1118 SendDeathscreen(peer_id, false, v3f(0,0,0));
1120 // Note things in chat if not in simple singleplayer mode
1121 if(!m_simple_singleplayer_mode) {
1122 // Send information about server to player in chat
1123 SendChatMessage(peer_id, getStatusString());
1125 Address addr = getPeerAddress(player->peer_id);
1126 std::string ip_str = addr.serializeString();
1127 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1132 const std::vector<std::string> &names = m_clients.getPlayerNames();
1134 actionstream << player->getName() << " joins game. List of players: ";
1136 for (std::vector<std::string>::const_iterator i = names.begin();
1137 i != names.end(); ++i) {
1138 actionstream << *i << " ";
1141 actionstream << player->getName() <<std::endl;
1146 inline void Server::handleCommand(NetworkPacket* pkt)
1148 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1149 (this->*opHandle.handler)(pkt);
1152 void Server::ProcessData(NetworkPacket *pkt)
1154 DSTACK(FUNCTION_NAME);
1155 // Environment is locked first.
1156 MutexAutoLock envlock(m_env_mutex);
1158 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1159 u32 peer_id = pkt->getPeerId();
1162 Address address = getPeerAddress(peer_id);
1163 std::string addr_s = address.serializeString();
1165 if(m_banmanager->isIpBanned(addr_s)) {
1166 std::string ban_name = m_banmanager->getBanName(addr_s);
1167 infostream << "Server: A banned client tried to connect from "
1168 << addr_s << "; banned name was "
1169 << ban_name << std::endl;
1170 // This actually doesn't seem to transfer to the client
1171 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1172 + utf8_to_wide(ban_name));
1176 catch(con::PeerNotFoundException &e) {
1178 * no peer for this packet found
1179 * most common reason is peer timeout, e.g. peer didn't
1180 * respond for some time, your server was overloaded or
1183 infostream << "Server::ProcessData(): Canceling: peer "
1184 << peer_id << " not found" << std::endl;
1189 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1191 // Command must be handled into ToServerCommandHandler
1192 if (command >= TOSERVER_NUM_MSG_TYPES) {
1193 infostream << "Server: Ignoring unknown command "
1194 << command << std::endl;
1198 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1203 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1205 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1206 errorstream << "Server::ProcessData(): Cancelling: Peer"
1207 " serialization format invalid or not initialized."
1208 " Skipping incoming command=" << command << std::endl;
1212 /* Handle commands related to client startup */
1213 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1218 if (m_clients.getClientState(peer_id) < CS_Active) {
1219 if (command == TOSERVER_PLAYERPOS) return;
1221 errorstream << "Got packet command: " << command << " for peer id "
1222 << peer_id << " but client isn't active yet. Dropping packet "
1228 } catch (SendFailedException &e) {
1229 errorstream << "Server::ProcessData(): SendFailedException: "
1230 << "what=" << e.what()
1232 } catch (PacketError &e) {
1233 actionstream << "Server::ProcessData(): PacketError: "
1234 << "what=" << e.what()
1239 void Server::setTimeOfDay(u32 time)
1241 m_env->setTimeOfDay(time);
1242 m_time_of_day_send_timer = 0;
1245 void Server::onMapEditEvent(MapEditEvent *event)
1247 if(m_ignore_map_edit_events)
1249 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1251 MapEditEvent *e = event->clone();
1252 m_unsent_map_edit_queue.push(e);
1255 Inventory* Server::getInventory(const InventoryLocation &loc)
1258 case InventoryLocation::UNDEFINED:
1259 case InventoryLocation::CURRENT_PLAYER:
1261 case InventoryLocation::PLAYER:
1263 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1266 PlayerSAO *playersao = player->getPlayerSAO();
1269 return playersao->getInventory();
1272 case InventoryLocation::NODEMETA:
1274 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1277 return meta->getInventory();
1280 case InventoryLocation::DETACHED:
1282 if(m_detached_inventories.count(loc.name) == 0)
1284 return m_detached_inventories[loc.name];
1288 sanity_check(false); // abort
1293 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1296 case InventoryLocation::UNDEFINED:
1298 case InventoryLocation::PLAYER:
1303 RemotePlayer *player =
1304 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1309 PlayerSAO *playersao = player->getPlayerSAO();
1313 SendInventory(playersao);
1316 case InventoryLocation::NODEMETA:
1318 v3s16 blockpos = getNodeBlockPos(loc.p);
1320 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1322 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1324 setBlockNotSent(blockpos);
1327 case InventoryLocation::DETACHED:
1329 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1333 sanity_check(false); // abort
1338 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1340 std::vector<u16> clients = m_clients.getClientIDs();
1342 // Set the modified blocks unsent for all the clients
1343 for (std::vector<u16>::iterator i = clients.begin();
1344 i != clients.end(); ++i) {
1345 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1346 client->SetBlocksNotSent(block);
1351 void Server::peerAdded(con::Peer *peer)
1353 DSTACK(FUNCTION_NAME);
1354 verbosestream<<"Server::peerAdded(): peer->id="
1355 <<peer->id<<std::endl;
1358 c.type = con::PEER_ADDED;
1359 c.peer_id = peer->id;
1361 m_peer_change_queue.push(c);
1364 void Server::deletingPeer(con::Peer *peer, bool timeout)
1366 DSTACK(FUNCTION_NAME);
1367 verbosestream<<"Server::deletingPeer(): peer->id="
1368 <<peer->id<<", timeout="<<timeout<<std::endl;
1370 m_clients.event(peer->id, CSE_Disconnect);
1372 c.type = con::PEER_REMOVED;
1373 c.peer_id = peer->id;
1374 c.timeout = timeout;
1375 m_peer_change_queue.push(c);
1378 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1380 *retval = m_con.getPeerStat(peer_id,type);
1381 if (*retval == -1) return false;
1385 bool Server::getClientInfo(
1394 std::string* vers_string
1397 *state = m_clients.getClientState(peer_id);
1399 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1401 if (client == NULL) {
1406 *uptime = client->uptime();
1407 *ser_vers = client->serialization_version;
1408 *prot_vers = client->net_proto_version;
1410 *major = client->getMajor();
1411 *minor = client->getMinor();
1412 *patch = client->getPatch();
1413 *vers_string = client->getPatch();
1420 void Server::handlePeerChanges()
1422 while(m_peer_change_queue.size() > 0)
1424 con::PeerChange c = m_peer_change_queue.front();
1425 m_peer_change_queue.pop();
1427 verbosestream<<"Server: Handling peer change: "
1428 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1433 case con::PEER_ADDED:
1434 m_clients.CreateClient(c.peer_id);
1437 case con::PEER_REMOVED:
1438 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1442 FATAL_ERROR("Invalid peer change event received!");
1448 void Server::printToConsoleOnly(const std::string &text)
1451 m_admin_chat->outgoing_queue.push_back(
1452 new ChatEventChat("", utf8_to_wide(text)));
1454 std::cout << text << std::endl;
1458 void Server::Send(NetworkPacket* pkt)
1460 m_clients.send(pkt->getPeerId(),
1461 clientCommandFactoryTable[pkt->getCommand()].channel,
1463 clientCommandFactoryTable[pkt->getCommand()].reliable);
1466 void Server::SendMovement(u16 peer_id)
1468 DSTACK(FUNCTION_NAME);
1469 std::ostringstream os(std::ios_base::binary);
1471 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1473 pkt << g_settings->getFloat("movement_acceleration_default");
1474 pkt << g_settings->getFloat("movement_acceleration_air");
1475 pkt << g_settings->getFloat("movement_acceleration_fast");
1476 pkt << g_settings->getFloat("movement_speed_walk");
1477 pkt << g_settings->getFloat("movement_speed_crouch");
1478 pkt << g_settings->getFloat("movement_speed_fast");
1479 pkt << g_settings->getFloat("movement_speed_climb");
1480 pkt << g_settings->getFloat("movement_speed_jump");
1481 pkt << g_settings->getFloat("movement_liquid_fluidity");
1482 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1483 pkt << g_settings->getFloat("movement_liquid_sink");
1484 pkt << g_settings->getFloat("movement_gravity");
1489 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1491 if (!g_settings->getBool("enable_damage"))
1494 u16 peer_id = playersao->getPeerID();
1495 bool is_alive = playersao->getHP() > 0;
1498 SendPlayerHP(peer_id);
1503 void Server::SendHP(u16 peer_id, u8 hp)
1505 DSTACK(FUNCTION_NAME);
1507 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1512 void Server::SendBreath(u16 peer_id, u16 breath)
1514 DSTACK(FUNCTION_NAME);
1516 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1517 pkt << (u16) breath;
1521 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1522 const std::string &custom_reason, bool reconnect)
1524 assert(reason < SERVER_ACCESSDENIED_MAX);
1526 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1528 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1529 pkt << custom_reason;
1530 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1531 reason == SERVER_ACCESSDENIED_CRASH)
1532 pkt << custom_reason << (u8)reconnect;
1536 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1538 DSTACK(FUNCTION_NAME);
1540 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1545 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1546 v3f camera_point_target)
1548 DSTACK(FUNCTION_NAME);
1550 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1551 pkt << set_camera_point_target << camera_point_target;
1555 void Server::SendItemDef(u16 peer_id,
1556 IItemDefManager *itemdef, u16 protocol_version)
1558 DSTACK(FUNCTION_NAME);
1560 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1564 u32 length of the next item
1565 zlib-compressed serialized ItemDefManager
1567 std::ostringstream tmp_os(std::ios::binary);
1568 itemdef->serialize(tmp_os, protocol_version);
1569 std::ostringstream tmp_os2(std::ios::binary);
1570 compressZlib(tmp_os.str(), tmp_os2);
1571 pkt.putLongString(tmp_os2.str());
1574 verbosestream << "Server: Sending item definitions to id(" << peer_id
1575 << "): size=" << pkt.getSize() << std::endl;
1580 void Server::SendNodeDef(u16 peer_id,
1581 INodeDefManager *nodedef, u16 protocol_version)
1583 DSTACK(FUNCTION_NAME);
1585 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1589 u32 length of the next item
1590 zlib-compressed serialized NodeDefManager
1592 std::ostringstream tmp_os(std::ios::binary);
1593 nodedef->serialize(tmp_os, protocol_version);
1594 std::ostringstream tmp_os2(std::ios::binary);
1595 compressZlib(tmp_os.str(), tmp_os2);
1597 pkt.putLongString(tmp_os2.str());
1600 verbosestream << "Server: Sending node definitions to id(" << peer_id
1601 << "): size=" << pkt.getSize() << std::endl;
1607 Non-static send methods
1610 void Server::SendInventory(PlayerSAO* playerSAO)
1612 DSTACK(FUNCTION_NAME);
1614 UpdateCrafting(playerSAO->getPlayer());
1620 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1622 std::ostringstream os;
1623 playerSAO->getInventory()->serialize(os);
1625 std::string s = os.str();
1627 pkt.putRawString(s.c_str(), s.size());
1631 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1633 DSTACK(FUNCTION_NAME);
1635 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1638 if (peer_id != PEER_ID_INEXISTENT) {
1642 m_clients.sendToAll(0, &pkt, true);
1646 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1647 const std::string &formname)
1649 DSTACK(FUNCTION_NAME);
1651 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1652 if (formspec == "" ){
1653 //the client should close the formspec
1654 pkt.putLongString("");
1656 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1663 // Spawns a particle on peer with peer_id
1664 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1665 float expirationtime, float size, bool collisiondetection,
1666 bool collision_removal,
1667 bool vertical, const std::string &texture)
1669 DSTACK(FUNCTION_NAME);
1671 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1673 pkt << pos << velocity << acceleration << expirationtime
1674 << size << collisiondetection;
1675 pkt.putLongString(texture);
1677 pkt << collision_removal;
1679 if (peer_id != PEER_ID_INEXISTENT) {
1683 m_clients.sendToAll(0, &pkt, true);
1687 // Adds a ParticleSpawner on peer with peer_id
1688 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1689 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1690 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1691 u16 attached_id, bool vertical, const std::string &texture, u32 id)
1693 DSTACK(FUNCTION_NAME);
1695 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1697 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1698 << minacc << maxacc << minexptime << maxexptime << minsize
1699 << maxsize << collisiondetection;
1701 pkt.putLongString(texture);
1703 pkt << id << vertical;
1704 pkt << collision_removal;
1707 if (peer_id != PEER_ID_INEXISTENT) {
1711 m_clients.sendToAll(0, &pkt, true);
1715 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1717 DSTACK(FUNCTION_NAME);
1719 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1721 // Ugly error in this packet
1724 if (peer_id != PEER_ID_INEXISTENT) {
1728 m_clients.sendToAll(0, &pkt, true);
1733 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1735 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1737 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1738 << form->text << form->number << form->item << form->dir
1739 << form->align << form->offset << form->world_pos << form->size;
1744 void Server::SendHUDRemove(u16 peer_id, u32 id)
1746 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1751 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1753 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1754 pkt << id << (u8) stat;
1758 case HUD_STAT_SCALE:
1759 case HUD_STAT_ALIGN:
1760 case HUD_STAT_OFFSET:
1761 pkt << *(v2f *) value;
1765 pkt << *(std::string *) value;
1767 case HUD_STAT_WORLD_POS:
1768 pkt << *(v3f *) value;
1771 pkt << *(v2s32 *) value;
1773 case HUD_STAT_NUMBER:
1777 pkt << *(u32 *) value;
1784 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1786 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1788 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1790 pkt << flags << mask;
1795 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1797 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1798 pkt << param << value;
1802 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1803 const std::string &type, const std::vector<std::string> ¶ms)
1805 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1806 pkt << bgcolor << type << (u16) params.size();
1808 for(size_t i=0; i<params.size(); i++)
1814 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1817 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1820 pkt << do_override << (u16) (ratio * 65535);
1825 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1827 DSTACK(FUNCTION_NAME);
1829 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1830 pkt << time << time_speed;
1832 if (peer_id == PEER_ID_INEXISTENT) {
1833 m_clients.sendToAll(0, &pkt, true);
1840 void Server::SendPlayerHP(u16 peer_id)
1842 DSTACK(FUNCTION_NAME);
1843 PlayerSAO *playersao = getPlayerSAO(peer_id);
1844 // In some rare case if the player is disconnected
1845 // while Lua call l_punch, for example, this can be NULL
1849 SendHP(peer_id, playersao->getHP());
1850 m_script->player_event(playersao,"health_changed");
1852 // Send to other clients
1853 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1854 ActiveObjectMessage aom(playersao->getId(), true, str);
1855 playersao->m_messages_out.push(aom);
1858 void Server::SendPlayerBreath(PlayerSAO *sao)
1860 DSTACK(FUNCTION_NAME);
1863 m_script->player_event(sao, "breath_changed");
1864 SendBreath(sao->getPeerID(), sao->getBreath());
1867 void Server::SendMovePlayer(u16 peer_id)
1869 DSTACK(FUNCTION_NAME);
1870 RemotePlayer *player = m_env->getPlayer(peer_id);
1872 PlayerSAO *sao = player->getPlayerSAO();
1875 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1876 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1879 v3f pos = sao->getBasePosition();
1880 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1881 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1882 << " pitch=" << sao->getPitch()
1883 << " yaw=" << sao->getYaw()
1890 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1892 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1895 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1896 << animation_frames[3] << animation_speed;
1901 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1903 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1904 pkt << first << third;
1907 void Server::SendPlayerPrivileges(u16 peer_id)
1909 RemotePlayer *player = m_env->getPlayer(peer_id);
1911 if(player->peer_id == PEER_ID_INEXISTENT)
1914 std::set<std::string> privs;
1915 m_script->getAuth(player->getName(), NULL, &privs);
1917 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1918 pkt << (u16) privs.size();
1920 for(std::set<std::string>::const_iterator i = privs.begin();
1921 i != privs.end(); ++i) {
1928 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1930 RemotePlayer *player = m_env->getPlayer(peer_id);
1932 if(player->peer_id == PEER_ID_INEXISTENT)
1935 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1936 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1940 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1942 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 return pkt.getSize();
1948 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1950 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1951 datas.size(), peer_id);
1953 pkt.putRawString(datas.c_str(), datas.size());
1955 m_clients.send(pkt.getPeerId(),
1956 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1961 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<u16> dst_clients;
1973 if(params.to_player != "")
1975 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not found"<<std::endl;
1981 if(player->peer_id == PEER_ID_INEXISTENT){
1982 infostream<<"Server::playSound: Player \""<<params.to_player
1983 <<"\" not connected"<<std::endl;
1986 dst_clients.push_back(player->peer_id);
1989 std::vector<u16> clients = m_clients.getClientIDs();
1991 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1992 RemotePlayer *player = m_env->getPlayer(*i);
1996 PlayerSAO *sao = player->getPlayerSAO();
2001 if(sao->getBasePosition().getDistanceFrom(pos) >
2002 params.max_hear_distance)
2005 dst_clients.push_back(*i);
2009 if(dst_clients.empty())
2013 s32 id = m_next_sound_id++;
2014 // The sound will exist as a reference in m_playing_sounds
2015 m_playing_sounds[id] = ServerPlayingSound();
2016 ServerPlayingSound &psound = m_playing_sounds[id];
2017 psound.params = params;
2019 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2020 pkt << id << spec.name << (float) (spec.gain * params.gain)
2021 << (u8) params.type << pos << params.object << params.loop;
2023 for(std::vector<u16>::iterator i = dst_clients.begin();
2024 i != dst_clients.end(); ++i) {
2025 psound.clients.insert(*i);
2026 m_clients.send(*i, 0, &pkt, true);
2030 void Server::stopSound(s32 handle)
2032 // Get sound reference
2033 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2034 if (i == m_playing_sounds.end())
2036 ServerPlayingSound &psound = i->second;
2038 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2041 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2042 i != psound.clients.end(); ++i) {
2044 m_clients.send(*i, 0, &pkt, true);
2046 // Remove sound reference
2047 m_playing_sounds.erase(i);
2050 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2051 std::vector<u16> *far_players, float far_d_nodes)
2053 float maxd = far_d_nodes*BS;
2054 v3f p_f = intToFloat(p, BS);
2056 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2059 std::vector<u16> clients = m_clients.getClientIDs();
2060 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2063 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2064 PlayerSAO *sao = player->getPlayerSAO();
2068 // If player is far away, only set modified blocks not sent
2069 v3f player_pos = sao->getBasePosition();
2070 if (player_pos.getDistanceFrom(p_f) > maxd) {
2071 far_players->push_back(*i);
2078 m_clients.send(*i, 0, &pkt, true);
2082 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2083 std::vector<u16> *far_players, float far_d_nodes,
2084 bool remove_metadata)
2086 float maxd = far_d_nodes*BS;
2087 v3f p_f = intToFloat(p, BS);
2089 std::vector<u16> clients = m_clients.getClientIDs();
2090 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2093 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2094 PlayerSAO *sao = player->getPlayerSAO();
2098 // If player is far away, only set modified blocks not sent
2099 v3f player_pos = sao->getBasePosition();
2100 if(player_pos.getDistanceFrom(p_f) > maxd) {
2101 far_players->push_back(*i);
2107 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2109 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2111 pkt << p << n.param0 << n.param1 << n.param2
2112 << (u8) (remove_metadata ? 0 : 1);
2114 if (!remove_metadata) {
2115 if (client->net_proto_version <= 21) {
2116 // Old clients always clear metadata; fix it
2117 // by sending the full block again.
2118 client->SetBlockNotSent(getNodeBlockPos(p));
2125 if (pkt.getSize() > 0)
2126 m_clients.send(*i, 0, &pkt, true);
2130 void Server::setBlockNotSent(v3s16 p)
2132 std::vector<u16> clients = m_clients.getClientIDs();
2134 for(std::vector<u16>::iterator i = clients.begin();
2135 i != clients.end(); ++i) {
2136 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2137 client->SetBlockNotSent(p);
2142 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2144 DSTACK(FUNCTION_NAME);
2146 v3s16 p = block->getPos();
2149 Create a packet with the block in the right format
2152 std::ostringstream os(std::ios_base::binary);
2153 block->serialize(os, ver, false);
2154 block->serializeNetworkSpecific(os, net_proto_version);
2155 std::string s = os.str();
2157 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2160 pkt.putRawString(s.c_str(), s.size());
2164 void Server::SendBlocks(float dtime)
2166 DSTACK(FUNCTION_NAME);
2168 MutexAutoLock envlock(m_env_mutex);
2169 //TODO check if one big lock could be faster then multiple small ones
2171 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2173 std::vector<PrioritySortedBlockTransfer> queue;
2175 s32 total_sending = 0;
2178 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2180 std::vector<u16> clients = m_clients.getClientIDs();
2183 for(std::vector<u16>::iterator i = clients.begin();
2184 i != clients.end(); ++i) {
2185 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2190 total_sending += client->SendingCount();
2191 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2197 // Lowest priority number comes first.
2198 // Lowest is most important.
2199 std::sort(queue.begin(), queue.end());
2202 for(u32 i=0; i<queue.size(); i++)
2204 //TODO: Calculate limit dynamically
2205 if(total_sending >= g_settings->getS32
2206 ("max_simultaneous_block_sends_server_total"))
2209 PrioritySortedBlockTransfer q = queue[i];
2211 MapBlock *block = NULL;
2214 block = m_env->getMap().getBlockNoCreate(q.pos);
2216 catch(InvalidPositionException &e)
2221 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2226 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2228 client->SentBlock(q.pos);
2234 void Server::fillMediaCache()
2236 DSTACK(FUNCTION_NAME);
2238 infostream<<"Server: Calculating media file checksums"<<std::endl;
2240 // Collect all media file paths
2241 std::vector<std::string> paths;
2242 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2243 i != m_mods.end(); ++i) {
2244 const ModSpec &mod = *i;
2245 paths.push_back(mod.path + DIR_DELIM + "textures");
2246 paths.push_back(mod.path + DIR_DELIM + "sounds");
2247 paths.push_back(mod.path + DIR_DELIM + "media");
2248 paths.push_back(mod.path + DIR_DELIM + "models");
2250 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2252 // Collect media file information from paths into cache
2253 for(std::vector<std::string>::iterator i = paths.begin();
2254 i != paths.end(); ++i) {
2255 std::string mediapath = *i;
2256 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2257 for (u32 j = 0; j < dirlist.size(); j++) {
2258 if (dirlist[j].dir) // Ignode dirs
2260 std::string filename = dirlist[j].name;
2261 // If name contains illegal characters, ignore the file
2262 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2263 infostream<<"Server: ignoring illegal file name: \""
2264 << filename << "\"" << std::endl;
2267 // If name is not in a supported format, ignore it
2268 const char *supported_ext[] = {
2269 ".png", ".jpg", ".bmp", ".tga",
2270 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2272 ".x", ".b3d", ".md2", ".obj",
2275 if (removeStringEnd(filename, supported_ext) == ""){
2276 infostream << "Server: ignoring unsupported file extension: \""
2277 << filename << "\"" << std::endl;
2280 // Ok, attempt to load the file and add to cache
2281 std::string filepath = mediapath + DIR_DELIM + filename;
2283 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2285 errorstream << "Server::fillMediaCache(): Could not open \""
2286 << filename << "\" for reading" << std::endl;
2289 std::ostringstream tmp_os(std::ios_base::binary);
2293 fis.read(buf, 1024);
2294 std::streamsize len = fis.gcount();
2295 tmp_os.write(buf, len);
2304 errorstream<<"Server::fillMediaCache(): Failed to read \""
2305 << filename << "\"" << std::endl;
2308 if(tmp_os.str().length() == 0) {
2309 errorstream << "Server::fillMediaCache(): Empty file \""
2310 << filepath << "\"" << std::endl;
2315 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2317 unsigned char *digest = sha1.getDigest();
2318 std::string sha1_base64 = base64_encode(digest, 20);
2319 std::string sha1_hex = hex_encode((char*)digest, 20);
2323 m_media[filename] = MediaInfo(filepath, sha1_base64);
2324 verbosestream << "Server: " << sha1_hex << " is " << filename
2330 void Server::sendMediaAnnouncement(u16 peer_id)
2332 DSTACK(FUNCTION_NAME);
2334 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2338 std::ostringstream os(std::ios_base::binary);
2340 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2341 pkt << (u16) m_media.size();
2343 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2344 i != m_media.end(); ++i) {
2345 pkt << i->first << i->second.sha1_digest;
2348 pkt << g_settings->get("remote_media");
2352 struct SendableMedia
2358 SendableMedia(const std::string &name_="", const std::string &path_="",
2359 const std::string &data_=""):
2366 void Server::sendRequestedMedia(u16 peer_id,
2367 const std::vector<std::string> &tosend)
2369 DSTACK(FUNCTION_NAME);
2371 verbosestream<<"Server::sendRequestedMedia(): "
2372 <<"Sending files to client"<<std::endl;
2376 // Put 5kB in one bunch (this is not accurate)
2377 u32 bytes_per_bunch = 5000;
2379 std::vector< std::vector<SendableMedia> > file_bunches;
2380 file_bunches.push_back(std::vector<SendableMedia>());
2382 u32 file_size_bunch_total = 0;
2384 for(std::vector<std::string>::const_iterator i = tosend.begin();
2385 i != tosend.end(); ++i) {
2386 const std::string &name = *i;
2388 if (m_media.find(name) == m_media.end()) {
2389 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2390 <<"unknown file \""<<(name)<<"\""<<std::endl;
2394 //TODO get path + name
2395 std::string tpath = m_media[name].path;
2398 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2399 if(fis.good() == false){
2400 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2401 <<tpath<<"\" for reading"<<std::endl;
2404 std::ostringstream tmp_os(std::ios_base::binary);
2408 fis.read(buf, 1024);
2409 std::streamsize len = fis.gcount();
2410 tmp_os.write(buf, len);
2411 file_size_bunch_total += len;
2420 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2421 <<name<<"\""<<std::endl;
2424 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2425 <<tname<<"\""<<std::endl;*/
2427 file_bunches[file_bunches.size()-1].push_back(
2428 SendableMedia(name, tpath, tmp_os.str()));
2430 // Start next bunch if got enough data
2431 if(file_size_bunch_total >= bytes_per_bunch) {
2432 file_bunches.push_back(std::vector<SendableMedia>());
2433 file_size_bunch_total = 0;
2438 /* Create and send packets */
2440 u16 num_bunches = file_bunches.size();
2441 for(u16 i = 0; i < num_bunches; i++) {
2444 u16 total number of texture bunches
2445 u16 index of this bunch
2446 u32 number of files in this bunch
2455 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2456 pkt << num_bunches << i << (u32) file_bunches[i].size();
2458 for(std::vector<SendableMedia>::iterator
2459 j = file_bunches[i].begin();
2460 j != file_bunches[i].end(); ++j) {
2462 pkt.putLongString(j->data);
2465 verbosestream << "Server::sendRequestedMedia(): bunch "
2466 << i << "/" << num_bunches
2467 << " files=" << file_bunches[i].size()
2468 << " size=" << pkt.getSize() << std::endl;
2473 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2475 if(m_detached_inventories.count(name) == 0) {
2476 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2479 Inventory *inv = m_detached_inventories[name];
2480 std::ostringstream os(std::ios_base::binary);
2482 os << serializeString(name);
2486 std::string s = os.str();
2488 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2489 pkt.putRawString(s.c_str(), s.size());
2491 const std::string &check = m_detached_inventories_player[name];
2492 if (peer_id == PEER_ID_INEXISTENT) {
2494 return m_clients.sendToAll(0, &pkt, true);
2495 RemotePlayer *p = m_env->getPlayer(check.c_str());
2497 m_clients.send(p->peer_id, 0, &pkt, true);
2499 if (check == "" || getPlayerName(peer_id) == check)
2504 void Server::sendDetachedInventories(u16 peer_id)
2506 DSTACK(FUNCTION_NAME);
2508 for(std::map<std::string, Inventory*>::iterator
2509 i = m_detached_inventories.begin();
2510 i != m_detached_inventories.end(); ++i) {
2511 const std::string &name = i->first;
2512 //Inventory *inv = i->second;
2513 sendDetachedInventory(name, peer_id);
2521 void Server::DiePlayer(u16 peer_id)
2523 DSTACK(FUNCTION_NAME);
2524 PlayerSAO *playersao = getPlayerSAO(peer_id);
2525 // In some rare cases this can be NULL -- if the player is disconnected
2526 // when a Lua function modifies l_punch, for example
2530 infostream << "Server::DiePlayer(): Player "
2531 << playersao->getPlayer()->getName()
2532 << " dies" << std::endl;
2534 playersao->setHP(0);
2536 // Trigger scripted stuff
2537 m_script->on_dieplayer(playersao);
2539 SendPlayerHP(peer_id);
2540 SendDeathscreen(peer_id, false, v3f(0,0,0));
2543 void Server::RespawnPlayer(u16 peer_id)
2545 DSTACK(FUNCTION_NAME);
2547 PlayerSAO *playersao = getPlayerSAO(peer_id);
2550 infostream << "Server::RespawnPlayer(): Player "
2551 << playersao->getPlayer()->getName()
2552 << " respawns" << std::endl;
2554 playersao->setHP(PLAYER_MAX_HP);
2555 playersao->setBreath(PLAYER_MAX_BREATH);
2557 bool repositioned = m_script->on_respawnplayer(playersao);
2558 if (!repositioned) {
2559 v3f pos = findSpawnPos();
2560 // setPos will send the new position to client
2561 playersao->setPos(pos);
2564 SendPlayerHP(peer_id);
2568 void Server::DenySudoAccess(u16 peer_id)
2570 DSTACK(FUNCTION_NAME);
2572 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2577 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2578 const std::string &str_reason, bool reconnect)
2580 if (proto_ver >= 25) {
2581 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2583 std::wstring wreason = utf8_to_wide(
2584 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2585 accessDeniedStrings[(u8)reason]);
2586 SendAccessDenied_Legacy(peer_id, wreason);
2589 m_clients.event(peer_id, CSE_SetDenied);
2590 m_con.DisconnectPeer(peer_id);
2594 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2596 DSTACK(FUNCTION_NAME);
2598 SendAccessDenied(peer_id, reason, custom_reason);
2599 m_clients.event(peer_id, CSE_SetDenied);
2600 m_con.DisconnectPeer(peer_id);
2603 // 13/03/15: remove this function when protocol version 25 will become
2604 // the minimum version for MT users, maybe in 1 year
2605 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2607 DSTACK(FUNCTION_NAME);
2609 SendAccessDenied_Legacy(peer_id, reason);
2610 m_clients.event(peer_id, CSE_SetDenied);
2611 m_con.DisconnectPeer(peer_id);
2614 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2616 DSTACK(FUNCTION_NAME);
2619 RemoteClient* client = getClient(peer_id, CS_Invalid);
2621 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2623 // Right now, the auth mechs don't change between login and sudo mode.
2624 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2625 client->allowed_sudo_mechs = sudo_auth_mechs;
2627 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2628 << g_settings->getFloat("dedicated_server_step")
2632 m_clients.event(peer_id, CSE_AuthAccept);
2634 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2636 // We only support SRP right now
2637 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2639 resp_pkt << sudo_auth_mechs;
2641 m_clients.event(peer_id, CSE_SudoSuccess);
2645 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2647 DSTACK(FUNCTION_NAME);
2648 std::wstring message;
2651 Clear references to playing sounds
2653 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2654 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2655 ServerPlayingSound &psound = i->second;
2656 psound.clients.erase(peer_id);
2657 if (psound.clients.empty())
2658 m_playing_sounds.erase(i++);
2663 RemotePlayer *player = m_env->getPlayer(peer_id);
2665 /* Run scripts and remove from environment */
2666 if (player != NULL) {
2667 PlayerSAO *playersao = player->getPlayerSAO();
2670 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2672 playersao->disconnected();
2679 if(player != NULL && reason != CDR_DENY) {
2680 std::ostringstream os(std::ios_base::binary);
2681 std::vector<u16> clients = m_clients.getClientIDs();
2683 for(std::vector<u16>::iterator i = clients.begin();
2684 i != clients.end(); ++i) {
2686 RemotePlayer *player = m_env->getPlayer(*i);
2690 // Get name of player
2691 os << player->getName() << " ";
2694 std::string name = player->getName();
2695 actionstream << name << " "
2696 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2697 << " List of players: " << os.str() << std::endl;
2699 m_admin_chat->outgoing_queue.push_back(
2700 new ChatEventNick(CET_NICK_REMOVE, name));
2704 MutexAutoLock env_lock(m_env_mutex);
2705 m_clients.DeleteClient(peer_id);
2709 // Send leave chat message to all remaining clients
2710 if(message.length() != 0)
2711 SendChatMessage(PEER_ID_INEXISTENT,message);
2714 void Server::UpdateCrafting(RemotePlayer *player)
2716 DSTACK(FUNCTION_NAME);
2718 // Get a preview for crafting
2720 InventoryLocation loc;
2721 loc.setPlayer(player->getName());
2722 std::vector<ItemStack> output_replacements;
2723 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2724 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2725 (&player->inventory)->getList("craft"), loc);
2727 // Put the new preview in
2728 InventoryList *plist = player->inventory.getList("craftpreview");
2729 sanity_check(plist);
2730 sanity_check(plist->getSize() >= 1);
2731 plist->changeItem(0, preview);
2734 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2736 if (evt->type == CET_NICK_ADD) {
2737 // The terminal informed us of its nick choice
2738 m_admin_nick = ((ChatEventNick *)evt)->nick;
2739 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2740 errorstream << "You haven't set up an account." << std::endl
2741 << "Please log in using the client as '"
2742 << m_admin_nick << "' with a secure password." << std::endl
2743 << "Until then, you can't execute admin tasks via the console," << std::endl
2744 << "and everybody can claim the user account instead of you," << std::endl
2745 << "giving them full control over this server." << std::endl;
2748 assert(evt->type == CET_CHAT);
2749 handleAdminChat((ChatEventChat *)evt);
2753 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2754 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2756 // If something goes wrong, this player is to blame
2757 RollbackScopeActor rollback_scope(m_rollback,
2758 std::string("player:") + name);
2762 // Whether to send line to the player that sent the message, or to all players
2763 bool broadcast_line = true;
2766 bool ate = m_script->on_chat_message(name,
2767 wide_to_utf8(wmessage));
2768 // If script ate the message, don't proceed
2773 switch (player->canSendChatMessage()) {
2774 case RPLAYER_CHATRESULT_FLOODING: {
2775 std::wstringstream ws;
2776 ws << L"You cannot send more messages. You are limited to "
2777 << g_settings->getFloat("chat_message_limit_per_10sec")
2778 << L" messages per 10 seconds.";
2781 case RPLAYER_CHATRESULT_KICK:
2782 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2784 case RPLAYER_CHATRESULT_OK: break;
2785 default: FATAL_ERROR("Unhandled chat filtering result found.");
2789 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2790 return L"Your message exceed the maximum chat message limit set on the server. "
2791 L"It was refused. Send a shorter message";
2794 // Commands are implemented in Lua, so only catch invalid
2795 // commands that were not "eaten" and send an error back
2796 if (wmessage[0] == L'/') {
2797 std::wstring wcmd = wmessage.substr(1);
2798 broadcast_line = false;
2799 if (wcmd.length() == 0)
2800 line += L"-!- Empty command";
2802 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2804 if (check_shout_priv && !checkPriv(name, "shout")) {
2805 line += L"-!- You don't have permission to shout.";
2806 broadcast_line = false;
2816 Tell calling method to send the message to sender
2818 if (!broadcast_line) {
2822 Send the message to others
2824 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2826 std::vector<u16> clients = m_clients.getClientIDs();
2828 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2829 for (u16 i = 0; i < clients.size(); i++) {
2830 u16 cid = clients[i];
2831 if (cid != peer_id_to_avoid_sending)
2832 SendChatMessage(cid, line);
2838 void Server::handleAdminChat(const ChatEventChat *evt)
2840 std::string name = evt->nick;
2841 std::wstring wname = utf8_to_wide(name);
2842 std::wstring wmessage = evt->evt_msg;
2844 std::wstring answer = handleChat(name, wname, wmessage);
2846 // If asked to send answer to sender
2847 if (!answer.empty()) {
2848 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2852 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2854 RemoteClient *client = getClientNoEx(peer_id,state_min);
2856 throw ClientNotFoundException("Client not found");
2860 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2862 return m_clients.getClientNoEx(peer_id, state_min);
2865 std::string Server::getPlayerName(u16 peer_id)
2867 RemotePlayer *player = m_env->getPlayer(peer_id);
2869 return "[id="+itos(peer_id)+"]";
2870 return player->getName();
2873 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2875 RemotePlayer *player = m_env->getPlayer(peer_id);
2878 return player->getPlayerSAO();
2881 std::wstring Server::getStatusString()
2883 std::wostringstream os(std::ios_base::binary);
2886 os<<L"version="<<narrow_to_wide(g_version_string);
2888 os<<L", uptime="<<m_uptime.get();
2890 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2891 // Information about clients
2894 std::vector<u16> clients = m_clients.getClientIDs();
2895 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2897 RemotePlayer *player = m_env->getPlayer(*i);
2898 // Get name of player
2899 std::wstring name = L"unknown";
2901 name = narrow_to_wide(player->getName());
2902 // Add name to information string
2910 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2911 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2912 if(g_settings->get("motd") != "")
2913 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2917 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2919 std::set<std::string> privs;
2920 m_script->getAuth(name, NULL, &privs);
2924 bool Server::checkPriv(const std::string &name, const std::string &priv)
2926 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2927 return (privs.count(priv) != 0);
2930 void Server::reportPrivsModified(const std::string &name)
2933 std::vector<u16> clients = m_clients.getClientIDs();
2934 for(std::vector<u16>::iterator i = clients.begin();
2935 i != clients.end(); ++i) {
2936 RemotePlayer *player = m_env->getPlayer(*i);
2937 reportPrivsModified(player->getName());
2940 RemotePlayer *player = m_env->getPlayer(name.c_str());
2943 SendPlayerPrivileges(player->peer_id);
2944 PlayerSAO *sao = player->getPlayerSAO();
2947 sao->updatePrivileges(
2948 getPlayerEffectivePrivs(name),
2953 void Server::reportInventoryFormspecModified(const std::string &name)
2955 RemotePlayer *player = m_env->getPlayer(name.c_str());
2958 SendPlayerInventoryFormspec(player->peer_id);
2961 void Server::setIpBanned(const std::string &ip, const std::string &name)
2963 m_banmanager->add(ip, name);
2966 void Server::unsetIpBanned(const std::string &ip_or_name)
2968 m_banmanager->remove(ip_or_name);
2971 std::string Server::getBanDescription(const std::string &ip_or_name)
2973 return m_banmanager->getBanDescription(ip_or_name);
2976 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2978 // m_env will be NULL if the server is initializing
2982 if (m_admin_nick == name && !m_admin_nick.empty()) {
2983 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2986 RemotePlayer *player = m_env->getPlayer(name);
2991 if (player->peer_id == PEER_ID_INEXISTENT)
2994 SendChatMessage(player->peer_id, msg);
2997 bool Server::showFormspec(const char *playername, const std::string &formspec,
2998 const std::string &formname)
3000 // m_env will be NULL if the server is initializing
3004 RemotePlayer *player = m_env->getPlayer(playername);
3008 SendShowFormspecMessage(player->peer_id, formspec, formname);
3012 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3017 u32 id = player->addHud(form);
3019 SendHUDAdd(player->peer_id, id, form);
3024 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3028 HudElement* todel = player->removeHud(id);
3035 SendHUDRemove(player->peer_id, id);
3039 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3044 SendHUDChange(player->peer_id, id, stat, data);
3048 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3053 SendHUDSetFlags(player->peer_id, flags, mask);
3054 player->hud_flags &= ~mask;
3055 player->hud_flags |= flags;
3057 PlayerSAO* playersao = player->getPlayerSAO();
3059 if (playersao == NULL)
3062 m_script->player_event(playersao, "hud_changed");
3066 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3071 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3074 player->setHotbarItemcount(hotbar_itemcount);
3075 std::ostringstream os(std::ios::binary);
3076 writeS32(os, hotbar_itemcount);
3077 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3081 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3086 player->setHotbarImage(name);
3087 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3090 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3094 return player->getHotbarImage();
3097 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3102 player->setHotbarSelectedImage(name);
3103 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3106 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3107 v2s32 animation_frames[4], f32 frame_speed)
3112 player->setLocalAnimations(animation_frames, frame_speed);
3113 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3117 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3122 player->eye_offset_first = first;
3123 player->eye_offset_third = third;
3124 SendEyeOffset(player->peer_id, first, third);
3128 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3129 const std::string &type, const std::vector<std::string> ¶ms)
3134 player->setSky(bgcolor, type, params);
3135 SendSetSky(player->peer_id, bgcolor, type, params);
3139 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3145 player->overrideDayNightRatio(do_override, ratio);
3146 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3150 void Server::notifyPlayers(const std::wstring &msg)
3152 SendChatMessage(PEER_ID_INEXISTENT,msg);
3155 void Server::spawnParticle(const std::string &playername, v3f pos,
3156 v3f velocity, v3f acceleration,
3157 float expirationtime, float size, bool
3158 collisiondetection, bool collision_removal,
3159 bool vertical, const std::string &texture)
3161 // m_env will be NULL if the server is initializing
3165 u16 peer_id = PEER_ID_INEXISTENT;
3166 if (playername != "") {
3167 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3170 peer_id = player->peer_id;
3173 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3174 expirationtime, size, collisiondetection,
3175 collision_removal, vertical, texture);
3178 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3179 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3180 float minexptime, float maxexptime, float minsize, float maxsize,
3181 bool collisiondetection, bool collision_removal,
3182 ServerActiveObject *attached, bool vertical, const std::string &texture,
3183 const std::string &playername)
3185 // m_env will be NULL if the server is initializing
3189 u16 peer_id = PEER_ID_INEXISTENT;
3190 if (playername != "") {
3191 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3194 peer_id = player->peer_id;
3197 u16 attached_id = attached ? attached->getId() : 0;
3200 if (attached_id == 0)
3201 id = m_env->addParticleSpawner(spawntime);
3203 id = m_env->addParticleSpawner(spawntime, attached_id);
3205 SendAddParticleSpawner(peer_id, amount, spawntime,
3206 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3207 minexptime, maxexptime, minsize, maxsize,
3208 collisiondetection, collision_removal, attached_id, vertical,
3214 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3216 // m_env will be NULL if the server is initializing
3218 throw ServerError("Can't delete particle spawners during initialisation!");
3220 u16 peer_id = PEER_ID_INEXISTENT;
3221 if (playername != "") {
3222 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3225 peer_id = player->peer_id;
3228 m_env->deleteParticleSpawner(id);
3229 SendDeleteParticleSpawner(peer_id, id);
3232 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3234 if(m_detached_inventories.count(name) > 0){
3235 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3236 delete m_detached_inventories[name];
3238 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3240 Inventory *inv = new Inventory(m_itemdef);
3242 m_detached_inventories[name] = inv;
3243 m_detached_inventories_player[name] = player;
3244 //TODO find a better way to do this
3245 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3249 // actions: time-reversed list
3250 // Return value: success/failure
3251 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3252 std::list<std::string> *log)
3254 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3255 ServerMap *map = (ServerMap*)(&m_env->getMap());
3257 // Fail if no actions to handle
3258 if(actions.empty()){
3259 log->push_back("Nothing to do.");
3266 for(std::list<RollbackAction>::const_iterator
3267 i = actions.begin();
3268 i != actions.end(); ++i)
3270 const RollbackAction &action = *i;
3272 bool success = action.applyRevert(map, this, this);
3275 std::ostringstream os;
3276 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3277 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3279 log->push_back(os.str());
3281 std::ostringstream os;
3282 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3283 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3285 log->push_back(os.str());
3289 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3290 <<" failed"<<std::endl;
3292 // Call it done if less than half failed
3293 return num_failed <= num_tried/2;
3296 // IGameDef interface
3298 IItemDefManager *Server::getItemDefManager()
3303 INodeDefManager *Server::getNodeDefManager()
3308 ICraftDefManager *Server::getCraftDefManager()
3313 u16 Server::allocateUnknownNodeId(const std::string &name)
3315 return m_nodedef->allocateDummy(name);
3318 MtEventManager *Server::getEventManager()
3323 IWritableItemDefManager *Server::getWritableItemDefManager()
3328 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3333 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3338 const ModSpec *Server::getModSpec(const std::string &modname) const
3340 std::vector<ModSpec>::const_iterator it;
3341 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3342 const ModSpec &mod = *it;
3343 if (mod.name == modname)
3349 void Server::getModNames(std::vector<std::string> &modlist)
3351 std::vector<ModSpec>::iterator it;
3352 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3353 modlist.push_back(it->name);
3356 std::string Server::getBuiltinLuaPath()
3358 return porting::path_share + DIR_DELIM + "builtin";
3361 v3f Server::findSpawnPos()
3363 ServerMap &map = m_env->getServerMap();
3365 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3366 return nodeposf * BS;
3369 bool is_good = false;
3371 // Try to find a good place a few times
3372 for(s32 i = 0; i < 4000 && !is_good; i++) {
3374 // We're going to try to throw the player to this position
3375 v2s16 nodepos2d = v2s16(
3376 -range + (myrand() % (range * 2)),
3377 -range + (myrand() % (range * 2)));
3379 // Get spawn level at point
3380 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3381 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3382 // the mapgen to signify an unsuitable spawn position
3383 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3386 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3389 for (s32 i = 0; i < 10; i++) {
3390 v3s16 blockpos = getNodeBlockPos(nodepos);
3391 map.emergeBlock(blockpos, true);
3392 content_t c = map.getNodeNoEx(nodepos).getContent();
3393 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3395 if (air_count >= 2) {
3396 nodeposf = intToFloat(nodepos, BS);
3397 // Don't spawn the player outside map boundaries
3398 if (objectpos_over_limit(nodeposf))
3411 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3413 bool newplayer = false;
3416 Try to get an existing player
3418 RemotePlayer *player = m_env->getPlayer(name);
3420 // If player is already connected, cancel
3421 if (player != NULL && player->peer_id != 0) {
3422 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3427 If player with the wanted peer_id already exists, cancel.
3429 if (m_env->getPlayer(peer_id) != NULL) {
3430 infostream<<"emergePlayer(): Player with wrong name but same"
3431 " peer_id already exists"<<std::endl;
3435 // Create a new player active object
3436 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3437 player = m_env->loadPlayer(name, playersao);
3439 // Create player if it doesn't exist
3442 player = new RemotePlayer(name, this->idef());
3443 // Set player position
3444 infostream<<"Server: Finding spawn place for player \""
3445 <<name<<"\""<<std::endl;
3446 playersao->setBasePosition(findSpawnPos());
3448 // Make sure the player is saved
3449 player->setModified(true);
3451 // Add player to environment
3452 m_env->addPlayer(player);
3454 // If the player exists, ensure that they respawn inside legal bounds
3455 // This fixes an assert crash when the player can't be added
3456 // to the environment
3457 if (objectpos_over_limit(playersao->getBasePosition())) {
3458 actionstream << "Respawn position for player \""
3459 << name << "\" outside limits, resetting" << std::endl;
3460 playersao->setBasePosition(findSpawnPos());
3464 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3466 player->protocol_version = proto_version;
3468 /* Clean up old HUD elements from previous sessions */
3471 /* Add object to environment */
3472 m_env->addActiveObject(playersao);
3476 m_script->on_newplayer(playersao);
3482 void dedicated_server_loop(Server &server, bool &kill)
3484 DSTACK(FUNCTION_NAME);
3486 verbosestream<<"dedicated_server_loop()"<<std::endl;
3488 IntervalLimiter m_profiler_interval;
3490 static const float steplen = g_settings->getFloat("dedicated_server_step");
3491 static const float profiler_print_interval =
3492 g_settings->getFloat("profiler_print_interval");
3495 // This is kind of a hack but can be done like this
3496 // because server.step() is very light
3498 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3499 sleep_ms((int)(steplen*1000.0));
3501 server.step(steplen);
3503 if(server.getShutdownRequested() || kill)
3505 infostream<<"Dedicated server quitting"<<std::endl;
3507 if(g_settings->getBool("server_announce"))
3508 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3516 if (profiler_print_interval != 0) {
3517 if(m_profiler_interval.step(steplen, profiler_print_interval))
3519 infostream<<"Profiler:"<<std::endl;
3520 g_profiler->print(infostream);
3521 g_profiler->clear();