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 "serverscripting.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,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_dedicated(dedicated),
158 m_async_fatal_error(""),
167 m_enable_rollback_recording(false),
170 m_itemdef(createItemDefManager()),
171 m_nodedef(createNodeDefManager()),
172 m_craftdef(createCraftDefManager()),
173 m_event(new EventManager()),
175 m_time_of_day_send_timer(0),
178 m_shutdown_requested(false),
179 m_shutdown_ask_reconnect(false),
181 m_ignore_map_edit_events(false),
182 m_ignore_map_edit_events_peer_id(0),
184 m_mod_storage_save_timer(10.0f)
186 m_liquid_transform_timer = 0.0;
187 m_liquid_transform_every = 1.0;
188 m_masterserver_timer = 0.0;
189 m_emergethread_trigger_timer = 0.0;
190 m_savemap_timer = 0.0;
193 m_lag = g_settings->getFloat("dedicated_server_step");
196 throw ServerError("Supplied empty world path");
198 if(!gamespec.isValid())
199 throw ServerError("Supplied invalid gamespec");
201 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
202 if(m_simple_singleplayer_mode)
203 infostream<<" in simple singleplayer mode"<<std::endl;
205 infostream<<std::endl;
206 infostream<<"- world: "<<m_path_world<<std::endl;
207 infostream<<"- game: "<<m_gamespec.path<<std::endl;
209 // Create world if it doesn't exist
210 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
211 throw ServerError("Failed to initialize world");
213 // Create server thread
214 m_thread = new ServerThread(this);
216 // Create emerge manager
217 m_emerge = new EmergeManager(this);
219 // Create ban manager
220 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
221 m_banmanager = new BanManager(ban_path);
223 ServerModConfiguration modconf(m_path_world);
224 m_mods = modconf.getMods();
225 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
226 // complain about mods with unsatisfied dependencies
227 if (!modconf.isConsistent()) {
228 modconf.printUnsatisfiedModsError();
231 Settings worldmt_settings;
232 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
233 worldmt_settings.readConfigFile(worldmt.c_str());
234 std::vector<std::string> names = worldmt_settings.getNames();
235 std::set<std::string> load_mod_names;
236 for(std::vector<std::string>::iterator it = names.begin();
237 it != names.end(); ++it) {
238 std::string name = *it;
239 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
240 load_mod_names.insert(name.substr(9));
242 // complain about mods declared to be loaded, but not found
243 for(std::vector<ModSpec>::iterator it = m_mods.begin();
244 it != m_mods.end(); ++it)
245 load_mod_names.erase((*it).name);
246 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
247 it != unsatisfied_mods.end(); ++it)
248 load_mod_names.erase((*it).name);
249 if(!load_mod_names.empty()) {
250 errorstream << "The following mods could not be found:";
251 for(std::set<std::string>::iterator it = load_mod_names.begin();
252 it != load_mod_names.end(); ++it)
253 errorstream << " \"" << (*it) << "\"";
254 errorstream << std::endl;
258 MutexAutoLock envlock(m_env_mutex);
260 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
261 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
263 // Initialize scripting
264 infostream<<"Server: Initializing Lua"<<std::endl;
266 m_script = new ServerScripting(this);
268 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
271 infostream << "Server: Loading mods: ";
272 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
273 i != m_mods.end(); ++i) {
274 infostream << (*i).name << " ";
276 infostream << std::endl;
277 // Load and run "mod" scripts
278 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
279 it != m_mods.end(); ++it) {
280 const ModSpec &mod = *it;
281 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
282 throw ModError("Error loading mod \"" + mod.name +
283 "\": Mod name does not follow naming conventions: "
284 "Only chararacters [a-z0-9_] are allowed.");
286 std::string script_path = mod.path + DIR_DELIM + "init.lua";
287 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
288 << script_path << "\"]" << std::endl;
289 m_script->loadMod(script_path, mod.name);
292 // Read Textures and calculate sha1 sums
295 // Apply item aliases in the node definition manager
296 m_nodedef->updateAliases(m_itemdef);
298 // Apply texture overrides from texturepack/override.txt
299 std::string texture_path = g_settings->get("texture_path");
300 if (texture_path != "" && fs::IsDir(texture_path))
301 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
303 m_nodedef->setNodeRegistrationStatus(true);
305 // Perform pending node name resolutions
306 m_nodedef->runNodeResolveCallbacks();
308 // unmap node names for connected nodeboxes
309 m_nodedef->mapNodeboxConnections();
311 // init the recipe hashes to speed up crafting
312 m_craftdef->initHashes(this);
314 // Initialize Environment
315 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
317 m_clients.setEnv(m_env);
319 if (!servermap->settings_mgr.makeMapgenParams())
320 FATAL_ERROR("Couldn't create any mapgen type");
322 // Initialize mapgens
323 m_emerge->initMapgens(servermap->getMapgenParams());
325 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
326 if (m_enable_rollback_recording) {
327 // Create rollback manager
328 m_rollback = new RollbackManager(m_path_world, this);
331 // Give environment reference to scripting api
332 m_script->initializeEnvironment(m_env);
334 // Register us to receive map edit events
335 servermap->addEventReceiver(this);
337 // If file exists, load environment metadata
338 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
339 infostream << "Server: Loading environment metadata" << std::endl;
342 m_env->loadDefaultMeta();
345 // Add some test ActiveBlockModifiers to environment
346 add_legacy_abms(m_env, m_nodedef);
348 m_liquid_transform_every = g_settings->getFloat("liquid_update");
349 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
354 infostream<<"Server destructing"<<std::endl;
356 // Send shutdown message
357 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
360 MutexAutoLock envlock(m_env_mutex);
362 // Execute script shutdown hooks
363 m_script->on_shutdown();
365 infostream << "Server: Saving players" << std::endl;
366 m_env->saveLoadedPlayers();
368 infostream << "Server: Kicking players" << std::endl;
369 std::string kick_msg;
370 bool reconnect = false;
371 if (getShutdownRequested()) {
372 reconnect = m_shutdown_ask_reconnect;
373 kick_msg = m_shutdown_msg;
375 if (kick_msg == "") {
376 kick_msg = g_settings->get("kick_msg_shutdown");
378 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
379 kick_msg, reconnect);
381 infostream << "Server: Saving environment metadata" << std::endl;
389 // stop all emerge threads before deleting players that may have
390 // requested blocks to be emerged
391 m_emerge->stopThreads();
393 // Delete things in the reverse order of creation
403 // Deinitialize scripting
404 infostream<<"Server: Deinitializing scripting"<<std::endl;
407 // Delete detached inventories
408 for (std::map<std::string, Inventory*>::iterator
409 i = m_detached_inventories.begin();
410 i != m_detached_inventories.end(); ++i) {
415 void Server::start(Address bind_addr)
417 DSTACK(FUNCTION_NAME);
419 m_bind_addr = bind_addr;
421 infostream<<"Starting server on "
422 << bind_addr.serializeString() <<"..."<<std::endl;
424 // Stop thread if already running
427 // Initialize connection
428 m_con.SetTimeoutMs(30);
429 m_con.Serve(bind_addr);
434 // ASCII art for the win!
436 <<" .__ __ __ "<<std::endl
437 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
438 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
439 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
440 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
441 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
442 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
443 actionstream<<"Server for gameid=\""<<m_gamespec.id
444 <<"\" listening on "<<bind_addr.serializeString()<<":"
445 <<bind_addr.getPort() << "."<<std::endl;
450 DSTACK(FUNCTION_NAME);
452 infostream<<"Server: Stopping and waiting threads"<<std::endl;
454 // Stop threads (set run=false first so both start stopping)
456 //m_emergethread.setRun(false);
458 //m_emergethread.stop();
460 infostream<<"Server: Threads stopped"<<std::endl;
463 void Server::step(float dtime)
465 DSTACK(FUNCTION_NAME);
470 MutexAutoLock lock(m_step_dtime_mutex);
471 m_step_dtime += dtime;
473 // Throw if fatal error occurred in thread
474 std::string async_err = m_async_fatal_error.get();
475 if (!async_err.empty()) {
476 if (!m_simple_singleplayer_mode) {
477 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
478 g_settings->get("kick_msg_crash"),
479 g_settings->getBool("ask_reconnect_on_crash"));
481 throw ServerError("AsyncErr: " + async_err);
485 void Server::AsyncRunStep(bool initial_step)
487 DSTACK(FUNCTION_NAME);
489 g_profiler->add("Server::AsyncRunStep (num)", 1);
493 MutexAutoLock lock1(m_step_dtime_mutex);
494 dtime = m_step_dtime;
498 // Send blocks to clients
502 if((dtime < 0.001) && (initial_step == false))
505 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
507 //infostream<<"Server steps "<<dtime<<std::endl;
508 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
511 MutexAutoLock lock1(m_step_dtime_mutex);
512 m_step_dtime -= dtime;
519 m_uptime.set(m_uptime.get() + dtime);
525 Update time of day and overall game time
527 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
530 Send to clients at constant intervals
533 m_time_of_day_send_timer -= dtime;
534 if(m_time_of_day_send_timer < 0.0) {
535 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
536 u16 time = m_env->getTimeOfDay();
537 float time_speed = g_settings->getFloat("time_speed");
538 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
542 MutexAutoLock lock(m_env_mutex);
543 // Figure out and report maximum lag to environment
544 float max_lag = m_env->getMaxLagEstimate();
545 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
547 if(dtime > 0.1 && dtime > max_lag * 2.0)
548 infostream<<"Server: Maximum lag peaked to "<<dtime
552 m_env->reportMaxLagEstimate(max_lag);
554 ScopeProfiler sp(g_profiler, "SEnv step");
555 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
559 static const float map_timer_and_unload_dtime = 2.92;
560 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
562 MutexAutoLock lock(m_env_mutex);
563 // Run Map's timers and unload unused data
564 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
565 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
566 g_settings->getFloat("server_unload_unused_data_timeout"),
571 Listen to the admin chat, if available
574 if (!m_admin_chat->command_queue.empty()) {
575 MutexAutoLock lock(m_env_mutex);
576 while (!m_admin_chat->command_queue.empty()) {
577 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
578 handleChatInterfaceEvent(evt);
582 m_admin_chat->outgoing_queue.push_back(
583 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
590 /* Transform liquids */
591 m_liquid_transform_timer += dtime;
592 if(m_liquid_transform_timer >= m_liquid_transform_every)
594 m_liquid_transform_timer -= m_liquid_transform_every;
596 MutexAutoLock lock(m_env_mutex);
598 ScopeProfiler sp(g_profiler, "Server: liquid transform");
600 std::map<v3s16, MapBlock*> modified_blocks;
601 m_env->getMap().transformLiquids(modified_blocks);
606 core::map<v3s16, MapBlock*> lighting_modified_blocks;
607 ServerMap &map = ((ServerMap&)m_env->getMap());
608 map.updateLighting(modified_blocks, lighting_modified_blocks);
610 // Add blocks modified by lighting to modified_blocks
611 for(core::map<v3s16, MapBlock*>::Iterator
612 i = lighting_modified_blocks.getIterator();
613 i.atEnd() == false; i++)
615 MapBlock *block = i.getNode()->getValue();
616 modified_blocks.insert(block->getPos(), block);
620 Set the modified blocks unsent for all the clients
622 if(!modified_blocks.empty())
624 SetBlocksNotSent(modified_blocks);
627 m_clients.step(dtime);
629 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
631 // send masterserver announce
633 float &counter = m_masterserver_timer;
634 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
635 g_settings->getBool("server_announce")) {
636 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
637 ServerList::AA_START,
638 m_bind_addr.getPort(),
639 m_clients.getPlayerNames(),
641 m_env->getGameTime(),
644 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
654 Check added and deleted active objects
657 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
658 MutexAutoLock envlock(m_env_mutex);
661 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
662 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
664 // Radius inside which objects are active
665 static const s16 radius =
666 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
668 // Radius inside which players are active
669 static const bool is_transfer_limited =
670 g_settings->exists("unlimited_player_transfer_distance") &&
671 !g_settings->getBool("unlimited_player_transfer_distance");
672 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
673 s16 player_radius = player_transfer_dist;
674 if (player_radius == 0 && is_transfer_limited)
675 player_radius = radius;
677 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
678 i != clients.end(); ++i) {
679 RemoteClient *client = i->second;
681 // If definitions and textures have not been sent, don't
682 // send objects either
683 if (client->getState() < CS_DefinitionsSent)
686 RemotePlayer *player = m_env->getPlayer(client->peer_id);
687 if (player == NULL) {
688 // This can happen if the client timeouts somehow
689 /*warningstream<<FUNCTION_NAME<<": Client "
691 <<" has no associated player"<<std::endl;*/
695 PlayerSAO *playersao = player->getPlayerSAO();
696 if (playersao == NULL)
699 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
700 if (my_radius <= 0) my_radius = radius;
701 //infostream << "Server: Active Radius " << my_radius << std::endl;
703 std::queue<u16> removed_objects;
704 std::queue<u16> added_objects;
705 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
706 client->m_known_objects, removed_objects);
707 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
708 client->m_known_objects, added_objects);
710 // Ignore if nothing happened
711 if (removed_objects.empty() && added_objects.empty()) {
715 std::string data_buffer;
719 // Handle removed objects
720 writeU16((u8*)buf, removed_objects.size());
721 data_buffer.append(buf, 2);
722 while (!removed_objects.empty()) {
724 u16 id = removed_objects.front();
725 ServerActiveObject* obj = m_env->getActiveObject(id);
727 // Add to data buffer for sending
728 writeU16((u8*)buf, id);
729 data_buffer.append(buf, 2);
731 // Remove from known objects
732 client->m_known_objects.erase(id);
734 if(obj && obj->m_known_by_count > 0)
735 obj->m_known_by_count--;
736 removed_objects.pop();
739 // Handle added objects
740 writeU16((u8*)buf, added_objects.size());
741 data_buffer.append(buf, 2);
742 while (!added_objects.empty()) {
744 u16 id = added_objects.front();
745 ServerActiveObject* obj = m_env->getActiveObject(id);
748 u8 type = ACTIVEOBJECT_TYPE_INVALID;
750 warningstream<<FUNCTION_NAME
751 <<": NULL object"<<std::endl;
753 type = obj->getSendType();
755 // Add to data buffer for sending
756 writeU16((u8*)buf, id);
757 data_buffer.append(buf, 2);
758 writeU8((u8*)buf, type);
759 data_buffer.append(buf, 1);
762 data_buffer.append(serializeLongString(
763 obj->getClientInitializationData(client->net_proto_version)));
765 data_buffer.append(serializeLongString(""));
767 // Add to known objects
768 client->m_known_objects.insert(id);
771 obj->m_known_by_count++;
776 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
777 verbosestream << "Server: Sent object remove/add: "
778 << removed_objects.size() << " removed, "
779 << added_objects.size() << " added, "
780 << "packet size is " << pktSize << std::endl;
784 m_mod_storage_save_timer -= dtime;
785 if (m_mod_storage_save_timer <= 0.0f) {
786 infostream << "Saving registered mod storages." << std::endl;
787 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
788 for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
789 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
790 if (it->second->isModified()) {
791 it->second->save(getModStoragePath());
801 MutexAutoLock envlock(m_env_mutex);
802 ScopeProfiler sp(g_profiler, "Server: sending object messages");
805 // Value = data sent by object
806 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
808 // Get active object messages from environment
810 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
814 std::vector<ActiveObjectMessage>* message_list = NULL;
815 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
816 n = buffered_messages.find(aom.id);
817 if (n == buffered_messages.end()) {
818 message_list = new std::vector<ActiveObjectMessage>;
819 buffered_messages[aom.id] = message_list;
822 message_list = n->second;
824 message_list->push_back(aom);
828 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
829 // Route data to every client
830 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
831 i != clients.end(); ++i) {
832 RemoteClient *client = i->second;
833 std::string reliable_data;
834 std::string unreliable_data;
835 // Go through all objects in message buffer
836 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
837 j = buffered_messages.begin();
838 j != buffered_messages.end(); ++j) {
839 // If object is not known by client, skip it
841 if (client->m_known_objects.find(id) == client->m_known_objects.end())
844 // Get message list of object
845 std::vector<ActiveObjectMessage>* list = j->second;
846 // Go through every message
847 for (std::vector<ActiveObjectMessage>::iterator
848 k = list->begin(); k != list->end(); ++k) {
849 // Compose the full new data with header
850 ActiveObjectMessage aom = *k;
851 std::string new_data;
854 writeU16((u8*)&buf[0], aom.id);
855 new_data.append(buf, 2);
857 new_data += serializeString(aom.datastring);
858 // Add data to buffer
860 reliable_data += new_data;
862 unreliable_data += new_data;
866 reliable_data and unreliable_data are now ready.
869 if(reliable_data.size() > 0) {
870 SendActiveObjectMessages(client->peer_id, reliable_data);
873 if(unreliable_data.size() > 0) {
874 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
879 // Clear buffered_messages
880 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
881 i = buffered_messages.begin();
882 i != buffered_messages.end(); ++i) {
888 Send queued-for-sending map edit events.
891 // We will be accessing the environment
892 MutexAutoLock lock(m_env_mutex);
894 // Don't send too many at a time
897 // Single change sending is disabled if queue size is not small
898 bool disable_single_change_sending = false;
899 if(m_unsent_map_edit_queue.size() >= 4)
900 disable_single_change_sending = true;
902 int event_count = m_unsent_map_edit_queue.size();
904 // We'll log the amount of each
907 while(m_unsent_map_edit_queue.size() != 0)
909 MapEditEvent* event = m_unsent_map_edit_queue.front();
910 m_unsent_map_edit_queue.pop();
912 // Players far away from the change are stored here.
913 // Instead of sending the changes, MapBlocks are set not sent
915 std::vector<u16> far_players;
917 switch (event->type) {
920 prof.add("MEET_ADDNODE", 1);
921 sendAddNode(event->p, event->n, event->already_known_by_peer,
922 &far_players, disable_single_change_sending ? 5 : 30,
923 event->type == MEET_ADDNODE);
925 case MEET_REMOVENODE:
926 prof.add("MEET_REMOVENODE", 1);
927 sendRemoveNode(event->p, event->already_known_by_peer,
928 &far_players, disable_single_change_sending ? 5 : 30);
930 case MEET_BLOCK_NODE_METADATA_CHANGED:
931 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
932 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
933 setBlockNotSent(event->p);
936 infostream << "Server: MEET_OTHER" << std::endl;
937 prof.add("MEET_OTHER", 1);
938 for(std::set<v3s16>::iterator
939 i = event->modified_blocks.begin();
940 i != event->modified_blocks.end(); ++i) {
945 prof.add("unknown", 1);
946 warningstream << "Server: Unknown MapEditEvent "
947 << ((u32)event->type) << std::endl;
952 Set blocks not sent to far players
954 if(!far_players.empty()) {
955 // Convert list format to that wanted by SetBlocksNotSent
956 std::map<v3s16, MapBlock*> modified_blocks2;
957 for(std::set<v3s16>::iterator
958 i = event->modified_blocks.begin();
959 i != event->modified_blocks.end(); ++i) {
960 modified_blocks2[*i] =
961 m_env->getMap().getBlockNoCreateNoEx(*i);
964 // Set blocks not sent
965 for(std::vector<u16>::iterator
966 i = far_players.begin();
967 i != far_players.end(); ++i) {
968 if(RemoteClient *client = getClient(*i))
969 client->SetBlocksNotSent(modified_blocks2);
975 /*// Don't send too many at a time
977 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
981 if(event_count >= 5){
982 infostream<<"Server: MapEditEvents:"<<std::endl;
983 prof.print(infostream);
984 } else if(event_count != 0){
985 verbosestream<<"Server: MapEditEvents:"<<std::endl;
986 prof.print(verbosestream);
992 Trigger emergethread (it somehow gets to a non-triggered but
993 bysy state sometimes)
996 float &counter = m_emergethread_trigger_timer;
998 if (counter >= 2.0) {
1001 m_emerge->startThreads();
1005 // Save map, players and auth stuff
1007 float &counter = m_savemap_timer;
1009 static const float save_interval =
1010 g_settings->getFloat("server_map_save_interval");
1011 if (counter >= save_interval) {
1013 MutexAutoLock lock(m_env_mutex);
1015 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1018 if (m_banmanager->isModified()) {
1019 m_banmanager->save();
1022 // Save changed parts of map
1023 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1026 m_env->saveLoadedPlayers();
1028 // Save environment metadata
1034 void Server::Receive()
1036 DSTACK(FUNCTION_NAME);
1037 SharedBuffer<u8> data;
1041 m_con.Receive(&pkt);
1042 peer_id = pkt.getPeerId();
1045 catch(con::InvalidIncomingDataException &e) {
1046 infostream<<"Server::Receive(): "
1047 "InvalidIncomingDataException: what()="
1048 <<e.what()<<std::endl;
1050 catch(SerializationError &e) {
1051 infostream<<"Server::Receive(): "
1052 "SerializationError: what()="
1053 <<e.what()<<std::endl;
1055 catch(ClientStateError &e) {
1056 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1057 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1058 L"Try reconnecting or updating your client");
1060 catch(con::PeerNotFoundException &e) {
1065 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1067 std::string playername = "";
1068 PlayerSAO *playersao = NULL;
1071 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1072 if (client != NULL) {
1073 playername = client->getName();
1074 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1076 } catch (std::exception &e) {
1082 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1084 // If failed, cancel
1085 if ((playersao == NULL) || (player == NULL)) {
1086 if (player && player->peer_id != 0) {
1087 actionstream << "Server: Failed to emerge player \"" << playername
1088 << "\" (player allocated to an another client)" << std::endl;
1089 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1090 L"name. If your client closed unexpectedly, try again in "
1093 errorstream << "Server: " << playername << ": Failed to emerge player"
1095 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1101 Send complete position information
1103 SendMovePlayer(peer_id);
1106 SendPlayerPrivileges(peer_id);
1108 // Send inventory formspec
1109 SendPlayerInventoryFormspec(peer_id);
1112 SendInventory(playersao);
1115 SendPlayerHPOrDie(playersao);
1118 SendPlayerBreath(playersao);
1120 // Show death screen if necessary
1121 if (playersao->isDead())
1122 SendDeathscreen(peer_id, false, v3f(0,0,0));
1124 // Note things in chat if not in simple singleplayer mode
1125 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1126 // Send information about server to player in chat
1127 SendChatMessage(peer_id, getStatusString());
1129 Address addr = getPeerAddress(player->peer_id);
1130 std::string ip_str = addr.serializeString();
1131 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1136 const std::vector<std::string> &names = m_clients.getPlayerNames();
1138 actionstream << player->getName() << " joins game. List of players: ";
1140 for (std::vector<std::string>::const_iterator i = names.begin();
1141 i != names.end(); ++i) {
1142 actionstream << *i << " ";
1145 actionstream << player->getName() <<std::endl;
1150 inline void Server::handleCommand(NetworkPacket* pkt)
1152 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1153 (this->*opHandle.handler)(pkt);
1156 void Server::ProcessData(NetworkPacket *pkt)
1158 DSTACK(FUNCTION_NAME);
1159 // Environment is locked first.
1160 MutexAutoLock envlock(m_env_mutex);
1162 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1163 u32 peer_id = pkt->getPeerId();
1166 Address address = getPeerAddress(peer_id);
1167 std::string addr_s = address.serializeString();
1169 if(m_banmanager->isIpBanned(addr_s)) {
1170 std::string ban_name = m_banmanager->getBanName(addr_s);
1171 infostream << "Server: A banned client tried to connect from "
1172 << addr_s << "; banned name was "
1173 << ban_name << std::endl;
1174 // This actually doesn't seem to transfer to the client
1175 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1176 + utf8_to_wide(ban_name));
1180 catch(con::PeerNotFoundException &e) {
1182 * no peer for this packet found
1183 * most common reason is peer timeout, e.g. peer didn't
1184 * respond for some time, your server was overloaded or
1187 infostream << "Server::ProcessData(): Canceling: peer "
1188 << peer_id << " not found" << std::endl;
1193 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1195 // Command must be handled into ToServerCommandHandler
1196 if (command >= TOSERVER_NUM_MSG_TYPES) {
1197 infostream << "Server: Ignoring unknown command "
1198 << command << std::endl;
1202 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1207 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1209 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1210 errorstream << "Server::ProcessData(): Cancelling: Peer"
1211 " serialization format invalid or not initialized."
1212 " Skipping incoming command=" << command << std::endl;
1216 /* Handle commands related to client startup */
1217 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1222 if (m_clients.getClientState(peer_id) < CS_Active) {
1223 if (command == TOSERVER_PLAYERPOS) return;
1225 errorstream << "Got packet command: " << command << " for peer id "
1226 << peer_id << " but client isn't active yet. Dropping packet "
1232 } catch (SendFailedException &e) {
1233 errorstream << "Server::ProcessData(): SendFailedException: "
1234 << "what=" << e.what()
1236 } catch (PacketError &e) {
1237 actionstream << "Server::ProcessData(): PacketError: "
1238 << "what=" << e.what()
1243 void Server::setTimeOfDay(u32 time)
1245 m_env->setTimeOfDay(time);
1246 m_time_of_day_send_timer = 0;
1249 void Server::onMapEditEvent(MapEditEvent *event)
1251 if(m_ignore_map_edit_events)
1253 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1255 MapEditEvent *e = event->clone();
1256 m_unsent_map_edit_queue.push(e);
1259 Inventory* Server::getInventory(const InventoryLocation &loc)
1262 case InventoryLocation::UNDEFINED:
1263 case InventoryLocation::CURRENT_PLAYER:
1265 case InventoryLocation::PLAYER:
1267 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1270 PlayerSAO *playersao = player->getPlayerSAO();
1273 return playersao->getInventory();
1276 case InventoryLocation::NODEMETA:
1278 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1281 return meta->getInventory();
1284 case InventoryLocation::DETACHED:
1286 if(m_detached_inventories.count(loc.name) == 0)
1288 return m_detached_inventories[loc.name];
1292 sanity_check(false); // abort
1297 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1300 case InventoryLocation::UNDEFINED:
1302 case InventoryLocation::PLAYER:
1307 RemotePlayer *player =
1308 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1313 PlayerSAO *playersao = player->getPlayerSAO();
1317 SendInventory(playersao);
1320 case InventoryLocation::NODEMETA:
1322 v3s16 blockpos = getNodeBlockPos(loc.p);
1324 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1326 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1328 setBlockNotSent(blockpos);
1331 case InventoryLocation::DETACHED:
1333 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1337 sanity_check(false); // abort
1342 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1344 std::vector<u16> clients = m_clients.getClientIDs();
1346 // Set the modified blocks unsent for all the clients
1347 for (std::vector<u16>::iterator i = clients.begin();
1348 i != clients.end(); ++i) {
1349 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1350 client->SetBlocksNotSent(block);
1355 void Server::peerAdded(con::Peer *peer)
1357 DSTACK(FUNCTION_NAME);
1358 verbosestream<<"Server::peerAdded(): peer->id="
1359 <<peer->id<<std::endl;
1362 c.type = con::PEER_ADDED;
1363 c.peer_id = peer->id;
1365 m_peer_change_queue.push(c);
1368 void Server::deletingPeer(con::Peer *peer, bool timeout)
1370 DSTACK(FUNCTION_NAME);
1371 verbosestream<<"Server::deletingPeer(): peer->id="
1372 <<peer->id<<", timeout="<<timeout<<std::endl;
1374 m_clients.event(peer->id, CSE_Disconnect);
1376 c.type = con::PEER_REMOVED;
1377 c.peer_id = peer->id;
1378 c.timeout = timeout;
1379 m_peer_change_queue.push(c);
1382 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1384 *retval = m_con.getPeerStat(peer_id,type);
1385 if (*retval == -1) return false;
1389 bool Server::getClientInfo(
1398 std::string* vers_string
1401 *state = m_clients.getClientState(peer_id);
1403 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1405 if (client == NULL) {
1410 *uptime = client->uptime();
1411 *ser_vers = client->serialization_version;
1412 *prot_vers = client->net_proto_version;
1414 *major = client->getMajor();
1415 *minor = client->getMinor();
1416 *patch = client->getPatch();
1417 *vers_string = client->getPatch();
1424 void Server::handlePeerChanges()
1426 while(m_peer_change_queue.size() > 0)
1428 con::PeerChange c = m_peer_change_queue.front();
1429 m_peer_change_queue.pop();
1431 verbosestream<<"Server: Handling peer change: "
1432 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1437 case con::PEER_ADDED:
1438 m_clients.CreateClient(c.peer_id);
1441 case con::PEER_REMOVED:
1442 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1446 FATAL_ERROR("Invalid peer change event received!");
1452 void Server::printToConsoleOnly(const std::string &text)
1455 m_admin_chat->outgoing_queue.push_back(
1456 new ChatEventChat("", utf8_to_wide(text)));
1458 std::cout << text << std::endl;
1462 void Server::Send(NetworkPacket* pkt)
1464 m_clients.send(pkt->getPeerId(),
1465 clientCommandFactoryTable[pkt->getCommand()].channel,
1467 clientCommandFactoryTable[pkt->getCommand()].reliable);
1470 void Server::SendMovement(u16 peer_id)
1472 DSTACK(FUNCTION_NAME);
1473 std::ostringstream os(std::ios_base::binary);
1475 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1477 pkt << g_settings->getFloat("movement_acceleration_default");
1478 pkt << g_settings->getFloat("movement_acceleration_air");
1479 pkt << g_settings->getFloat("movement_acceleration_fast");
1480 pkt << g_settings->getFloat("movement_speed_walk");
1481 pkt << g_settings->getFloat("movement_speed_crouch");
1482 pkt << g_settings->getFloat("movement_speed_fast");
1483 pkt << g_settings->getFloat("movement_speed_climb");
1484 pkt << g_settings->getFloat("movement_speed_jump");
1485 pkt << g_settings->getFloat("movement_liquid_fluidity");
1486 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1487 pkt << g_settings->getFloat("movement_liquid_sink");
1488 pkt << g_settings->getFloat("movement_gravity");
1493 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1495 if (!g_settings->getBool("enable_damage"))
1498 u16 peer_id = playersao->getPeerID();
1499 bool is_alive = playersao->getHP() > 0;
1502 SendPlayerHP(peer_id);
1507 void Server::SendHP(u16 peer_id, u8 hp)
1509 DSTACK(FUNCTION_NAME);
1511 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1516 void Server::SendBreath(u16 peer_id, u16 breath)
1518 DSTACK(FUNCTION_NAME);
1520 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1521 pkt << (u16) breath;
1525 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1526 const std::string &custom_reason, bool reconnect)
1528 assert(reason < SERVER_ACCESSDENIED_MAX);
1530 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1532 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1533 pkt << custom_reason;
1534 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1535 reason == SERVER_ACCESSDENIED_CRASH)
1536 pkt << custom_reason << (u8)reconnect;
1540 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1542 DSTACK(FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1549 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1550 v3f camera_point_target)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1555 pkt << set_camera_point_target << camera_point_target;
1559 void Server::SendItemDef(u16 peer_id,
1560 IItemDefManager *itemdef, u16 protocol_version)
1562 DSTACK(FUNCTION_NAME);
1564 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1568 u32 length of the next item
1569 zlib-compressed serialized ItemDefManager
1571 std::ostringstream tmp_os(std::ios::binary);
1572 itemdef->serialize(tmp_os, protocol_version);
1573 std::ostringstream tmp_os2(std::ios::binary);
1574 compressZlib(tmp_os.str(), tmp_os2);
1575 pkt.putLongString(tmp_os2.str());
1578 verbosestream << "Server: Sending item definitions to id(" << peer_id
1579 << "): size=" << pkt.getSize() << std::endl;
1584 void Server::SendNodeDef(u16 peer_id,
1585 INodeDefManager *nodedef, u16 protocol_version)
1587 DSTACK(FUNCTION_NAME);
1589 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1593 u32 length of the next item
1594 zlib-compressed serialized NodeDefManager
1596 std::ostringstream tmp_os(std::ios::binary);
1597 nodedef->serialize(tmp_os, protocol_version);
1598 std::ostringstream tmp_os2(std::ios::binary);
1599 compressZlib(tmp_os.str(), tmp_os2);
1601 pkt.putLongString(tmp_os2.str());
1604 verbosestream << "Server: Sending node definitions to id(" << peer_id
1605 << "): size=" << pkt.getSize() << std::endl;
1611 Non-static send methods
1614 void Server::SendInventory(PlayerSAO* playerSAO)
1616 DSTACK(FUNCTION_NAME);
1618 UpdateCrafting(playerSAO->getPlayer());
1624 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1626 std::ostringstream os;
1627 playerSAO->getInventory()->serialize(os);
1629 std::string s = os.str();
1631 pkt.putRawString(s.c_str(), s.size());
1635 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1637 DSTACK(FUNCTION_NAME);
1639 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1642 if (peer_id != PEER_ID_INEXISTENT) {
1646 m_clients.sendToAll(0, &pkt, true);
1650 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1651 const std::string &formname)
1653 DSTACK(FUNCTION_NAME);
1655 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1656 if (formspec == "" ){
1657 //the client should close the formspec
1658 pkt.putLongString("");
1660 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1667 // Spawns a particle on peer with peer_id
1668 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1669 v3f pos, v3f velocity, v3f acceleration,
1670 float expirationtime, float size, bool collisiondetection,
1671 bool collision_removal,
1672 bool vertical, const std::string &texture,
1673 const struct TileAnimationParams &animation, u8 glow)
1675 DSTACK(FUNCTION_NAME);
1676 if (peer_id == PEER_ID_INEXISTENT) {
1677 // This sucks and should be replaced by a better solution in a refactor:
1678 std::vector<u16> clients = m_clients.getClientIDs();
1679 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1680 RemotePlayer *player = m_env->getPlayer(*i);
1683 SendSpawnParticle(*i, player->protocol_version,
1684 pos, velocity, acceleration,
1685 expirationtime, size, collisiondetection,
1686 collision_removal, vertical, texture, animation, glow);
1691 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1693 pkt << pos << velocity << acceleration << expirationtime
1694 << size << collisiondetection;
1695 pkt.putLongString(texture);
1697 pkt << collision_removal;
1698 // This is horrible but required (why are there two ways to serialize pkts?)
1699 std::ostringstream os(std::ios_base::binary);
1700 animation.serialize(os, protocol_version);
1701 pkt.putRawString(os.str());
1707 // Adds a ParticleSpawner on peer with peer_id
1708 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1709 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1710 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1711 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1712 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1713 const struct TileAnimationParams &animation, u8 glow)
1715 DSTACK(FUNCTION_NAME);
1716 if (peer_id == PEER_ID_INEXISTENT) {
1717 // This sucks and should be replaced:
1718 std::vector<u16> clients = m_clients.getClientIDs();
1719 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1720 RemotePlayer *player = m_env->getPlayer(*i);
1723 SendAddParticleSpawner(*i, player->protocol_version,
1724 amount, spawntime, minpos, maxpos,
1725 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1726 minsize, maxsize, collisiondetection, collision_removal,
1727 attached_id, vertical, texture, id, animation, glow);
1732 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1734 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1735 << minacc << maxacc << minexptime << maxexptime << minsize
1736 << maxsize << collisiondetection;
1738 pkt.putLongString(texture);
1740 pkt << id << vertical;
1741 pkt << collision_removal;
1743 // This is horrible but required
1744 std::ostringstream os(std::ios_base::binary);
1745 animation.serialize(os, protocol_version);
1746 pkt.putRawString(os.str());
1752 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1754 DSTACK(FUNCTION_NAME);
1756 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1758 // Ugly error in this packet
1761 if (peer_id != PEER_ID_INEXISTENT) {
1765 m_clients.sendToAll(0, &pkt, true);
1770 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1772 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1774 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1775 << form->text << form->number << form->item << form->dir
1776 << form->align << form->offset << form->world_pos << form->size;
1781 void Server::SendHUDRemove(u16 peer_id, u32 id)
1783 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1788 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1790 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1791 pkt << id << (u8) stat;
1795 case HUD_STAT_SCALE:
1796 case HUD_STAT_ALIGN:
1797 case HUD_STAT_OFFSET:
1798 pkt << *(v2f *) value;
1802 pkt << *(std::string *) value;
1804 case HUD_STAT_WORLD_POS:
1805 pkt << *(v3f *) value;
1808 pkt << *(v2s32 *) value;
1810 case HUD_STAT_NUMBER:
1814 pkt << *(u32 *) value;
1821 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1823 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1825 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1827 pkt << flags << mask;
1832 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1834 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1835 pkt << param << value;
1839 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1840 const std::string &type, const std::vector<std::string> ¶ms)
1842 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1843 pkt << bgcolor << type << (u16) params.size();
1845 for(size_t i=0; i<params.size(); i++)
1851 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1854 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1857 pkt << do_override << (u16) (ratio * 65535);
1862 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1864 DSTACK(FUNCTION_NAME);
1866 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1867 pkt << time << time_speed;
1869 if (peer_id == PEER_ID_INEXISTENT) {
1870 m_clients.sendToAll(0, &pkt, true);
1877 void Server::SendPlayerHP(u16 peer_id)
1879 DSTACK(FUNCTION_NAME);
1880 PlayerSAO *playersao = getPlayerSAO(peer_id);
1881 // In some rare case if the player is disconnected
1882 // while Lua call l_punch, for example, this can be NULL
1886 SendHP(peer_id, playersao->getHP());
1887 m_script->player_event(playersao,"health_changed");
1889 // Send to other clients
1890 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1891 ActiveObjectMessage aom(playersao->getId(), true, str);
1892 playersao->m_messages_out.push(aom);
1895 void Server::SendPlayerBreath(PlayerSAO *sao)
1897 DSTACK(FUNCTION_NAME);
1900 m_script->player_event(sao, "breath_changed");
1901 SendBreath(sao->getPeerID(), sao->getBreath());
1904 void Server::SendMovePlayer(u16 peer_id)
1906 DSTACK(FUNCTION_NAME);
1907 RemotePlayer *player = m_env->getPlayer(peer_id);
1909 PlayerSAO *sao = player->getPlayerSAO();
1912 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1913 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1916 v3f pos = sao->getBasePosition();
1917 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1918 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1919 << " pitch=" << sao->getPitch()
1920 << " yaw=" << sao->getYaw()
1927 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1929 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1932 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1933 << animation_frames[3] << animation_speed;
1938 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1940 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1941 pkt << first << third;
1944 void Server::SendPlayerPrivileges(u16 peer_id)
1946 RemotePlayer *player = m_env->getPlayer(peer_id);
1948 if(player->peer_id == PEER_ID_INEXISTENT)
1951 std::set<std::string> privs;
1952 m_script->getAuth(player->getName(), NULL, &privs);
1954 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1955 pkt << (u16) privs.size();
1957 for(std::set<std::string>::const_iterator i = privs.begin();
1958 i != privs.end(); ++i) {
1965 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1967 RemotePlayer *player = m_env->getPlayer(peer_id);
1969 if(player->peer_id == PEER_ID_INEXISTENT)
1972 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1973 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1977 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1979 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1980 pkt.putRawString(datas.c_str(), datas.size());
1982 return pkt.getSize();
1985 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1987 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1988 datas.size(), peer_id);
1990 pkt.putRawString(datas.c_str(), datas.size());
1992 m_clients.send(pkt.getPeerId(),
1993 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1998 s32 Server::playSound(const SimpleSoundSpec &spec,
1999 const ServerSoundParams ¶ms)
2001 // Find out initial position of sound
2002 bool pos_exists = false;
2003 v3f pos = params.getPos(m_env, &pos_exists);
2004 // If position is not found while it should be, cancel sound
2005 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2008 // Filter destination clients
2009 std::vector<u16> dst_clients;
2010 if(params.to_player != "")
2012 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2014 infostream<<"Server::playSound: Player \""<<params.to_player
2015 <<"\" not found"<<std::endl;
2018 if(player->peer_id == PEER_ID_INEXISTENT){
2019 infostream<<"Server::playSound: Player \""<<params.to_player
2020 <<"\" not connected"<<std::endl;
2023 dst_clients.push_back(player->peer_id);
2026 std::vector<u16> clients = m_clients.getClientIDs();
2028 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2029 RemotePlayer *player = m_env->getPlayer(*i);
2033 PlayerSAO *sao = player->getPlayerSAO();
2038 if(sao->getBasePosition().getDistanceFrom(pos) >
2039 params.max_hear_distance)
2042 dst_clients.push_back(*i);
2046 if(dst_clients.empty())
2050 s32 id = m_next_sound_id++;
2051 // The sound will exist as a reference in m_playing_sounds
2052 m_playing_sounds[id] = ServerPlayingSound();
2053 ServerPlayingSound &psound = m_playing_sounds[id];
2054 psound.params = params;
2056 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2057 pkt << id << spec.name << (float) (spec.gain * params.gain)
2058 << (u8) params.type << pos << params.object << params.loop;
2060 for(std::vector<u16>::iterator i = dst_clients.begin();
2061 i != dst_clients.end(); ++i) {
2062 psound.clients.insert(*i);
2063 m_clients.send(*i, 0, &pkt, true);
2067 void Server::stopSound(s32 handle)
2069 // Get sound reference
2070 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2071 if (i == m_playing_sounds.end())
2073 ServerPlayingSound &psound = i->second;
2075 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2078 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2079 i != psound.clients.end(); ++i) {
2081 m_clients.send(*i, 0, &pkt, true);
2083 // Remove sound reference
2084 m_playing_sounds.erase(i);
2087 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2088 std::vector<u16> *far_players, float far_d_nodes)
2090 float maxd = far_d_nodes*BS;
2091 v3f p_f = intToFloat(p, BS);
2093 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2096 std::vector<u16> clients = m_clients.getClientIDs();
2097 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2100 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2101 PlayerSAO *sao = player->getPlayerSAO();
2105 // If player is far away, only set modified blocks not sent
2106 v3f player_pos = sao->getBasePosition();
2107 if (player_pos.getDistanceFrom(p_f) > maxd) {
2108 far_players->push_back(*i);
2115 m_clients.send(*i, 0, &pkt, true);
2119 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2120 std::vector<u16> *far_players, float far_d_nodes,
2121 bool remove_metadata)
2123 float maxd = far_d_nodes*BS;
2124 v3f p_f = intToFloat(p, BS);
2126 std::vector<u16> clients = m_clients.getClientIDs();
2127 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2130 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2131 PlayerSAO *sao = player->getPlayerSAO();
2135 // If player is far away, only set modified blocks not sent
2136 v3f player_pos = sao->getBasePosition();
2137 if(player_pos.getDistanceFrom(p_f) > maxd) {
2138 far_players->push_back(*i);
2144 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2146 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2148 pkt << p << n.param0 << n.param1 << n.param2
2149 << (u8) (remove_metadata ? 0 : 1);
2154 if (pkt.getSize() > 0)
2155 m_clients.send(*i, 0, &pkt, true);
2159 void Server::setBlockNotSent(v3s16 p)
2161 std::vector<u16> clients = m_clients.getClientIDs();
2163 for(std::vector<u16>::iterator i = clients.begin();
2164 i != clients.end(); ++i) {
2165 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2166 client->SetBlockNotSent(p);
2171 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2173 DSTACK(FUNCTION_NAME);
2175 v3s16 p = block->getPos();
2178 Create a packet with the block in the right format
2181 std::ostringstream os(std::ios_base::binary);
2182 block->serialize(os, ver, false);
2183 block->serializeNetworkSpecific(os);
2184 std::string s = os.str();
2186 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2189 pkt.putRawString(s.c_str(), s.size());
2193 void Server::SendBlocks(float dtime)
2195 DSTACK(FUNCTION_NAME);
2197 MutexAutoLock envlock(m_env_mutex);
2198 //TODO check if one big lock could be faster then multiple small ones
2200 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2202 std::vector<PrioritySortedBlockTransfer> queue;
2204 s32 total_sending = 0;
2207 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2209 std::vector<u16> clients = m_clients.getClientIDs();
2212 for(std::vector<u16>::iterator i = clients.begin();
2213 i != clients.end(); ++i) {
2214 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2219 total_sending += client->SendingCount();
2220 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2226 // Lowest priority number comes first.
2227 // Lowest is most important.
2228 std::sort(queue.begin(), queue.end());
2231 for(u32 i=0; i<queue.size(); i++)
2233 //TODO: Calculate limit dynamically
2234 if(total_sending >= g_settings->getS32
2235 ("max_simultaneous_block_sends_server_total"))
2238 PrioritySortedBlockTransfer q = queue[i];
2240 MapBlock *block = NULL;
2243 block = m_env->getMap().getBlockNoCreate(q.pos);
2245 catch(InvalidPositionException &e)
2250 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2255 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2257 client->SentBlock(q.pos);
2263 void Server::fillMediaCache()
2265 DSTACK(FUNCTION_NAME);
2267 infostream<<"Server: Calculating media file checksums"<<std::endl;
2269 // Collect all media file paths
2270 std::vector<std::string> paths;
2271 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2272 i != m_mods.end(); ++i) {
2273 const ModSpec &mod = *i;
2274 paths.push_back(mod.path + DIR_DELIM + "textures");
2275 paths.push_back(mod.path + DIR_DELIM + "sounds");
2276 paths.push_back(mod.path + DIR_DELIM + "media");
2277 paths.push_back(mod.path + DIR_DELIM + "models");
2279 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2281 // Collect media file information from paths into cache
2282 for(std::vector<std::string>::iterator i = paths.begin();
2283 i != paths.end(); ++i) {
2284 std::string mediapath = *i;
2285 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2286 for (u32 j = 0; j < dirlist.size(); j++) {
2287 if (dirlist[j].dir) // Ignode dirs
2289 std::string filename = dirlist[j].name;
2290 // If name contains illegal characters, ignore the file
2291 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2292 infostream<<"Server: ignoring illegal file name: \""
2293 << filename << "\"" << std::endl;
2296 // If name is not in a supported format, ignore it
2297 const char *supported_ext[] = {
2298 ".png", ".jpg", ".bmp", ".tga",
2299 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2301 ".x", ".b3d", ".md2", ".obj",
2304 if (removeStringEnd(filename, supported_ext) == ""){
2305 infostream << "Server: ignoring unsupported file extension: \""
2306 << filename << "\"" << std::endl;
2309 // Ok, attempt to load the file and add to cache
2310 std::string filepath = mediapath + DIR_DELIM + filename;
2312 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2314 errorstream << "Server::fillMediaCache(): Could not open \""
2315 << filename << "\" for reading" << std::endl;
2318 std::ostringstream tmp_os(std::ios_base::binary);
2322 fis.read(buf, 1024);
2323 std::streamsize len = fis.gcount();
2324 tmp_os.write(buf, len);
2333 errorstream<<"Server::fillMediaCache(): Failed to read \""
2334 << filename << "\"" << std::endl;
2337 if(tmp_os.str().length() == 0) {
2338 errorstream << "Server::fillMediaCache(): Empty file \""
2339 << filepath << "\"" << std::endl;
2344 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2346 unsigned char *digest = sha1.getDigest();
2347 std::string sha1_base64 = base64_encode(digest, 20);
2348 std::string sha1_hex = hex_encode((char*)digest, 20);
2352 m_media[filename] = MediaInfo(filepath, sha1_base64);
2353 verbosestream << "Server: " << sha1_hex << " is " << filename
2359 void Server::sendMediaAnnouncement(u16 peer_id)
2361 DSTACK(FUNCTION_NAME);
2363 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2367 std::ostringstream os(std::ios_base::binary);
2369 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2370 pkt << (u16) m_media.size();
2372 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2373 i != m_media.end(); ++i) {
2374 pkt << i->first << i->second.sha1_digest;
2377 pkt << g_settings->get("remote_media");
2381 struct SendableMedia
2387 SendableMedia(const std::string &name_="", const std::string &path_="",
2388 const std::string &data_=""):
2395 void Server::sendRequestedMedia(u16 peer_id,
2396 const std::vector<std::string> &tosend)
2398 DSTACK(FUNCTION_NAME);
2400 verbosestream<<"Server::sendRequestedMedia(): "
2401 <<"Sending files to client"<<std::endl;
2405 // Put 5kB in one bunch (this is not accurate)
2406 u32 bytes_per_bunch = 5000;
2408 std::vector< std::vector<SendableMedia> > file_bunches;
2409 file_bunches.push_back(std::vector<SendableMedia>());
2411 u32 file_size_bunch_total = 0;
2413 for(std::vector<std::string>::const_iterator i = tosend.begin();
2414 i != tosend.end(); ++i) {
2415 const std::string &name = *i;
2417 if (m_media.find(name) == m_media.end()) {
2418 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2419 <<"unknown file \""<<(name)<<"\""<<std::endl;
2423 //TODO get path + name
2424 std::string tpath = m_media[name].path;
2427 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2428 if(fis.good() == false){
2429 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2430 <<tpath<<"\" for reading"<<std::endl;
2433 std::ostringstream tmp_os(std::ios_base::binary);
2437 fis.read(buf, 1024);
2438 std::streamsize len = fis.gcount();
2439 tmp_os.write(buf, len);
2440 file_size_bunch_total += len;
2449 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2450 <<name<<"\""<<std::endl;
2453 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2454 <<tname<<"\""<<std::endl;*/
2456 file_bunches[file_bunches.size()-1].push_back(
2457 SendableMedia(name, tpath, tmp_os.str()));
2459 // Start next bunch if got enough data
2460 if(file_size_bunch_total >= bytes_per_bunch) {
2461 file_bunches.push_back(std::vector<SendableMedia>());
2462 file_size_bunch_total = 0;
2467 /* Create and send packets */
2469 u16 num_bunches = file_bunches.size();
2470 for(u16 i = 0; i < num_bunches; i++) {
2473 u16 total number of texture bunches
2474 u16 index of this bunch
2475 u32 number of files in this bunch
2484 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2485 pkt << num_bunches << i << (u32) file_bunches[i].size();
2487 for(std::vector<SendableMedia>::iterator
2488 j = file_bunches[i].begin();
2489 j != file_bunches[i].end(); ++j) {
2491 pkt.putLongString(j->data);
2494 verbosestream << "Server::sendRequestedMedia(): bunch "
2495 << i << "/" << num_bunches
2496 << " files=" << file_bunches[i].size()
2497 << " size=" << pkt.getSize() << std::endl;
2502 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2504 if(m_detached_inventories.count(name) == 0) {
2505 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2508 Inventory *inv = m_detached_inventories[name];
2509 std::ostringstream os(std::ios_base::binary);
2511 os << serializeString(name);
2515 std::string s = os.str();
2517 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2518 pkt.putRawString(s.c_str(), s.size());
2520 const std::string &check = m_detached_inventories_player[name];
2521 if (peer_id == PEER_ID_INEXISTENT) {
2523 return m_clients.sendToAll(0, &pkt, true);
2524 RemotePlayer *p = m_env->getPlayer(check.c_str());
2526 m_clients.send(p->peer_id, 0, &pkt, true);
2528 if (check == "" || getPlayerName(peer_id) == check)
2533 void Server::sendDetachedInventories(u16 peer_id)
2535 DSTACK(FUNCTION_NAME);
2537 for(std::map<std::string, Inventory*>::iterator
2538 i = m_detached_inventories.begin();
2539 i != m_detached_inventories.end(); ++i) {
2540 const std::string &name = i->first;
2541 //Inventory *inv = i->second;
2542 sendDetachedInventory(name, peer_id);
2550 void Server::DiePlayer(u16 peer_id)
2552 DSTACK(FUNCTION_NAME);
2553 PlayerSAO *playersao = getPlayerSAO(peer_id);
2554 // In some rare cases this can be NULL -- if the player is disconnected
2555 // when a Lua function modifies l_punch, for example
2559 infostream << "Server::DiePlayer(): Player "
2560 << playersao->getPlayer()->getName()
2561 << " dies" << std::endl;
2563 playersao->setHP(0);
2565 // Trigger scripted stuff
2566 m_script->on_dieplayer(playersao);
2568 SendPlayerHP(peer_id);
2569 SendDeathscreen(peer_id, false, v3f(0,0,0));
2572 void Server::RespawnPlayer(u16 peer_id)
2574 DSTACK(FUNCTION_NAME);
2576 PlayerSAO *playersao = getPlayerSAO(peer_id);
2579 infostream << "Server::RespawnPlayer(): Player "
2580 << playersao->getPlayer()->getName()
2581 << " respawns" << std::endl;
2583 playersao->setHP(PLAYER_MAX_HP);
2584 playersao->setBreath(PLAYER_MAX_BREATH);
2586 bool repositioned = m_script->on_respawnplayer(playersao);
2587 if (!repositioned) {
2588 v3f pos = findSpawnPos();
2589 // setPos will send the new position to client
2590 playersao->setPos(pos);
2593 SendPlayerHP(peer_id);
2597 void Server::DenySudoAccess(u16 peer_id)
2599 DSTACK(FUNCTION_NAME);
2601 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2606 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2607 const std::string &str_reason, bool reconnect)
2609 if (proto_ver >= 25) {
2610 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2612 std::wstring wreason = utf8_to_wide(
2613 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2614 accessDeniedStrings[(u8)reason]);
2615 SendAccessDenied_Legacy(peer_id, wreason);
2618 m_clients.event(peer_id, CSE_SetDenied);
2619 m_con.DisconnectPeer(peer_id);
2623 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2625 DSTACK(FUNCTION_NAME);
2627 SendAccessDenied(peer_id, reason, custom_reason);
2628 m_clients.event(peer_id, CSE_SetDenied);
2629 m_con.DisconnectPeer(peer_id);
2632 // 13/03/15: remove this function when protocol version 25 will become
2633 // the minimum version for MT users, maybe in 1 year
2634 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2636 DSTACK(FUNCTION_NAME);
2638 SendAccessDenied_Legacy(peer_id, reason);
2639 m_clients.event(peer_id, CSE_SetDenied);
2640 m_con.DisconnectPeer(peer_id);
2643 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2645 DSTACK(FUNCTION_NAME);
2648 RemoteClient* client = getClient(peer_id, CS_Invalid);
2650 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2652 // Right now, the auth mechs don't change between login and sudo mode.
2653 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2654 client->allowed_sudo_mechs = sudo_auth_mechs;
2656 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2657 << g_settings->getFloat("dedicated_server_step")
2661 m_clients.event(peer_id, CSE_AuthAccept);
2663 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2665 // We only support SRP right now
2666 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2668 resp_pkt << sudo_auth_mechs;
2670 m_clients.event(peer_id, CSE_SudoSuccess);
2674 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2676 DSTACK(FUNCTION_NAME);
2677 std::wstring message;
2680 Clear references to playing sounds
2682 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2683 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2684 ServerPlayingSound &psound = i->second;
2685 psound.clients.erase(peer_id);
2686 if (psound.clients.empty())
2687 m_playing_sounds.erase(i++);
2692 RemotePlayer *player = m_env->getPlayer(peer_id);
2694 /* Run scripts and remove from environment */
2695 if (player != NULL) {
2696 PlayerSAO *playersao = player->getPlayerSAO();
2699 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2701 playersao->disconnected();
2708 if(player != NULL && reason != CDR_DENY) {
2709 std::ostringstream os(std::ios_base::binary);
2710 std::vector<u16> clients = m_clients.getClientIDs();
2712 for(std::vector<u16>::iterator i = clients.begin();
2713 i != clients.end(); ++i) {
2715 RemotePlayer *player = m_env->getPlayer(*i);
2719 // Get name of player
2720 os << player->getName() << " ";
2723 std::string name = player->getName();
2724 actionstream << name << " "
2725 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2726 << " List of players: " << os.str() << std::endl;
2728 m_admin_chat->outgoing_queue.push_back(
2729 new ChatEventNick(CET_NICK_REMOVE, name));
2733 MutexAutoLock env_lock(m_env_mutex);
2734 m_clients.DeleteClient(peer_id);
2738 // Send leave chat message to all remaining clients
2739 if(message.length() != 0)
2740 SendChatMessage(PEER_ID_INEXISTENT,message);
2743 void Server::UpdateCrafting(RemotePlayer *player)
2745 DSTACK(FUNCTION_NAME);
2747 // Get a preview for crafting
2749 InventoryLocation loc;
2750 loc.setPlayer(player->getName());
2751 std::vector<ItemStack> output_replacements;
2752 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2753 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2754 (&player->inventory)->getList("craft"), loc);
2756 // Put the new preview in
2757 InventoryList *plist = player->inventory.getList("craftpreview");
2758 sanity_check(plist);
2759 sanity_check(plist->getSize() >= 1);
2760 plist->changeItem(0, preview);
2763 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2765 if (evt->type == CET_NICK_ADD) {
2766 // The terminal informed us of its nick choice
2767 m_admin_nick = ((ChatEventNick *)evt)->nick;
2768 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2769 errorstream << "You haven't set up an account." << std::endl
2770 << "Please log in using the client as '"
2771 << m_admin_nick << "' with a secure password." << std::endl
2772 << "Until then, you can't execute admin tasks via the console," << std::endl
2773 << "and everybody can claim the user account instead of you," << std::endl
2774 << "giving them full control over this server." << std::endl;
2777 assert(evt->type == CET_CHAT);
2778 handleAdminChat((ChatEventChat *)evt);
2782 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2783 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2785 // If something goes wrong, this player is to blame
2786 RollbackScopeActor rollback_scope(m_rollback,
2787 std::string("player:") + name);
2790 switch (player->canSendChatMessage()) {
2791 case RPLAYER_CHATRESULT_FLOODING: {
2792 std::wstringstream ws;
2793 ws << L"You cannot send more messages. You are limited to "
2794 << g_settings->getFloat("chat_message_limit_per_10sec")
2795 << L" messages per 10 seconds.";
2798 case RPLAYER_CHATRESULT_KICK:
2799 DenyAccess_Legacy(player->peer_id,
2800 L"You have been kicked due to message flooding.");
2802 case RPLAYER_CHATRESULT_OK:
2805 FATAL_ERROR("Unhandled chat filtering result found.");
2809 if (m_max_chatmessage_length > 0
2810 && wmessage.length() > m_max_chatmessage_length) {
2811 return L"Your message exceed the maximum chat message limit set on the server. "
2812 L"It was refused. Send a shorter message";
2815 // Run script hook, exit if script ate the chat message
2816 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2821 // Whether to send line to the player that sent the message, or to all players
2822 bool broadcast_line = true;
2824 // Commands are implemented in Lua, so only catch invalid
2825 // commands that were not "eaten" and send an error back
2826 if (wmessage[0] == L'/') {
2827 std::wstring wcmd = wmessage.substr(1);
2828 broadcast_line = false;
2829 if (wcmd.length() == 0)
2830 line += L"-!- Empty command";
2832 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2834 if (check_shout_priv && !checkPriv(name, "shout")) {
2835 line += L"-!- You don't have permission to shout.";
2836 broadcast_line = false;
2846 Tell calling method to send the message to sender
2848 if (!broadcast_line) {
2852 Send the message to others
2854 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2856 std::vector<u16> clients = m_clients.getClientIDs();
2859 Send the message back to the inital sender
2860 if they are using protocol version >= 29
2863 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2864 if (player && player->protocol_version >= 29)
2865 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2867 for (u16 i = 0; i < clients.size(); i++) {
2868 u16 cid = clients[i];
2869 if (cid != peer_id_to_avoid_sending)
2870 SendChatMessage(cid, line);
2876 void Server::handleAdminChat(const ChatEventChat *evt)
2878 std::string name = evt->nick;
2879 std::wstring wname = utf8_to_wide(name);
2880 std::wstring wmessage = evt->evt_msg;
2882 std::wstring answer = handleChat(name, wname, wmessage);
2884 // If asked to send answer to sender
2885 if (!answer.empty()) {
2886 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2890 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2892 RemoteClient *client = getClientNoEx(peer_id,state_min);
2894 throw ClientNotFoundException("Client not found");
2898 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2900 return m_clients.getClientNoEx(peer_id, state_min);
2903 std::string Server::getPlayerName(u16 peer_id)
2905 RemotePlayer *player = m_env->getPlayer(peer_id);
2907 return "[id="+itos(peer_id)+"]";
2908 return player->getName();
2911 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2913 RemotePlayer *player = m_env->getPlayer(peer_id);
2916 return player->getPlayerSAO();
2919 std::wstring Server::getStatusString()
2921 std::wostringstream os(std::ios_base::binary);
2924 os<<L"version="<<narrow_to_wide(g_version_string);
2926 os<<L", uptime="<<m_uptime.get();
2928 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2929 // Information about clients
2932 std::vector<u16> clients = m_clients.getClientIDs();
2933 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2935 RemotePlayer *player = m_env->getPlayer(*i);
2936 // Get name of player
2937 std::wstring name = L"unknown";
2939 name = narrow_to_wide(player->getName());
2940 // Add name to information string
2948 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2949 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2950 if(g_settings->get("motd") != "")
2951 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2955 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2957 std::set<std::string> privs;
2958 m_script->getAuth(name, NULL, &privs);
2962 bool Server::checkPriv(const std::string &name, const std::string &priv)
2964 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2965 return (privs.count(priv) != 0);
2968 void Server::reportPrivsModified(const std::string &name)
2971 std::vector<u16> clients = m_clients.getClientIDs();
2972 for(std::vector<u16>::iterator i = clients.begin();
2973 i != clients.end(); ++i) {
2974 RemotePlayer *player = m_env->getPlayer(*i);
2975 reportPrivsModified(player->getName());
2978 RemotePlayer *player = m_env->getPlayer(name.c_str());
2981 SendPlayerPrivileges(player->peer_id);
2982 PlayerSAO *sao = player->getPlayerSAO();
2985 sao->updatePrivileges(
2986 getPlayerEffectivePrivs(name),
2991 void Server::reportInventoryFormspecModified(const std::string &name)
2993 RemotePlayer *player = m_env->getPlayer(name.c_str());
2996 SendPlayerInventoryFormspec(player->peer_id);
2999 void Server::setIpBanned(const std::string &ip, const std::string &name)
3001 m_banmanager->add(ip, name);
3004 void Server::unsetIpBanned(const std::string &ip_or_name)
3006 m_banmanager->remove(ip_or_name);
3009 std::string Server::getBanDescription(const std::string &ip_or_name)
3011 return m_banmanager->getBanDescription(ip_or_name);
3014 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3016 // m_env will be NULL if the server is initializing
3020 if (m_admin_nick == name && !m_admin_nick.empty()) {
3021 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3024 RemotePlayer *player = m_env->getPlayer(name);
3029 if (player->peer_id == PEER_ID_INEXISTENT)
3032 SendChatMessage(player->peer_id, msg);
3035 bool Server::showFormspec(const char *playername, const std::string &formspec,
3036 const std::string &formname)
3038 // m_env will be NULL if the server is initializing
3042 RemotePlayer *player = m_env->getPlayer(playername);
3046 SendShowFormspecMessage(player->peer_id, formspec, formname);
3050 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3055 u32 id = player->addHud(form);
3057 SendHUDAdd(player->peer_id, id, form);
3062 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3066 HudElement* todel = player->removeHud(id);
3073 SendHUDRemove(player->peer_id, id);
3077 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3082 SendHUDChange(player->peer_id, id, stat, data);
3086 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3091 SendHUDSetFlags(player->peer_id, flags, mask);
3092 player->hud_flags &= ~mask;
3093 player->hud_flags |= flags;
3095 PlayerSAO* playersao = player->getPlayerSAO();
3097 if (playersao == NULL)
3100 m_script->player_event(playersao, "hud_changed");
3104 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3109 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3112 player->setHotbarItemcount(hotbar_itemcount);
3113 std::ostringstream os(std::ios::binary);
3114 writeS32(os, hotbar_itemcount);
3115 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3119 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3124 player->setHotbarImage(name);
3125 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3128 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3132 return player->getHotbarImage();
3135 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3140 player->setHotbarSelectedImage(name);
3141 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3144 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3145 v2s32 animation_frames[4], f32 frame_speed)
3150 player->setLocalAnimations(animation_frames, frame_speed);
3151 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3155 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3160 player->eye_offset_first = first;
3161 player->eye_offset_third = third;
3162 SendEyeOffset(player->peer_id, first, third);
3166 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3167 const std::string &type, const std::vector<std::string> ¶ms)
3172 player->setSky(bgcolor, type, params);
3173 SendSetSky(player->peer_id, bgcolor, type, params);
3177 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3183 player->overrideDayNightRatio(do_override, ratio);
3184 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3188 void Server::notifyPlayers(const std::wstring &msg)
3190 SendChatMessage(PEER_ID_INEXISTENT,msg);
3193 void Server::spawnParticle(const std::string &playername, v3f pos,
3194 v3f velocity, v3f acceleration,
3195 float expirationtime, float size, bool
3196 collisiondetection, bool collision_removal,
3197 bool vertical, const std::string &texture,
3198 const struct TileAnimationParams &animation, u8 glow)
3200 // m_env will be NULL if the server is initializing
3204 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3205 if (playername != "") {
3206 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3209 peer_id = player->peer_id;
3210 proto_ver = player->protocol_version;
3213 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3214 expirationtime, size, collisiondetection,
3215 collision_removal, vertical, texture, animation, glow);
3218 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3219 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3220 float minexptime, float maxexptime, float minsize, float maxsize,
3221 bool collisiondetection, bool collision_removal,
3222 ServerActiveObject *attached, bool vertical, const std::string &texture,
3223 const std::string &playername, const struct TileAnimationParams &animation,
3226 // m_env will be NULL if the server is initializing
3230 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3231 if (playername != "") {
3232 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3235 peer_id = player->peer_id;
3236 proto_ver = player->protocol_version;
3239 u16 attached_id = attached ? attached->getId() : 0;
3242 if (attached_id == 0)
3243 id = m_env->addParticleSpawner(spawntime);
3245 id = m_env->addParticleSpawner(spawntime, attached_id);
3247 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3248 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3249 minexptime, maxexptime, minsize, maxsize,
3250 collisiondetection, collision_removal, attached_id, vertical,
3251 texture, id, animation, glow);
3256 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3258 // m_env will be NULL if the server is initializing
3260 throw ServerError("Can't delete particle spawners during initialisation!");
3262 u16 peer_id = PEER_ID_INEXISTENT;
3263 if (playername != "") {
3264 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3267 peer_id = player->peer_id;
3270 m_env->deleteParticleSpawner(id);
3271 SendDeleteParticleSpawner(peer_id, id);
3274 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3276 if(m_detached_inventories.count(name) > 0){
3277 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3278 delete m_detached_inventories[name];
3280 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3282 Inventory *inv = new Inventory(m_itemdef);
3284 m_detached_inventories[name] = inv;
3285 m_detached_inventories_player[name] = player;
3286 //TODO find a better way to do this
3287 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3291 // actions: time-reversed list
3292 // Return value: success/failure
3293 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3294 std::list<std::string> *log)
3296 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3297 ServerMap *map = (ServerMap*)(&m_env->getMap());
3299 // Fail if no actions to handle
3300 if(actions.empty()){
3301 log->push_back("Nothing to do.");
3308 for(std::list<RollbackAction>::const_iterator
3309 i = actions.begin();
3310 i != actions.end(); ++i)
3312 const RollbackAction &action = *i;
3314 bool success = action.applyRevert(map, this, this);
3317 std::ostringstream os;
3318 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3319 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3321 log->push_back(os.str());
3323 std::ostringstream os;
3324 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3325 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3327 log->push_back(os.str());
3331 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3332 <<" failed"<<std::endl;
3334 // Call it done if less than half failed
3335 return num_failed <= num_tried/2;
3338 // IGameDef interface
3340 IItemDefManager *Server::getItemDefManager()
3345 INodeDefManager *Server::getNodeDefManager()
3350 ICraftDefManager *Server::getCraftDefManager()
3355 u16 Server::allocateUnknownNodeId(const std::string &name)
3357 return m_nodedef->allocateDummy(name);
3360 MtEventManager *Server::getEventManager()
3365 IWritableItemDefManager *Server::getWritableItemDefManager()
3370 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3375 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3380 const ModSpec *Server::getModSpec(const std::string &modname) const
3382 std::vector<ModSpec>::const_iterator it;
3383 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3384 const ModSpec &mod = *it;
3385 if (mod.name == modname)
3391 void Server::getModNames(std::vector<std::string> &modlist)
3393 std::vector<ModSpec>::iterator it;
3394 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3395 modlist.push_back(it->name);
3398 std::string Server::getBuiltinLuaPath()
3400 return porting::path_share + DIR_DELIM + "builtin";
3403 std::string Server::getModStoragePath() const
3405 return m_path_world + DIR_DELIM + "mod_storage";
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 bool Server::registerModStorage(ModMetadata *storage)
3531 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3532 errorstream << "Unable to register same mod storage twice. Storage name: "
3533 << storage->getModName() << std::endl;
3537 m_mod_storages[storage->getModName()] = storage;
3541 void Server::unregisterModStorage(const std::string &name)
3543 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3544 if (it != m_mod_storages.end()) {
3545 // Save unconditionaly on unregistration
3546 it->second->save(getModStoragePath());
3547 m_mod_storages.erase(name);
3551 void dedicated_server_loop(Server &server, bool &kill)
3553 DSTACK(FUNCTION_NAME);
3555 verbosestream<<"dedicated_server_loop()"<<std::endl;
3557 IntervalLimiter m_profiler_interval;
3559 static const float steplen = g_settings->getFloat("dedicated_server_step");
3560 static const float profiler_print_interval =
3561 g_settings->getFloat("profiler_print_interval");
3564 // This is kind of a hack but can be done like this
3565 // because server.step() is very light
3567 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3568 sleep_ms((int)(steplen*1000.0));
3570 server.step(steplen);
3572 if (server.getShutdownRequested() || kill)
3578 if (profiler_print_interval != 0) {
3579 if(m_profiler_interval.step(steplen, profiler_print_interval))
3581 infostream<<"Profiler:"<<std::endl;
3582 g_profiler->print(infostream);
3583 g_profiler->clear();
3588 infostream << "Dedicated server quitting" << std::endl;
3590 if (g_settings->getBool("server_announce"))
3591 ServerList::sendAnnounce(ServerList::AA_DELETE,
3592 server.m_bind_addr.getPort());