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"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "util/base64.h"
61 #include "util/sha1.h"
64 class ClientNotFoundException : public BaseException
67 ClientNotFoundException(const char *s):
72 class ServerThread : public Thread
76 ServerThread(Server *server):
87 void *ServerThread::run()
89 DSTACK(FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
92 m_server->AsyncRunStep(true);
94 while (!stopRequested()) {
96 //TimeTaker timer("AsyncRunStep() + Receive()");
98 m_server->AsyncRunStep();
102 } catch (con::NoIncomingDataException &e) {
103 } catch (con::PeerNotFoundException &e) {
104 infostream<<"Server: PeerNotFoundException"<<std::endl;
105 } catch (ClientNotFoundException &e) {
106 } catch (con::ConnectionBindFailed &e) {
107 m_server->setAsyncFatalError(e.what());
108 } catch (LuaError &e) {
109 m_server->setAsyncFatalError(
110 "ServerThread::run Lua: " + std::string(e.what()));
114 END_DEBUG_EXCEPTION_HANDLER
119 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
121 if(pos_exists) *pos_exists = false;
126 if(pos_exists) *pos_exists = true;
131 ServerActiveObject *sao = env->getActiveObject(object);
134 if(pos_exists) *pos_exists = true;
135 return sao->getBasePosition(); }
147 const std::string &path_world,
148 const SubgameSpec &gamespec,
149 bool simple_singleplayer_mode,
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("AsyncErr: " + 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, u16 protocol_version,
1665 v3f pos, v3f velocity, v3f acceleration,
1666 float expirationtime, float size, bool collisiondetection,
1667 bool collision_removal,
1668 bool vertical, const std::string &texture,
1669 const struct TileAnimationParams &animation, u8 glow)
1671 DSTACK(FUNCTION_NAME);
1672 if (peer_id == PEER_ID_INEXISTENT) {
1673 // This sucks and should be replaced by a better solution in a refactor:
1674 std::vector<u16> clients = m_clients.getClientIDs();
1675 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1676 RemotePlayer *player = m_env->getPlayer(*i);
1679 SendSpawnParticle(*i, player->protocol_version,
1680 pos, velocity, acceleration,
1681 expirationtime, size, collisiondetection,
1682 collision_removal, vertical, texture, animation, glow);
1687 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1689 pkt << pos << velocity << acceleration << expirationtime
1690 << size << collisiondetection;
1691 pkt.putLongString(texture);
1693 pkt << collision_removal;
1694 // This is horrible but required (why are there two ways to serialize pkts?)
1695 std::ostringstream os(std::ios_base::binary);
1696 animation.serialize(os, protocol_version);
1697 pkt.putRawString(os.str());
1703 // Adds a ParticleSpawner on peer with peer_id
1704 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1705 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1706 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1707 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1708 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1709 const struct TileAnimationParams &animation, u8 glow)
1711 DSTACK(FUNCTION_NAME);
1712 if (peer_id == PEER_ID_INEXISTENT) {
1713 // This sucks and should be replaced:
1714 std::vector<u16> clients = m_clients.getClientIDs();
1715 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1716 RemotePlayer *player = m_env->getPlayer(*i);
1719 SendAddParticleSpawner(*i, player->protocol_version,
1720 amount, spawntime, minpos, maxpos,
1721 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1722 minsize, maxsize, collisiondetection, collision_removal,
1723 attached_id, vertical, texture, id, animation, glow);
1728 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1730 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1731 << minacc << maxacc << minexptime << maxexptime << minsize
1732 << maxsize << collisiondetection;
1734 pkt.putLongString(texture);
1736 pkt << id << vertical;
1737 pkt << collision_removal;
1739 // This is horrible but required
1740 std::ostringstream os(std::ios_base::binary);
1741 animation.serialize(os, protocol_version);
1742 pkt.putRawString(os.str());
1748 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1750 DSTACK(FUNCTION_NAME);
1752 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1754 // Ugly error in this packet
1757 if (peer_id != PEER_ID_INEXISTENT) {
1761 m_clients.sendToAll(0, &pkt, true);
1766 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1768 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1770 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1771 << form->text << form->number << form->item << form->dir
1772 << form->align << form->offset << form->world_pos << form->size;
1777 void Server::SendHUDRemove(u16 peer_id, u32 id)
1779 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1784 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1786 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1787 pkt << id << (u8) stat;
1791 case HUD_STAT_SCALE:
1792 case HUD_STAT_ALIGN:
1793 case HUD_STAT_OFFSET:
1794 pkt << *(v2f *) value;
1798 pkt << *(std::string *) value;
1800 case HUD_STAT_WORLD_POS:
1801 pkt << *(v3f *) value;
1804 pkt << *(v2s32 *) value;
1806 case HUD_STAT_NUMBER:
1810 pkt << *(u32 *) value;
1817 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1819 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1821 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1823 pkt << flags << mask;
1828 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1830 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1831 pkt << param << value;
1835 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1836 const std::string &type, const std::vector<std::string> ¶ms)
1838 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1839 pkt << bgcolor << type << (u16) params.size();
1841 for(size_t i=0; i<params.size(); i++)
1847 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1850 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1853 pkt << do_override << (u16) (ratio * 65535);
1858 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1860 DSTACK(FUNCTION_NAME);
1862 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1863 pkt << time << time_speed;
1865 if (peer_id == PEER_ID_INEXISTENT) {
1866 m_clients.sendToAll(0, &pkt, true);
1873 void Server::SendPlayerHP(u16 peer_id)
1875 DSTACK(FUNCTION_NAME);
1876 PlayerSAO *playersao = getPlayerSAO(peer_id);
1877 // In some rare case if the player is disconnected
1878 // while Lua call l_punch, for example, this can be NULL
1882 SendHP(peer_id, playersao->getHP());
1883 m_script->player_event(playersao,"health_changed");
1885 // Send to other clients
1886 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1887 ActiveObjectMessage aom(playersao->getId(), true, str);
1888 playersao->m_messages_out.push(aom);
1891 void Server::SendPlayerBreath(PlayerSAO *sao)
1893 DSTACK(FUNCTION_NAME);
1896 m_script->player_event(sao, "breath_changed");
1897 SendBreath(sao->getPeerID(), sao->getBreath());
1900 void Server::SendMovePlayer(u16 peer_id)
1902 DSTACK(FUNCTION_NAME);
1903 RemotePlayer *player = m_env->getPlayer(peer_id);
1905 PlayerSAO *sao = player->getPlayerSAO();
1908 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1909 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1912 v3f pos = sao->getBasePosition();
1913 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1914 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1915 << " pitch=" << sao->getPitch()
1916 << " yaw=" << sao->getYaw()
1923 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1925 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1928 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1929 << animation_frames[3] << animation_speed;
1934 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1936 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1937 pkt << first << third;
1940 void Server::SendPlayerPrivileges(u16 peer_id)
1942 RemotePlayer *player = m_env->getPlayer(peer_id);
1944 if(player->peer_id == PEER_ID_INEXISTENT)
1947 std::set<std::string> privs;
1948 m_script->getAuth(player->getName(), NULL, &privs);
1950 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1951 pkt << (u16) privs.size();
1953 for(std::set<std::string>::const_iterator i = privs.begin();
1954 i != privs.end(); ++i) {
1961 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1963 RemotePlayer *player = m_env->getPlayer(peer_id);
1965 if(player->peer_id == PEER_ID_INEXISTENT)
1968 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1969 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1973 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1975 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1976 pkt.putRawString(datas.c_str(), datas.size());
1978 return pkt.getSize();
1981 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1983 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1984 datas.size(), peer_id);
1986 pkt.putRawString(datas.c_str(), datas.size());
1988 m_clients.send(pkt.getPeerId(),
1989 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1994 s32 Server::playSound(const SimpleSoundSpec &spec,
1995 const ServerSoundParams ¶ms)
1997 // Find out initial position of sound
1998 bool pos_exists = false;
1999 v3f pos = params.getPos(m_env, &pos_exists);
2000 // If position is not found while it should be, cancel sound
2001 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2004 // Filter destination clients
2005 std::vector<u16> dst_clients;
2006 if(params.to_player != "")
2008 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2010 infostream<<"Server::playSound: Player \""<<params.to_player
2011 <<"\" not found"<<std::endl;
2014 if(player->peer_id == PEER_ID_INEXISTENT){
2015 infostream<<"Server::playSound: Player \""<<params.to_player
2016 <<"\" not connected"<<std::endl;
2019 dst_clients.push_back(player->peer_id);
2022 std::vector<u16> clients = m_clients.getClientIDs();
2024 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2025 RemotePlayer *player = m_env->getPlayer(*i);
2029 PlayerSAO *sao = player->getPlayerSAO();
2034 if(sao->getBasePosition().getDistanceFrom(pos) >
2035 params.max_hear_distance)
2038 dst_clients.push_back(*i);
2042 if(dst_clients.empty())
2046 s32 id = m_next_sound_id++;
2047 // The sound will exist as a reference in m_playing_sounds
2048 m_playing_sounds[id] = ServerPlayingSound();
2049 ServerPlayingSound &psound = m_playing_sounds[id];
2050 psound.params = params;
2052 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2053 pkt << id << spec.name << (float) (spec.gain * params.gain)
2054 << (u8) params.type << pos << params.object << params.loop;
2056 for(std::vector<u16>::iterator i = dst_clients.begin();
2057 i != dst_clients.end(); ++i) {
2058 psound.clients.insert(*i);
2059 m_clients.send(*i, 0, &pkt, true);
2063 void Server::stopSound(s32 handle)
2065 // Get sound reference
2066 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2067 if (i == m_playing_sounds.end())
2069 ServerPlayingSound &psound = i->second;
2071 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2074 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2075 i != psound.clients.end(); ++i) {
2077 m_clients.send(*i, 0, &pkt, true);
2079 // Remove sound reference
2080 m_playing_sounds.erase(i);
2083 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2084 std::vector<u16> *far_players, float far_d_nodes)
2086 float maxd = far_d_nodes*BS;
2087 v3f p_f = intToFloat(p, BS);
2089 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2092 std::vector<u16> clients = m_clients.getClientIDs();
2093 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2096 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2097 PlayerSAO *sao = player->getPlayerSAO();
2101 // If player is far away, only set modified blocks not sent
2102 v3f player_pos = sao->getBasePosition();
2103 if (player_pos.getDistanceFrom(p_f) > maxd) {
2104 far_players->push_back(*i);
2111 m_clients.send(*i, 0, &pkt, true);
2115 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2116 std::vector<u16> *far_players, float far_d_nodes,
2117 bool remove_metadata)
2119 float maxd = far_d_nodes*BS;
2120 v3f p_f = intToFloat(p, BS);
2122 std::vector<u16> clients = m_clients.getClientIDs();
2123 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2126 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2127 PlayerSAO *sao = player->getPlayerSAO();
2131 // If player is far away, only set modified blocks not sent
2132 v3f player_pos = sao->getBasePosition();
2133 if(player_pos.getDistanceFrom(p_f) > maxd) {
2134 far_players->push_back(*i);
2140 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2142 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2144 pkt << p << n.param0 << n.param1 << n.param2
2145 << (u8) (remove_metadata ? 0 : 1);
2147 if (!remove_metadata) {
2148 if (client->net_proto_version <= 21) {
2149 // Old clients always clear metadata; fix it
2150 // by sending the full block again.
2151 client->SetBlockNotSent(getNodeBlockPos(p));
2158 if (pkt.getSize() > 0)
2159 m_clients.send(*i, 0, &pkt, true);
2163 void Server::setBlockNotSent(v3s16 p)
2165 std::vector<u16> clients = m_clients.getClientIDs();
2167 for(std::vector<u16>::iterator i = clients.begin();
2168 i != clients.end(); ++i) {
2169 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2170 client->SetBlockNotSent(p);
2175 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2177 DSTACK(FUNCTION_NAME);
2179 v3s16 p = block->getPos();
2182 Create a packet with the block in the right format
2185 std::ostringstream os(std::ios_base::binary);
2186 block->serialize(os, ver, false);
2187 block->serializeNetworkSpecific(os, net_proto_version);
2188 std::string s = os.str();
2190 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2193 pkt.putRawString(s.c_str(), s.size());
2197 void Server::SendBlocks(float dtime)
2199 DSTACK(FUNCTION_NAME);
2201 MutexAutoLock envlock(m_env_mutex);
2202 //TODO check if one big lock could be faster then multiple small ones
2204 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2206 std::vector<PrioritySortedBlockTransfer> queue;
2208 s32 total_sending = 0;
2211 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2213 std::vector<u16> clients = m_clients.getClientIDs();
2216 for(std::vector<u16>::iterator i = clients.begin();
2217 i != clients.end(); ++i) {
2218 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2223 total_sending += client->SendingCount();
2224 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2230 // Lowest priority number comes first.
2231 // Lowest is most important.
2232 std::sort(queue.begin(), queue.end());
2235 for(u32 i=0; i<queue.size(); i++)
2237 //TODO: Calculate limit dynamically
2238 if(total_sending >= g_settings->getS32
2239 ("max_simultaneous_block_sends_server_total"))
2242 PrioritySortedBlockTransfer q = queue[i];
2244 MapBlock *block = NULL;
2247 block = m_env->getMap().getBlockNoCreate(q.pos);
2249 catch(InvalidPositionException &e)
2254 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2259 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2261 client->SentBlock(q.pos);
2267 void Server::fillMediaCache()
2269 DSTACK(FUNCTION_NAME);
2271 infostream<<"Server: Calculating media file checksums"<<std::endl;
2273 // Collect all media file paths
2274 std::vector<std::string> paths;
2275 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2276 i != m_mods.end(); ++i) {
2277 const ModSpec &mod = *i;
2278 paths.push_back(mod.path + DIR_DELIM + "textures");
2279 paths.push_back(mod.path + DIR_DELIM + "sounds");
2280 paths.push_back(mod.path + DIR_DELIM + "media");
2281 paths.push_back(mod.path + DIR_DELIM + "models");
2283 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2285 // Collect media file information from paths into cache
2286 for(std::vector<std::string>::iterator i = paths.begin();
2287 i != paths.end(); ++i) {
2288 std::string mediapath = *i;
2289 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2290 for (u32 j = 0; j < dirlist.size(); j++) {
2291 if (dirlist[j].dir) // Ignode dirs
2293 std::string filename = dirlist[j].name;
2294 // If name contains illegal characters, ignore the file
2295 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2296 infostream<<"Server: ignoring illegal file name: \""
2297 << filename << "\"" << std::endl;
2300 // If name is not in a supported format, ignore it
2301 const char *supported_ext[] = {
2302 ".png", ".jpg", ".bmp", ".tga",
2303 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2305 ".x", ".b3d", ".md2", ".obj",
2308 if (removeStringEnd(filename, supported_ext) == ""){
2309 infostream << "Server: ignoring unsupported file extension: \""
2310 << filename << "\"" << std::endl;
2313 // Ok, attempt to load the file and add to cache
2314 std::string filepath = mediapath + DIR_DELIM + filename;
2316 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2318 errorstream << "Server::fillMediaCache(): Could not open \""
2319 << filename << "\" for reading" << std::endl;
2322 std::ostringstream tmp_os(std::ios_base::binary);
2326 fis.read(buf, 1024);
2327 std::streamsize len = fis.gcount();
2328 tmp_os.write(buf, len);
2337 errorstream<<"Server::fillMediaCache(): Failed to read \""
2338 << filename << "\"" << std::endl;
2341 if(tmp_os.str().length() == 0) {
2342 errorstream << "Server::fillMediaCache(): Empty file \""
2343 << filepath << "\"" << std::endl;
2348 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2350 unsigned char *digest = sha1.getDigest();
2351 std::string sha1_base64 = base64_encode(digest, 20);
2352 std::string sha1_hex = hex_encode((char*)digest, 20);
2356 m_media[filename] = MediaInfo(filepath, sha1_base64);
2357 verbosestream << "Server: " << sha1_hex << " is " << filename
2363 void Server::sendMediaAnnouncement(u16 peer_id)
2365 DSTACK(FUNCTION_NAME);
2367 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2371 std::ostringstream os(std::ios_base::binary);
2373 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2374 pkt << (u16) m_media.size();
2376 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2377 i != m_media.end(); ++i) {
2378 pkt << i->first << i->second.sha1_digest;
2381 pkt << g_settings->get("remote_media");
2385 struct SendableMedia
2391 SendableMedia(const std::string &name_="", const std::string &path_="",
2392 const std::string &data_=""):
2399 void Server::sendRequestedMedia(u16 peer_id,
2400 const std::vector<std::string> &tosend)
2402 DSTACK(FUNCTION_NAME);
2404 verbosestream<<"Server::sendRequestedMedia(): "
2405 <<"Sending files to client"<<std::endl;
2409 // Put 5kB in one bunch (this is not accurate)
2410 u32 bytes_per_bunch = 5000;
2412 std::vector< std::vector<SendableMedia> > file_bunches;
2413 file_bunches.push_back(std::vector<SendableMedia>());
2415 u32 file_size_bunch_total = 0;
2417 for(std::vector<std::string>::const_iterator i = tosend.begin();
2418 i != tosend.end(); ++i) {
2419 const std::string &name = *i;
2421 if (m_media.find(name) == m_media.end()) {
2422 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2423 <<"unknown file \""<<(name)<<"\""<<std::endl;
2427 //TODO get path + name
2428 std::string tpath = m_media[name].path;
2431 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2432 if(fis.good() == false){
2433 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2434 <<tpath<<"\" for reading"<<std::endl;
2437 std::ostringstream tmp_os(std::ios_base::binary);
2441 fis.read(buf, 1024);
2442 std::streamsize len = fis.gcount();
2443 tmp_os.write(buf, len);
2444 file_size_bunch_total += len;
2453 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2454 <<name<<"\""<<std::endl;
2457 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2458 <<tname<<"\""<<std::endl;*/
2460 file_bunches[file_bunches.size()-1].push_back(
2461 SendableMedia(name, tpath, tmp_os.str()));
2463 // Start next bunch if got enough data
2464 if(file_size_bunch_total >= bytes_per_bunch) {
2465 file_bunches.push_back(std::vector<SendableMedia>());
2466 file_size_bunch_total = 0;
2471 /* Create and send packets */
2473 u16 num_bunches = file_bunches.size();
2474 for(u16 i = 0; i < num_bunches; i++) {
2477 u16 total number of texture bunches
2478 u16 index of this bunch
2479 u32 number of files in this bunch
2488 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2489 pkt << num_bunches << i << (u32) file_bunches[i].size();
2491 for(std::vector<SendableMedia>::iterator
2492 j = file_bunches[i].begin();
2493 j != file_bunches[i].end(); ++j) {
2495 pkt.putLongString(j->data);
2498 verbosestream << "Server::sendRequestedMedia(): bunch "
2499 << i << "/" << num_bunches
2500 << " files=" << file_bunches[i].size()
2501 << " size=" << pkt.getSize() << std::endl;
2506 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2508 if(m_detached_inventories.count(name) == 0) {
2509 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2512 Inventory *inv = m_detached_inventories[name];
2513 std::ostringstream os(std::ios_base::binary);
2515 os << serializeString(name);
2519 std::string s = os.str();
2521 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2522 pkt.putRawString(s.c_str(), s.size());
2524 const std::string &check = m_detached_inventories_player[name];
2525 if (peer_id == PEER_ID_INEXISTENT) {
2527 return m_clients.sendToAll(0, &pkt, true);
2528 RemotePlayer *p = m_env->getPlayer(check.c_str());
2530 m_clients.send(p->peer_id, 0, &pkt, true);
2532 if (check == "" || getPlayerName(peer_id) == check)
2537 void Server::sendDetachedInventories(u16 peer_id)
2539 DSTACK(FUNCTION_NAME);
2541 for(std::map<std::string, Inventory*>::iterator
2542 i = m_detached_inventories.begin();
2543 i != m_detached_inventories.end(); ++i) {
2544 const std::string &name = i->first;
2545 //Inventory *inv = i->second;
2546 sendDetachedInventory(name, peer_id);
2554 void Server::DiePlayer(u16 peer_id)
2556 DSTACK(FUNCTION_NAME);
2557 PlayerSAO *playersao = getPlayerSAO(peer_id);
2558 // In some rare cases this can be NULL -- if the player is disconnected
2559 // when a Lua function modifies l_punch, for example
2563 playersao->detachFromParent();
2565 infostream << "Server::DiePlayer(): Player "
2566 << playersao->getPlayer()->getName()
2567 << " dies" << std::endl;
2569 playersao->setHP(0);
2571 // Trigger scripted stuff
2572 m_script->on_dieplayer(playersao);
2574 SendPlayerHP(peer_id);
2575 SendDeathscreen(peer_id, false, v3f(0,0,0));
2578 void Server::RespawnPlayer(u16 peer_id)
2580 DSTACK(FUNCTION_NAME);
2582 PlayerSAO *playersao = getPlayerSAO(peer_id);
2585 infostream << "Server::RespawnPlayer(): Player "
2586 << playersao->getPlayer()->getName()
2587 << " respawns" << std::endl;
2589 playersao->setHP(PLAYER_MAX_HP);
2590 playersao->setBreath(PLAYER_MAX_BREATH);
2592 bool repositioned = m_script->on_respawnplayer(playersao);
2593 if (!repositioned) {
2594 v3f pos = findSpawnPos();
2595 // setPos will send the new position to client
2596 playersao->setPos(pos);
2599 SendPlayerHP(peer_id);
2603 void Server::DenySudoAccess(u16 peer_id)
2605 DSTACK(FUNCTION_NAME);
2607 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2612 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2613 const std::string &str_reason, bool reconnect)
2615 if (proto_ver >= 25) {
2616 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2618 std::wstring wreason = utf8_to_wide(
2619 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2620 accessDeniedStrings[(u8)reason]);
2621 SendAccessDenied_Legacy(peer_id, wreason);
2624 m_clients.event(peer_id, CSE_SetDenied);
2625 m_con.DisconnectPeer(peer_id);
2629 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2631 DSTACK(FUNCTION_NAME);
2633 SendAccessDenied(peer_id, reason, custom_reason);
2634 m_clients.event(peer_id, CSE_SetDenied);
2635 m_con.DisconnectPeer(peer_id);
2638 // 13/03/15: remove this function when protocol version 25 will become
2639 // the minimum version for MT users, maybe in 1 year
2640 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2642 DSTACK(FUNCTION_NAME);
2644 SendAccessDenied_Legacy(peer_id, reason);
2645 m_clients.event(peer_id, CSE_SetDenied);
2646 m_con.DisconnectPeer(peer_id);
2649 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2651 DSTACK(FUNCTION_NAME);
2654 RemoteClient* client = getClient(peer_id, CS_Invalid);
2656 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2658 // Right now, the auth mechs don't change between login and sudo mode.
2659 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2660 client->allowed_sudo_mechs = sudo_auth_mechs;
2662 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2663 << g_settings->getFloat("dedicated_server_step")
2667 m_clients.event(peer_id, CSE_AuthAccept);
2669 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2671 // We only support SRP right now
2672 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2674 resp_pkt << sudo_auth_mechs;
2676 m_clients.event(peer_id, CSE_SudoSuccess);
2680 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2682 DSTACK(FUNCTION_NAME);
2683 std::wstring message;
2686 Clear references to playing sounds
2688 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2689 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2690 ServerPlayingSound &psound = i->second;
2691 psound.clients.erase(peer_id);
2692 if (psound.clients.empty())
2693 m_playing_sounds.erase(i++);
2698 RemotePlayer *player = m_env->getPlayer(peer_id);
2700 /* Run scripts and remove from environment */
2701 if (player != NULL) {
2702 PlayerSAO *playersao = player->getPlayerSAO();
2705 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2707 playersao->disconnected();
2714 if(player != NULL && reason != CDR_DENY) {
2715 std::ostringstream os(std::ios_base::binary);
2716 std::vector<u16> clients = m_clients.getClientIDs();
2718 for(std::vector<u16>::iterator i = clients.begin();
2719 i != clients.end(); ++i) {
2721 RemotePlayer *player = m_env->getPlayer(*i);
2725 // Get name of player
2726 os << player->getName() << " ";
2729 std::string name = player->getName();
2730 actionstream << name << " "
2731 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2732 << " List of players: " << os.str() << std::endl;
2734 m_admin_chat->outgoing_queue.push_back(
2735 new ChatEventNick(CET_NICK_REMOVE, name));
2739 MutexAutoLock env_lock(m_env_mutex);
2740 m_clients.DeleteClient(peer_id);
2744 // Send leave chat message to all remaining clients
2745 if(message.length() != 0)
2746 SendChatMessage(PEER_ID_INEXISTENT,message);
2749 void Server::UpdateCrafting(RemotePlayer *player)
2751 DSTACK(FUNCTION_NAME);
2753 // Get a preview for crafting
2755 InventoryLocation loc;
2756 loc.setPlayer(player->getName());
2757 std::vector<ItemStack> output_replacements;
2758 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2759 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2760 (&player->inventory)->getList("craft"), loc);
2762 // Put the new preview in
2763 InventoryList *plist = player->inventory.getList("craftpreview");
2764 sanity_check(plist);
2765 sanity_check(plist->getSize() >= 1);
2766 plist->changeItem(0, preview);
2769 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2771 if (evt->type == CET_NICK_ADD) {
2772 // The terminal informed us of its nick choice
2773 m_admin_nick = ((ChatEventNick *)evt)->nick;
2774 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2775 errorstream << "You haven't set up an account." << std::endl
2776 << "Please log in using the client as '"
2777 << m_admin_nick << "' with a secure password." << std::endl
2778 << "Until then, you can't execute admin tasks via the console," << std::endl
2779 << "and everybody can claim the user account instead of you," << std::endl
2780 << "giving them full control over this server." << std::endl;
2783 assert(evt->type == CET_CHAT);
2784 handleAdminChat((ChatEventChat *)evt);
2788 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2789 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2791 // If something goes wrong, this player is to blame
2792 RollbackScopeActor rollback_scope(m_rollback,
2793 std::string("player:") + name);
2797 // Whether to send line to the player that sent the message, or to all players
2798 bool broadcast_line = true;
2801 bool ate = m_script->on_chat_message(name,
2802 wide_to_utf8(wmessage));
2803 // If script ate the message, don't proceed
2808 switch (player->canSendChatMessage()) {
2809 case RPLAYER_CHATRESULT_FLOODING: {
2810 std::wstringstream ws;
2811 ws << L"You cannot send more messages. You are limited to "
2812 << g_settings->getFloat("chat_message_limit_per_10sec")
2813 << L" messages per 10 seconds.";
2816 case RPLAYER_CHATRESULT_KICK:
2817 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2819 case RPLAYER_CHATRESULT_OK: break;
2820 default: FATAL_ERROR("Unhandled chat filtering result found.");
2824 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2825 return L"Your message exceed the maximum chat message limit set on the server. "
2826 L"It was refused. Send a shorter message";
2829 // Commands are implemented in Lua, so only catch invalid
2830 // commands that were not "eaten" and send an error back
2831 if (wmessage[0] == L'/') {
2832 std::wstring wcmd = wmessage.substr(1);
2833 broadcast_line = false;
2834 if (wcmd.length() == 0)
2835 line += L"-!- Empty command";
2837 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2839 if (check_shout_priv && !checkPriv(name, "shout")) {
2840 line += L"-!- You don't have permission to shout.";
2841 broadcast_line = false;
2851 Tell calling method to send the message to sender
2853 if (!broadcast_line) {
2857 Send the message to others
2859 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2861 std::vector<u16> clients = m_clients.getClientIDs();
2864 Send the message back to the inital sender
2865 if they are using protocol version >= 29
2868 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2869 if (player->protocol_version >= 29)
2870 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2872 for (u16 i = 0; i < clients.size(); i++) {
2873 u16 cid = clients[i];
2874 if (cid != peer_id_to_avoid_sending)
2875 SendChatMessage(cid, line);
2881 void Server::handleAdminChat(const ChatEventChat *evt)
2883 std::string name = evt->nick;
2884 std::wstring wname = utf8_to_wide(name);
2885 std::wstring wmessage = evt->evt_msg;
2887 std::wstring answer = handleChat(name, wname, wmessage);
2889 // If asked to send answer to sender
2890 if (!answer.empty()) {
2891 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2895 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2897 RemoteClient *client = getClientNoEx(peer_id,state_min);
2899 throw ClientNotFoundException("Client not found");
2903 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2905 return m_clients.getClientNoEx(peer_id, state_min);
2908 std::string Server::getPlayerName(u16 peer_id)
2910 RemotePlayer *player = m_env->getPlayer(peer_id);
2912 return "[id="+itos(peer_id)+"]";
2913 return player->getName();
2916 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2918 RemotePlayer *player = m_env->getPlayer(peer_id);
2921 return player->getPlayerSAO();
2924 std::wstring Server::getStatusString()
2926 std::wostringstream os(std::ios_base::binary);
2929 os<<L"version="<<narrow_to_wide(g_version_string);
2931 os<<L", uptime="<<m_uptime.get();
2933 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2934 // Information about clients
2937 std::vector<u16> clients = m_clients.getClientIDs();
2938 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2940 RemotePlayer *player = m_env->getPlayer(*i);
2941 // Get name of player
2942 std::wstring name = L"unknown";
2944 name = narrow_to_wide(player->getName());
2945 // Add name to information string
2953 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2954 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2955 if(g_settings->get("motd") != "")
2956 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2960 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2962 std::set<std::string> privs;
2963 m_script->getAuth(name, NULL, &privs);
2967 bool Server::checkPriv(const std::string &name, const std::string &priv)
2969 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2970 return (privs.count(priv) != 0);
2973 void Server::reportPrivsModified(const std::string &name)
2976 std::vector<u16> clients = m_clients.getClientIDs();
2977 for(std::vector<u16>::iterator i = clients.begin();
2978 i != clients.end(); ++i) {
2979 RemotePlayer *player = m_env->getPlayer(*i);
2980 reportPrivsModified(player->getName());
2983 RemotePlayer *player = m_env->getPlayer(name.c_str());
2986 SendPlayerPrivileges(player->peer_id);
2987 PlayerSAO *sao = player->getPlayerSAO();
2990 sao->updatePrivileges(
2991 getPlayerEffectivePrivs(name),
2996 void Server::reportInventoryFormspecModified(const std::string &name)
2998 RemotePlayer *player = m_env->getPlayer(name.c_str());
3001 SendPlayerInventoryFormspec(player->peer_id);
3004 void Server::setIpBanned(const std::string &ip, const std::string &name)
3006 m_banmanager->add(ip, name);
3009 void Server::unsetIpBanned(const std::string &ip_or_name)
3011 m_banmanager->remove(ip_or_name);
3014 std::string Server::getBanDescription(const std::string &ip_or_name)
3016 return m_banmanager->getBanDescription(ip_or_name);
3019 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3021 // m_env will be NULL if the server is initializing
3025 if (m_admin_nick == name && !m_admin_nick.empty()) {
3026 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3029 RemotePlayer *player = m_env->getPlayer(name);
3034 if (player->peer_id == PEER_ID_INEXISTENT)
3037 SendChatMessage(player->peer_id, msg);
3040 bool Server::showFormspec(const char *playername, const std::string &formspec,
3041 const std::string &formname)
3043 // m_env will be NULL if the server is initializing
3047 RemotePlayer *player = m_env->getPlayer(playername);
3051 SendShowFormspecMessage(player->peer_id, formspec, formname);
3055 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3060 u32 id = player->addHud(form);
3062 SendHUDAdd(player->peer_id, id, form);
3067 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3071 HudElement* todel = player->removeHud(id);
3078 SendHUDRemove(player->peer_id, id);
3082 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3087 SendHUDChange(player->peer_id, id, stat, data);
3091 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3096 SendHUDSetFlags(player->peer_id, flags, mask);
3097 player->hud_flags &= ~mask;
3098 player->hud_flags |= flags;
3100 PlayerSAO* playersao = player->getPlayerSAO();
3102 if (playersao == NULL)
3105 m_script->player_event(playersao, "hud_changed");
3109 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3114 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3117 player->setHotbarItemcount(hotbar_itemcount);
3118 std::ostringstream os(std::ios::binary);
3119 writeS32(os, hotbar_itemcount);
3120 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3124 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3129 player->setHotbarImage(name);
3130 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3133 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3137 return player->getHotbarImage();
3140 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3145 player->setHotbarSelectedImage(name);
3146 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3149 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3150 v2s32 animation_frames[4], f32 frame_speed)
3155 player->setLocalAnimations(animation_frames, frame_speed);
3156 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3160 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3165 player->eye_offset_first = first;
3166 player->eye_offset_third = third;
3167 SendEyeOffset(player->peer_id, first, third);
3171 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3172 const std::string &type, const std::vector<std::string> ¶ms)
3177 player->setSky(bgcolor, type, params);
3178 SendSetSky(player->peer_id, bgcolor, type, params);
3182 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3188 player->overrideDayNightRatio(do_override, ratio);
3189 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3193 void Server::notifyPlayers(const std::wstring &msg)
3195 SendChatMessage(PEER_ID_INEXISTENT,msg);
3198 void Server::spawnParticle(const std::string &playername, v3f pos,
3199 v3f velocity, v3f acceleration,
3200 float expirationtime, float size, bool
3201 collisiondetection, bool collision_removal,
3202 bool vertical, const std::string &texture,
3203 const struct TileAnimationParams &animation, u8 glow)
3205 // m_env will be NULL if the server is initializing
3209 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3210 if (playername != "") {
3211 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3214 peer_id = player->peer_id;
3215 proto_ver = player->protocol_version;
3218 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3219 expirationtime, size, collisiondetection,
3220 collision_removal, vertical, texture, animation, glow);
3223 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3224 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3225 float minexptime, float maxexptime, float minsize, float maxsize,
3226 bool collisiondetection, bool collision_removal,
3227 ServerActiveObject *attached, bool vertical, const std::string &texture,
3228 const std::string &playername, const struct TileAnimationParams &animation,
3231 // m_env will be NULL if the server is initializing
3235 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3236 if (playername != "") {
3237 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3240 peer_id = player->peer_id;
3241 proto_ver = player->protocol_version;
3244 u16 attached_id = attached ? attached->getId() : 0;
3247 if (attached_id == 0)
3248 id = m_env->addParticleSpawner(spawntime);
3250 id = m_env->addParticleSpawner(spawntime, attached_id);
3252 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3253 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3254 minexptime, maxexptime, minsize, maxsize,
3255 collisiondetection, collision_removal, attached_id, vertical,
3256 texture, id, animation, glow);
3261 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3263 // m_env will be NULL if the server is initializing
3265 throw ServerError("Can't delete particle spawners during initialisation!");
3267 u16 peer_id = PEER_ID_INEXISTENT;
3268 if (playername != "") {
3269 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3272 peer_id = player->peer_id;
3275 m_env->deleteParticleSpawner(id);
3276 SendDeleteParticleSpawner(peer_id, id);
3279 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3281 if(m_detached_inventories.count(name) > 0){
3282 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3283 delete m_detached_inventories[name];
3285 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3287 Inventory *inv = new Inventory(m_itemdef);
3289 m_detached_inventories[name] = inv;
3290 m_detached_inventories_player[name] = player;
3291 //TODO find a better way to do this
3292 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3296 // actions: time-reversed list
3297 // Return value: success/failure
3298 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3299 std::list<std::string> *log)
3301 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3302 ServerMap *map = (ServerMap*)(&m_env->getMap());
3304 // Fail if no actions to handle
3305 if(actions.empty()){
3306 log->push_back("Nothing to do.");
3313 for(std::list<RollbackAction>::const_iterator
3314 i = actions.begin();
3315 i != actions.end(); ++i)
3317 const RollbackAction &action = *i;
3319 bool success = action.applyRevert(map, this, this);
3322 std::ostringstream os;
3323 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3324 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3326 log->push_back(os.str());
3328 std::ostringstream os;
3329 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3330 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3332 log->push_back(os.str());
3336 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3337 <<" failed"<<std::endl;
3339 // Call it done if less than half failed
3340 return num_failed <= num_tried/2;
3343 // IGameDef interface
3345 IItemDefManager *Server::getItemDefManager()
3350 INodeDefManager *Server::getNodeDefManager()
3355 ICraftDefManager *Server::getCraftDefManager()
3360 u16 Server::allocateUnknownNodeId(const std::string &name)
3362 return m_nodedef->allocateDummy(name);
3365 MtEventManager *Server::getEventManager()
3370 IWritableItemDefManager *Server::getWritableItemDefManager()
3375 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3380 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3385 const ModSpec *Server::getModSpec(const std::string &modname) const
3387 std::vector<ModSpec>::const_iterator it;
3388 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3389 const ModSpec &mod = *it;
3390 if (mod.name == modname)
3396 void Server::getModNames(std::vector<std::string> &modlist)
3398 std::vector<ModSpec>::iterator it;
3399 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3400 modlist.push_back(it->name);
3403 std::string Server::getBuiltinLuaPath()
3405 return porting::path_share + DIR_DELIM + "builtin";
3408 v3f Server::findSpawnPos()
3410 ServerMap &map = m_env->getServerMap();
3412 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3413 return nodeposf * BS;
3416 bool is_good = false;
3418 // Try to find a good place a few times
3419 for(s32 i = 0; i < 4000 && !is_good; i++) {
3421 // We're going to try to throw the player to this position
3422 v2s16 nodepos2d = v2s16(
3423 -range + (myrand() % (range * 2)),
3424 -range + (myrand() % (range * 2)));
3426 // Get spawn level at point
3427 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3428 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3429 // the mapgen to signify an unsuitable spawn position
3430 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3433 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3436 for (s32 i = 0; i < 10; i++) {
3437 v3s16 blockpos = getNodeBlockPos(nodepos);
3438 map.emergeBlock(blockpos, true);
3439 content_t c = map.getNodeNoEx(nodepos).getContent();
3440 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3442 if (air_count >= 2) {
3443 nodeposf = intToFloat(nodepos, BS);
3444 // Don't spawn the player outside map boundaries
3445 if (objectpos_over_limit(nodeposf))
3458 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3460 bool newplayer = false;
3463 Try to get an existing player
3465 RemotePlayer *player = m_env->getPlayer(name);
3467 // If player is already connected, cancel
3468 if (player != NULL && player->peer_id != 0) {
3469 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3474 If player with the wanted peer_id already exists, cancel.
3476 if (m_env->getPlayer(peer_id) != NULL) {
3477 infostream<<"emergePlayer(): Player with wrong name but same"
3478 " peer_id already exists"<<std::endl;
3482 // Create a new player active object
3483 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3484 player = m_env->loadPlayer(name, playersao);
3486 // Create player if it doesn't exist
3489 player = new RemotePlayer(name, this->idef());
3490 // Set player position
3491 infostream<<"Server: Finding spawn place for player \""
3492 <<name<<"\""<<std::endl;
3493 playersao->setBasePosition(findSpawnPos());
3495 // Make sure the player is saved
3496 player->setModified(true);
3498 // Add player to environment
3499 m_env->addPlayer(player);
3501 // If the player exists, ensure that they respawn inside legal bounds
3502 // This fixes an assert crash when the player can't be added
3503 // to the environment
3504 if (objectpos_over_limit(playersao->getBasePosition())) {
3505 actionstream << "Respawn position for player \""
3506 << name << "\" outside limits, resetting" << std::endl;
3507 playersao->setBasePosition(findSpawnPos());
3511 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3513 player->protocol_version = proto_version;
3515 /* Clean up old HUD elements from previous sessions */
3518 /* Add object to environment */
3519 m_env->addActiveObject(playersao);
3523 m_script->on_newplayer(playersao);
3529 void dedicated_server_loop(Server &server, bool &kill)
3531 DSTACK(FUNCTION_NAME);
3533 verbosestream<<"dedicated_server_loop()"<<std::endl;
3535 IntervalLimiter m_profiler_interval;
3537 static const float steplen = g_settings->getFloat("dedicated_server_step");
3538 static const float profiler_print_interval =
3539 g_settings->getFloat("profiler_print_interval");
3542 // This is kind of a hack but can be done like this
3543 // because server.step() is very light
3545 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3546 sleep_ms((int)(steplen*1000.0));
3548 server.step(steplen);
3550 if(server.getShutdownRequested() || kill)
3552 infostream<<"Dedicated server quitting"<<std::endl;
3554 if(g_settings->getBool("server_announce"))
3555 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3563 if (profiler_print_interval != 0) {
3564 if(m_profiler_interval.step(steplen, profiler_print_interval))
3566 infostream<<"Profiler:"<<std::endl;
3567 g_profiler->print(infostream);
3568 g_profiler->clear();