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,
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),
182 m_mod_storage_save_timer(10.0f)
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 ServerModConfiguration 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 modconf.printUnsatisfiedModsError();
229 Settings worldmt_settings;
230 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
231 worldmt_settings.readConfigFile(worldmt.c_str());
232 std::vector<std::string> names = worldmt_settings.getNames();
233 std::set<std::string> load_mod_names;
234 for(std::vector<std::string>::iterator it = names.begin();
235 it != names.end(); ++it) {
236 std::string name = *it;
237 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
238 load_mod_names.insert(name.substr(9));
240 // complain about mods declared to be loaded, but not found
241 for(std::vector<ModSpec>::iterator it = m_mods.begin();
242 it != m_mods.end(); ++it)
243 load_mod_names.erase((*it).name);
244 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
245 it != unsatisfied_mods.end(); ++it)
246 load_mod_names.erase((*it).name);
247 if(!load_mod_names.empty()) {
248 errorstream << "The following mods could not be found:";
249 for(std::set<std::string>::iterator it = load_mod_names.begin();
250 it != load_mod_names.end(); ++it)
251 errorstream << " \"" << (*it) << "\"";
252 errorstream << std::endl;
256 MutexAutoLock envlock(m_env_mutex);
258 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
259 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
261 // Initialize scripting
262 infostream<<"Server: Initializing Lua"<<std::endl;
264 m_script = new ServerScripting(this);
266 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
269 infostream << "Server: Loading mods: ";
270 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
271 i != m_mods.end(); ++i) {
272 infostream << (*i).name << " ";
274 infostream << std::endl;
275 // Load and run "mod" scripts
276 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
277 it != m_mods.end(); ++it) {
278 const ModSpec &mod = *it;
279 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
280 throw ModError("Error loading mod \"" + mod.name +
281 "\": Mod name does not follow naming conventions: "
282 "Only chararacters [a-z0-9_] are allowed.");
284 std::string script_path = mod.path + DIR_DELIM + "init.lua";
285 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
286 << script_path << "\"]" << std::endl;
287 m_script->loadMod(script_path, mod.name);
290 // Read Textures and calculate sha1 sums
293 // Apply item aliases in the node definition manager
294 m_nodedef->updateAliases(m_itemdef);
296 // Apply texture overrides from texturepack/override.txt
297 std::string texture_path = g_settings->get("texture_path");
298 if (texture_path != "" && fs::IsDir(texture_path))
299 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
301 m_nodedef->setNodeRegistrationStatus(true);
303 // Perform pending node name resolutions
304 m_nodedef->runNodeResolveCallbacks();
306 // unmap node names for connected nodeboxes
307 m_nodedef->mapNodeboxConnections();
309 // init the recipe hashes to speed up crafting
310 m_craftdef->initHashes(this);
312 // Initialize Environment
313 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
315 m_clients.setEnv(m_env);
317 if (!servermap->settings_mgr.makeMapgenParams())
318 FATAL_ERROR("Couldn't create any mapgen type");
320 // Initialize mapgens
321 m_emerge->initMapgens(servermap->getMapgenParams());
323 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
324 if (m_enable_rollback_recording) {
325 // Create rollback manager
326 m_rollback = new RollbackManager(m_path_world, this);
329 // Give environment reference to scripting api
330 m_script->initializeEnvironment(m_env);
332 // Register us to receive map edit events
333 servermap->addEventReceiver(this);
335 // If file exists, load environment metadata
336 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
337 infostream << "Server: Loading environment metadata" << std::endl;
340 m_env->loadDefaultMeta();
343 // Add some test ActiveBlockModifiers to environment
344 add_legacy_abms(m_env, m_nodedef);
346 m_liquid_transform_every = g_settings->getFloat("liquid_update");
347 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
352 infostream<<"Server destructing"<<std::endl;
354 // Send shutdown message
355 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
358 MutexAutoLock envlock(m_env_mutex);
360 // Execute script shutdown hooks
361 m_script->on_shutdown();
363 infostream << "Server: Saving players" << std::endl;
364 m_env->saveLoadedPlayers();
366 infostream << "Server: Kicking players" << std::endl;
367 std::string kick_msg;
368 bool reconnect = false;
369 if (getShutdownRequested()) {
370 reconnect = m_shutdown_ask_reconnect;
371 kick_msg = m_shutdown_msg;
373 if (kick_msg == "") {
374 kick_msg = g_settings->get("kick_msg_shutdown");
376 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
377 kick_msg, reconnect);
379 infostream << "Server: Saving environment metadata" << std::endl;
387 // stop all emerge threads before deleting players that may have
388 // requested blocks to be emerged
389 m_emerge->stopThreads();
391 // Delete things in the reverse order of creation
401 // Deinitialize scripting
402 infostream<<"Server: Deinitializing scripting"<<std::endl;
405 // Delete detached inventories
406 for (std::map<std::string, Inventory*>::iterator
407 i = m_detached_inventories.begin();
408 i != m_detached_inventories.end(); ++i) {
413 void Server::start(Address bind_addr)
415 DSTACK(FUNCTION_NAME);
417 m_bind_addr = bind_addr;
419 infostream<<"Starting server on "
420 << bind_addr.serializeString() <<"..."<<std::endl;
422 // Stop thread if already running
425 // Initialize connection
426 m_con.SetTimeoutMs(30);
427 m_con.Serve(bind_addr);
432 // ASCII art for the win!
434 <<" .__ __ __ "<<std::endl
435 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
436 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
437 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
438 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
439 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
440 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
441 actionstream<<"Server for gameid=\""<<m_gamespec.id
442 <<"\" listening on "<<bind_addr.serializeString()<<":"
443 <<bind_addr.getPort() << "."<<std::endl;
448 DSTACK(FUNCTION_NAME);
450 infostream<<"Server: Stopping and waiting threads"<<std::endl;
452 // Stop threads (set run=false first so both start stopping)
454 //m_emergethread.setRun(false);
456 //m_emergethread.stop();
458 infostream<<"Server: Threads stopped"<<std::endl;
461 void Server::step(float dtime)
463 DSTACK(FUNCTION_NAME);
468 MutexAutoLock lock(m_step_dtime_mutex);
469 m_step_dtime += dtime;
471 // Throw if fatal error occurred in thread
472 std::string async_err = m_async_fatal_error.get();
473 if (!async_err.empty()) {
474 if (!m_simple_singleplayer_mode) {
475 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
476 g_settings->get("kick_msg_crash"),
477 g_settings->getBool("ask_reconnect_on_crash"));
479 throw ServerError("AsyncErr: " + async_err);
483 void Server::AsyncRunStep(bool initial_step)
485 DSTACK(FUNCTION_NAME);
487 g_profiler->add("Server::AsyncRunStep (num)", 1);
491 MutexAutoLock lock1(m_step_dtime_mutex);
492 dtime = m_step_dtime;
496 // Send blocks to clients
500 if((dtime < 0.001) && (initial_step == false))
503 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
505 //infostream<<"Server steps "<<dtime<<std::endl;
506 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
509 MutexAutoLock lock1(m_step_dtime_mutex);
510 m_step_dtime -= dtime;
517 m_uptime.set(m_uptime.get() + dtime);
523 Update time of day and overall game time
525 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
528 Send to clients at constant intervals
531 m_time_of_day_send_timer -= dtime;
532 if(m_time_of_day_send_timer < 0.0) {
533 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
534 u16 time = m_env->getTimeOfDay();
535 float time_speed = g_settings->getFloat("time_speed");
536 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
540 MutexAutoLock lock(m_env_mutex);
541 // Figure out and report maximum lag to environment
542 float max_lag = m_env->getMaxLagEstimate();
543 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
545 if(dtime > 0.1 && dtime > max_lag * 2.0)
546 infostream<<"Server: Maximum lag peaked to "<<dtime
550 m_env->reportMaxLagEstimate(max_lag);
552 ScopeProfiler sp(g_profiler, "SEnv step");
553 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
557 static const float map_timer_and_unload_dtime = 2.92;
558 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
560 MutexAutoLock lock(m_env_mutex);
561 // Run Map's timers and unload unused data
562 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
563 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
564 g_settings->getFloat("server_unload_unused_data_timeout"),
569 Listen to the admin chat, if available
572 if (!m_admin_chat->command_queue.empty()) {
573 MutexAutoLock lock(m_env_mutex);
574 while (!m_admin_chat->command_queue.empty()) {
575 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
576 handleChatInterfaceEvent(evt);
580 m_admin_chat->outgoing_queue.push_back(
581 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
588 /* Transform liquids */
589 m_liquid_transform_timer += dtime;
590 if(m_liquid_transform_timer >= m_liquid_transform_every)
592 m_liquid_transform_timer -= m_liquid_transform_every;
594 MutexAutoLock lock(m_env_mutex);
596 ScopeProfiler sp(g_profiler, "Server: liquid transform");
598 std::map<v3s16, MapBlock*> modified_blocks;
599 m_env->getMap().transformLiquids(modified_blocks);
604 core::map<v3s16, MapBlock*> lighting_modified_blocks;
605 ServerMap &map = ((ServerMap&)m_env->getMap());
606 map.updateLighting(modified_blocks, lighting_modified_blocks);
608 // Add blocks modified by lighting to modified_blocks
609 for(core::map<v3s16, MapBlock*>::Iterator
610 i = lighting_modified_blocks.getIterator();
611 i.atEnd() == false; i++)
613 MapBlock *block = i.getNode()->getValue();
614 modified_blocks.insert(block->getPos(), block);
618 Set the modified blocks unsent for all the clients
620 if(!modified_blocks.empty())
622 SetBlocksNotSent(modified_blocks);
625 m_clients.step(dtime);
627 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
629 // send masterserver announce
631 float &counter = m_masterserver_timer;
632 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
633 g_settings->getBool("server_announce"))
635 ServerList::sendAnnounce(counter ? "update" : "start",
636 m_bind_addr.getPort(),
637 m_clients.getPlayerNames(),
639 m_env->getGameTime(),
642 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
651 Check added and deleted active objects
654 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
655 MutexAutoLock envlock(m_env_mutex);
658 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
659 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
661 // Radius inside which objects are active
662 static const s16 radius =
663 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
665 // Radius inside which players are active
666 static const bool is_transfer_limited =
667 g_settings->exists("unlimited_player_transfer_distance") &&
668 !g_settings->getBool("unlimited_player_transfer_distance");
669 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
670 s16 player_radius = player_transfer_dist;
671 if (player_radius == 0 && is_transfer_limited)
672 player_radius = radius;
674 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
675 i != clients.end(); ++i) {
676 RemoteClient *client = i->second;
678 // If definitions and textures have not been sent, don't
679 // send objects either
680 if (client->getState() < CS_DefinitionsSent)
683 RemotePlayer *player = m_env->getPlayer(client->peer_id);
684 if (player == NULL) {
685 // This can happen if the client timeouts somehow
686 /*warningstream<<FUNCTION_NAME<<": Client "
688 <<" has no associated player"<<std::endl;*/
692 PlayerSAO *playersao = player->getPlayerSAO();
693 if (playersao == NULL)
696 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
697 if (my_radius <= 0) my_radius = radius;
698 //infostream << "Server: Active Radius " << my_radius << std::endl;
700 std::queue<u16> removed_objects;
701 std::queue<u16> added_objects;
702 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
703 client->m_known_objects, removed_objects);
704 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
705 client->m_known_objects, added_objects);
707 // Ignore if nothing happened
708 if (removed_objects.empty() && added_objects.empty()) {
712 std::string data_buffer;
716 // Handle removed objects
717 writeU16((u8*)buf, removed_objects.size());
718 data_buffer.append(buf, 2);
719 while (!removed_objects.empty()) {
721 u16 id = removed_objects.front();
722 ServerActiveObject* obj = m_env->getActiveObject(id);
724 // Add to data buffer for sending
725 writeU16((u8*)buf, id);
726 data_buffer.append(buf, 2);
728 // Remove from known objects
729 client->m_known_objects.erase(id);
731 if(obj && obj->m_known_by_count > 0)
732 obj->m_known_by_count--;
733 removed_objects.pop();
736 // Handle added objects
737 writeU16((u8*)buf, added_objects.size());
738 data_buffer.append(buf, 2);
739 while (!added_objects.empty()) {
741 u16 id = added_objects.front();
742 ServerActiveObject* obj = m_env->getActiveObject(id);
745 u8 type = ACTIVEOBJECT_TYPE_INVALID;
747 warningstream<<FUNCTION_NAME
748 <<": NULL object"<<std::endl;
750 type = obj->getSendType();
752 // Add to data buffer for sending
753 writeU16((u8*)buf, id);
754 data_buffer.append(buf, 2);
755 writeU8((u8*)buf, type);
756 data_buffer.append(buf, 1);
759 data_buffer.append(serializeLongString(
760 obj->getClientInitializationData(client->net_proto_version)));
762 data_buffer.append(serializeLongString(""));
764 // Add to known objects
765 client->m_known_objects.insert(id);
768 obj->m_known_by_count++;
773 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
774 verbosestream << "Server: Sent object remove/add: "
775 << removed_objects.size() << " removed, "
776 << added_objects.size() << " added, "
777 << "packet size is " << pktSize << std::endl;
781 m_mod_storage_save_timer -= dtime;
782 if (m_mod_storage_save_timer <= 0.0f) {
783 infostream << "Saving registered mod storages." << std::endl;
784 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
785 for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
786 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
787 if (it->second->isModified()) {
788 it->second->save(getModStoragePath());
798 MutexAutoLock envlock(m_env_mutex);
799 ScopeProfiler sp(g_profiler, "Server: sending object messages");
802 // Value = data sent by object
803 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
805 // Get active object messages from environment
807 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
811 std::vector<ActiveObjectMessage>* message_list = NULL;
812 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
813 n = buffered_messages.find(aom.id);
814 if (n == buffered_messages.end()) {
815 message_list = new std::vector<ActiveObjectMessage>;
816 buffered_messages[aom.id] = message_list;
819 message_list = n->second;
821 message_list->push_back(aom);
825 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
826 // Route data to every client
827 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
828 i != clients.end(); ++i) {
829 RemoteClient *client = i->second;
830 std::string reliable_data;
831 std::string unreliable_data;
832 // Go through all objects in message buffer
833 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
834 j = buffered_messages.begin();
835 j != buffered_messages.end(); ++j) {
836 // If object is not known by client, skip it
838 if (client->m_known_objects.find(id) == client->m_known_objects.end())
841 // Get message list of object
842 std::vector<ActiveObjectMessage>* list = j->second;
843 // Go through every message
844 for (std::vector<ActiveObjectMessage>::iterator
845 k = list->begin(); k != list->end(); ++k) {
846 // Compose the full new data with header
847 ActiveObjectMessage aom = *k;
848 std::string new_data;
851 writeU16((u8*)&buf[0], aom.id);
852 new_data.append(buf, 2);
854 new_data += serializeString(aom.datastring);
855 // Add data to buffer
857 reliable_data += new_data;
859 unreliable_data += new_data;
863 reliable_data and unreliable_data are now ready.
866 if(reliable_data.size() > 0) {
867 SendActiveObjectMessages(client->peer_id, reliable_data);
870 if(unreliable_data.size() > 0) {
871 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
876 // Clear buffered_messages
877 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
878 i = buffered_messages.begin();
879 i != buffered_messages.end(); ++i) {
885 Send queued-for-sending map edit events.
888 // We will be accessing the environment
889 MutexAutoLock lock(m_env_mutex);
891 // Don't send too many at a time
894 // Single change sending is disabled if queue size is not small
895 bool disable_single_change_sending = false;
896 if(m_unsent_map_edit_queue.size() >= 4)
897 disable_single_change_sending = true;
899 int event_count = m_unsent_map_edit_queue.size();
901 // We'll log the amount of each
904 while(m_unsent_map_edit_queue.size() != 0)
906 MapEditEvent* event = m_unsent_map_edit_queue.front();
907 m_unsent_map_edit_queue.pop();
909 // Players far away from the change are stored here.
910 // Instead of sending the changes, MapBlocks are set not sent
912 std::vector<u16> far_players;
914 switch (event->type) {
917 prof.add("MEET_ADDNODE", 1);
918 sendAddNode(event->p, event->n, event->already_known_by_peer,
919 &far_players, disable_single_change_sending ? 5 : 30,
920 event->type == MEET_ADDNODE);
922 case MEET_REMOVENODE:
923 prof.add("MEET_REMOVENODE", 1);
924 sendRemoveNode(event->p, event->already_known_by_peer,
925 &far_players, disable_single_change_sending ? 5 : 30);
927 case MEET_BLOCK_NODE_METADATA_CHANGED:
928 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
929 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
930 setBlockNotSent(event->p);
933 infostream << "Server: MEET_OTHER" << std::endl;
934 prof.add("MEET_OTHER", 1);
935 for(std::set<v3s16>::iterator
936 i = event->modified_blocks.begin();
937 i != event->modified_blocks.end(); ++i) {
942 prof.add("unknown", 1);
943 warningstream << "Server: Unknown MapEditEvent "
944 << ((u32)event->type) << std::endl;
949 Set blocks not sent to far players
951 if(!far_players.empty()) {
952 // Convert list format to that wanted by SetBlocksNotSent
953 std::map<v3s16, MapBlock*> modified_blocks2;
954 for(std::set<v3s16>::iterator
955 i = event->modified_blocks.begin();
956 i != event->modified_blocks.end(); ++i) {
957 modified_blocks2[*i] =
958 m_env->getMap().getBlockNoCreateNoEx(*i);
961 // Set blocks not sent
962 for(std::vector<u16>::iterator
963 i = far_players.begin();
964 i != far_players.end(); ++i) {
965 if(RemoteClient *client = getClient(*i))
966 client->SetBlocksNotSent(modified_blocks2);
972 /*// Don't send too many at a time
974 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
978 if(event_count >= 5){
979 infostream<<"Server: MapEditEvents:"<<std::endl;
980 prof.print(infostream);
981 } else if(event_count != 0){
982 verbosestream<<"Server: MapEditEvents:"<<std::endl;
983 prof.print(verbosestream);
989 Trigger emergethread (it somehow gets to a non-triggered but
990 bysy state sometimes)
993 float &counter = m_emergethread_trigger_timer;
995 if (counter >= 2.0) {
998 m_emerge->startThreads();
1002 // Save map, players and auth stuff
1004 float &counter = m_savemap_timer;
1006 static const float save_interval =
1007 g_settings->getFloat("server_map_save_interval");
1008 if (counter >= save_interval) {
1010 MutexAutoLock lock(m_env_mutex);
1012 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1015 if (m_banmanager->isModified()) {
1016 m_banmanager->save();
1019 // Save changed parts of map
1020 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1023 m_env->saveLoadedPlayers();
1025 // Save environment metadata
1031 void Server::Receive()
1033 DSTACK(FUNCTION_NAME);
1034 SharedBuffer<u8> data;
1038 m_con.Receive(&pkt);
1039 peer_id = pkt.getPeerId();
1042 catch(con::InvalidIncomingDataException &e) {
1043 infostream<<"Server::Receive(): "
1044 "InvalidIncomingDataException: what()="
1045 <<e.what()<<std::endl;
1047 catch(SerializationError &e) {
1048 infostream<<"Server::Receive(): "
1049 "SerializationError: what()="
1050 <<e.what()<<std::endl;
1052 catch(ClientStateError &e) {
1053 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1054 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1055 L"Try reconnecting or updating your client");
1057 catch(con::PeerNotFoundException &e) {
1062 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1064 std::string playername = "";
1065 PlayerSAO *playersao = NULL;
1068 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1069 if (client != NULL) {
1070 playername = client->getName();
1071 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1073 } catch (std::exception &e) {
1079 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1081 // If failed, cancel
1082 if ((playersao == NULL) || (player == NULL)) {
1083 if (player && player->peer_id != 0) {
1084 actionstream << "Server: Failed to emerge player \"" << playername
1085 << "\" (player allocated to an another client)" << std::endl;
1086 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1087 L"name. If your client closed unexpectedly, try again in "
1090 errorstream << "Server: " << playername << ": Failed to emerge player"
1092 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1098 Send complete position information
1100 SendMovePlayer(peer_id);
1103 SendPlayerPrivileges(peer_id);
1105 // Send inventory formspec
1106 SendPlayerInventoryFormspec(peer_id);
1109 SendInventory(playersao);
1112 SendPlayerHPOrDie(playersao);
1115 SendPlayerBreath(playersao);
1117 // Show death screen if necessary
1118 if (playersao->isDead())
1119 SendDeathscreen(peer_id, false, v3f(0,0,0));
1121 // Note things in chat if not in simple singleplayer mode
1122 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1123 // Send information about server to player in chat
1124 SendChatMessage(peer_id, getStatusString());
1126 Address addr = getPeerAddress(player->peer_id);
1127 std::string ip_str = addr.serializeString();
1128 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1133 const std::vector<std::string> &names = m_clients.getPlayerNames();
1135 actionstream << player->getName() << " joins game. List of players: ";
1137 for (std::vector<std::string>::const_iterator i = names.begin();
1138 i != names.end(); ++i) {
1139 actionstream << *i << " ";
1142 actionstream << player->getName() <<std::endl;
1147 inline void Server::handleCommand(NetworkPacket* pkt)
1149 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1150 (this->*opHandle.handler)(pkt);
1153 void Server::ProcessData(NetworkPacket *pkt)
1155 DSTACK(FUNCTION_NAME);
1156 // Environment is locked first.
1157 MutexAutoLock envlock(m_env_mutex);
1159 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1160 u32 peer_id = pkt->getPeerId();
1163 Address address = getPeerAddress(peer_id);
1164 std::string addr_s = address.serializeString();
1166 if(m_banmanager->isIpBanned(addr_s)) {
1167 std::string ban_name = m_banmanager->getBanName(addr_s);
1168 infostream << "Server: A banned client tried to connect from "
1169 << addr_s << "; banned name was "
1170 << ban_name << std::endl;
1171 // This actually doesn't seem to transfer to the client
1172 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1173 + utf8_to_wide(ban_name));
1177 catch(con::PeerNotFoundException &e) {
1179 * no peer for this packet found
1180 * most common reason is peer timeout, e.g. peer didn't
1181 * respond for some time, your server was overloaded or
1184 infostream << "Server::ProcessData(): Canceling: peer "
1185 << peer_id << " not found" << std::endl;
1190 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1192 // Command must be handled into ToServerCommandHandler
1193 if (command >= TOSERVER_NUM_MSG_TYPES) {
1194 infostream << "Server: Ignoring unknown command "
1195 << command << std::endl;
1199 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1204 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1206 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1207 errorstream << "Server::ProcessData(): Cancelling: Peer"
1208 " serialization format invalid or not initialized."
1209 " Skipping incoming command=" << command << std::endl;
1213 /* Handle commands related to client startup */
1214 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1219 if (m_clients.getClientState(peer_id) < CS_Active) {
1220 if (command == TOSERVER_PLAYERPOS) return;
1222 errorstream << "Got packet command: " << command << " for peer id "
1223 << peer_id << " but client isn't active yet. Dropping packet "
1229 } catch (SendFailedException &e) {
1230 errorstream << "Server::ProcessData(): SendFailedException: "
1231 << "what=" << e.what()
1233 } catch (PacketError &e) {
1234 actionstream << "Server::ProcessData(): PacketError: "
1235 << "what=" << e.what()
1240 void Server::setTimeOfDay(u32 time)
1242 m_env->setTimeOfDay(time);
1243 m_time_of_day_send_timer = 0;
1246 void Server::onMapEditEvent(MapEditEvent *event)
1248 if(m_ignore_map_edit_events)
1250 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1252 MapEditEvent *e = event->clone();
1253 m_unsent_map_edit_queue.push(e);
1256 Inventory* Server::getInventory(const InventoryLocation &loc)
1259 case InventoryLocation::UNDEFINED:
1260 case InventoryLocation::CURRENT_PLAYER:
1262 case InventoryLocation::PLAYER:
1264 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1267 PlayerSAO *playersao = player->getPlayerSAO();
1270 return playersao->getInventory();
1273 case InventoryLocation::NODEMETA:
1275 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1278 return meta->getInventory();
1281 case InventoryLocation::DETACHED:
1283 if(m_detached_inventories.count(loc.name) == 0)
1285 return m_detached_inventories[loc.name];
1289 sanity_check(false); // abort
1294 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1297 case InventoryLocation::UNDEFINED:
1299 case InventoryLocation::PLAYER:
1304 RemotePlayer *player =
1305 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1310 PlayerSAO *playersao = player->getPlayerSAO();
1314 SendInventory(playersao);
1317 case InventoryLocation::NODEMETA:
1319 v3s16 blockpos = getNodeBlockPos(loc.p);
1321 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1323 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1325 setBlockNotSent(blockpos);
1328 case InventoryLocation::DETACHED:
1330 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1334 sanity_check(false); // abort
1339 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1341 std::vector<u16> clients = m_clients.getClientIDs();
1343 // Set the modified blocks unsent for all the clients
1344 for (std::vector<u16>::iterator i = clients.begin();
1345 i != clients.end(); ++i) {
1346 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1347 client->SetBlocksNotSent(block);
1352 void Server::peerAdded(con::Peer *peer)
1354 DSTACK(FUNCTION_NAME);
1355 verbosestream<<"Server::peerAdded(): peer->id="
1356 <<peer->id<<std::endl;
1359 c.type = con::PEER_ADDED;
1360 c.peer_id = peer->id;
1362 m_peer_change_queue.push(c);
1365 void Server::deletingPeer(con::Peer *peer, bool timeout)
1367 DSTACK(FUNCTION_NAME);
1368 verbosestream<<"Server::deletingPeer(): peer->id="
1369 <<peer->id<<", timeout="<<timeout<<std::endl;
1371 m_clients.event(peer->id, CSE_Disconnect);
1373 c.type = con::PEER_REMOVED;
1374 c.peer_id = peer->id;
1375 c.timeout = timeout;
1376 m_peer_change_queue.push(c);
1379 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1381 *retval = m_con.getPeerStat(peer_id,type);
1382 if (*retval == -1) return false;
1386 bool Server::getClientInfo(
1395 std::string* vers_string
1398 *state = m_clients.getClientState(peer_id);
1400 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1402 if (client == NULL) {
1407 *uptime = client->uptime();
1408 *ser_vers = client->serialization_version;
1409 *prot_vers = client->net_proto_version;
1411 *major = client->getMajor();
1412 *minor = client->getMinor();
1413 *patch = client->getPatch();
1414 *vers_string = client->getPatch();
1421 void Server::handlePeerChanges()
1423 while(m_peer_change_queue.size() > 0)
1425 con::PeerChange c = m_peer_change_queue.front();
1426 m_peer_change_queue.pop();
1428 verbosestream<<"Server: Handling peer change: "
1429 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1434 case con::PEER_ADDED:
1435 m_clients.CreateClient(c.peer_id);
1438 case con::PEER_REMOVED:
1439 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1443 FATAL_ERROR("Invalid peer change event received!");
1449 void Server::printToConsoleOnly(const std::string &text)
1452 m_admin_chat->outgoing_queue.push_back(
1453 new ChatEventChat("", utf8_to_wide(text)));
1455 std::cout << text << std::endl;
1459 void Server::Send(NetworkPacket* pkt)
1461 m_clients.send(pkt->getPeerId(),
1462 clientCommandFactoryTable[pkt->getCommand()].channel,
1464 clientCommandFactoryTable[pkt->getCommand()].reliable);
1467 void Server::SendMovement(u16 peer_id)
1469 DSTACK(FUNCTION_NAME);
1470 std::ostringstream os(std::ios_base::binary);
1472 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1474 pkt << g_settings->getFloat("movement_acceleration_default");
1475 pkt << g_settings->getFloat("movement_acceleration_air");
1476 pkt << g_settings->getFloat("movement_acceleration_fast");
1477 pkt << g_settings->getFloat("movement_speed_walk");
1478 pkt << g_settings->getFloat("movement_speed_crouch");
1479 pkt << g_settings->getFloat("movement_speed_fast");
1480 pkt << g_settings->getFloat("movement_speed_climb");
1481 pkt << g_settings->getFloat("movement_speed_jump");
1482 pkt << g_settings->getFloat("movement_liquid_fluidity");
1483 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1484 pkt << g_settings->getFloat("movement_liquid_sink");
1485 pkt << g_settings->getFloat("movement_gravity");
1490 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1492 if (!g_settings->getBool("enable_damage"))
1495 u16 peer_id = playersao->getPeerID();
1496 bool is_alive = playersao->getHP() > 0;
1499 SendPlayerHP(peer_id);
1504 void Server::SendHP(u16 peer_id, u8 hp)
1506 DSTACK(FUNCTION_NAME);
1508 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1513 void Server::SendBreath(u16 peer_id, u16 breath)
1515 DSTACK(FUNCTION_NAME);
1517 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1518 pkt << (u16) breath;
1522 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1523 const std::string &custom_reason, bool reconnect)
1525 assert(reason < SERVER_ACCESSDENIED_MAX);
1527 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1529 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1530 pkt << custom_reason;
1531 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1532 reason == SERVER_ACCESSDENIED_CRASH)
1533 pkt << custom_reason << (u8)reconnect;
1537 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1539 DSTACK(FUNCTION_NAME);
1541 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1546 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1547 v3f camera_point_target)
1549 DSTACK(FUNCTION_NAME);
1551 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1552 pkt << set_camera_point_target << camera_point_target;
1556 void Server::SendItemDef(u16 peer_id,
1557 IItemDefManager *itemdef, u16 protocol_version)
1559 DSTACK(FUNCTION_NAME);
1561 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1565 u32 length of the next item
1566 zlib-compressed serialized ItemDefManager
1568 std::ostringstream tmp_os(std::ios::binary);
1569 itemdef->serialize(tmp_os, protocol_version);
1570 std::ostringstream tmp_os2(std::ios::binary);
1571 compressZlib(tmp_os.str(), tmp_os2);
1572 pkt.putLongString(tmp_os2.str());
1575 verbosestream << "Server: Sending item definitions to id(" << peer_id
1576 << "): size=" << pkt.getSize() << std::endl;
1581 void Server::SendNodeDef(u16 peer_id,
1582 INodeDefManager *nodedef, u16 protocol_version)
1584 DSTACK(FUNCTION_NAME);
1586 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1590 u32 length of the next item
1591 zlib-compressed serialized NodeDefManager
1593 std::ostringstream tmp_os(std::ios::binary);
1594 nodedef->serialize(tmp_os, protocol_version);
1595 std::ostringstream tmp_os2(std::ios::binary);
1596 compressZlib(tmp_os.str(), tmp_os2);
1598 pkt.putLongString(tmp_os2.str());
1601 verbosestream << "Server: Sending node definitions to id(" << peer_id
1602 << "): size=" << pkt.getSize() << std::endl;
1608 Non-static send methods
1611 void Server::SendInventory(PlayerSAO* playerSAO)
1613 DSTACK(FUNCTION_NAME);
1615 UpdateCrafting(playerSAO->getPlayer());
1621 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1623 std::ostringstream os;
1624 playerSAO->getInventory()->serialize(os);
1626 std::string s = os.str();
1628 pkt.putRawString(s.c_str(), s.size());
1632 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1634 DSTACK(FUNCTION_NAME);
1636 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1639 if (peer_id != PEER_ID_INEXISTENT) {
1643 m_clients.sendToAll(0, &pkt, true);
1647 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1648 const std::string &formname)
1650 DSTACK(FUNCTION_NAME);
1652 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1653 if (formspec == "" ){
1654 //the client should close the formspec
1655 pkt.putLongString("");
1657 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1664 // Spawns a particle on peer with peer_id
1665 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1666 v3f pos, v3f velocity, v3f acceleration,
1667 float expirationtime, float size, bool collisiondetection,
1668 bool collision_removal,
1669 bool vertical, const std::string &texture,
1670 const struct TileAnimationParams &animation, u8 glow)
1672 DSTACK(FUNCTION_NAME);
1673 if (peer_id == PEER_ID_INEXISTENT) {
1674 // This sucks and should be replaced by a better solution in a refactor:
1675 std::vector<u16> clients = m_clients.getClientIDs();
1676 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1677 RemotePlayer *player = m_env->getPlayer(*i);
1680 SendSpawnParticle(*i, player->protocol_version,
1681 pos, velocity, acceleration,
1682 expirationtime, size, collisiondetection,
1683 collision_removal, vertical, texture, animation, glow);
1688 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1690 pkt << pos << velocity << acceleration << expirationtime
1691 << size << collisiondetection;
1692 pkt.putLongString(texture);
1694 pkt << collision_removal;
1695 // This is horrible but required (why are there two ways to serialize pkts?)
1696 std::ostringstream os(std::ios_base::binary);
1697 animation.serialize(os, protocol_version);
1698 pkt.putRawString(os.str());
1704 // Adds a ParticleSpawner on peer with peer_id
1705 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1706 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1707 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1708 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1709 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1710 const struct TileAnimationParams &animation, u8 glow)
1712 DSTACK(FUNCTION_NAME);
1713 if (peer_id == PEER_ID_INEXISTENT) {
1714 // This sucks and should be replaced:
1715 std::vector<u16> clients = m_clients.getClientIDs();
1716 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1717 RemotePlayer *player = m_env->getPlayer(*i);
1720 SendAddParticleSpawner(*i, player->protocol_version,
1721 amount, spawntime, minpos, maxpos,
1722 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1723 minsize, maxsize, collisiondetection, collision_removal,
1724 attached_id, vertical, texture, id, animation, glow);
1729 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1731 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1732 << minacc << maxacc << minexptime << maxexptime << minsize
1733 << maxsize << collisiondetection;
1735 pkt.putLongString(texture);
1737 pkt << id << vertical;
1738 pkt << collision_removal;
1740 // This is horrible but required
1741 std::ostringstream os(std::ios_base::binary);
1742 animation.serialize(os, protocol_version);
1743 pkt.putRawString(os.str());
1749 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1751 DSTACK(FUNCTION_NAME);
1753 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1755 // Ugly error in this packet
1758 if (peer_id != PEER_ID_INEXISTENT) {
1762 m_clients.sendToAll(0, &pkt, true);
1767 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1769 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1771 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1772 << form->text << form->number << form->item << form->dir
1773 << form->align << form->offset << form->world_pos << form->size;
1778 void Server::SendHUDRemove(u16 peer_id, u32 id)
1780 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1785 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1787 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1788 pkt << id << (u8) stat;
1792 case HUD_STAT_SCALE:
1793 case HUD_STAT_ALIGN:
1794 case HUD_STAT_OFFSET:
1795 pkt << *(v2f *) value;
1799 pkt << *(std::string *) value;
1801 case HUD_STAT_WORLD_POS:
1802 pkt << *(v3f *) value;
1805 pkt << *(v2s32 *) value;
1807 case HUD_STAT_NUMBER:
1811 pkt << *(u32 *) value;
1818 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1820 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1822 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1824 pkt << flags << mask;
1829 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1831 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1832 pkt << param << value;
1836 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1837 const std::string &type, const std::vector<std::string> ¶ms)
1839 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1840 pkt << bgcolor << type << (u16) params.size();
1842 for(size_t i=0; i<params.size(); i++)
1848 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1851 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1854 pkt << do_override << (u16) (ratio * 65535);
1859 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1861 DSTACK(FUNCTION_NAME);
1863 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1864 pkt << time << time_speed;
1866 if (peer_id == PEER_ID_INEXISTENT) {
1867 m_clients.sendToAll(0, &pkt, true);
1874 void Server::SendPlayerHP(u16 peer_id)
1876 DSTACK(FUNCTION_NAME);
1877 PlayerSAO *playersao = getPlayerSAO(peer_id);
1878 // In some rare case if the player is disconnected
1879 // while Lua call l_punch, for example, this can be NULL
1883 SendHP(peer_id, playersao->getHP());
1884 m_script->player_event(playersao,"health_changed");
1886 // Send to other clients
1887 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1888 ActiveObjectMessage aom(playersao->getId(), true, str);
1889 playersao->m_messages_out.push(aom);
1892 void Server::SendPlayerBreath(PlayerSAO *sao)
1894 DSTACK(FUNCTION_NAME);
1897 m_script->player_event(sao, "breath_changed");
1898 SendBreath(sao->getPeerID(), sao->getBreath());
1901 void Server::SendMovePlayer(u16 peer_id)
1903 DSTACK(FUNCTION_NAME);
1904 RemotePlayer *player = m_env->getPlayer(peer_id);
1906 PlayerSAO *sao = player->getPlayerSAO();
1909 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1910 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1913 v3f pos = sao->getBasePosition();
1914 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1915 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1916 << " pitch=" << sao->getPitch()
1917 << " yaw=" << sao->getYaw()
1924 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1926 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1929 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1930 << animation_frames[3] << animation_speed;
1935 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1937 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1938 pkt << first << third;
1941 void Server::SendPlayerPrivileges(u16 peer_id)
1943 RemotePlayer *player = m_env->getPlayer(peer_id);
1945 if(player->peer_id == PEER_ID_INEXISTENT)
1948 std::set<std::string> privs;
1949 m_script->getAuth(player->getName(), NULL, &privs);
1951 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1952 pkt << (u16) privs.size();
1954 for(std::set<std::string>::const_iterator i = privs.begin();
1955 i != privs.end(); ++i) {
1962 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1964 RemotePlayer *player = m_env->getPlayer(peer_id);
1966 if(player->peer_id == PEER_ID_INEXISTENT)
1969 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1970 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1974 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1976 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1977 pkt.putRawString(datas.c_str(), datas.size());
1979 return pkt.getSize();
1982 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1984 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1985 datas.size(), peer_id);
1987 pkt.putRawString(datas.c_str(), datas.size());
1989 m_clients.send(pkt.getPeerId(),
1990 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1995 s32 Server::playSound(const SimpleSoundSpec &spec,
1996 const ServerSoundParams ¶ms)
1998 // Find out initial position of sound
1999 bool pos_exists = false;
2000 v3f pos = params.getPos(m_env, &pos_exists);
2001 // If position is not found while it should be, cancel sound
2002 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2005 // Filter destination clients
2006 std::vector<u16> dst_clients;
2007 if(params.to_player != "")
2009 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2011 infostream<<"Server::playSound: Player \""<<params.to_player
2012 <<"\" not found"<<std::endl;
2015 if(player->peer_id == PEER_ID_INEXISTENT){
2016 infostream<<"Server::playSound: Player \""<<params.to_player
2017 <<"\" not connected"<<std::endl;
2020 dst_clients.push_back(player->peer_id);
2023 std::vector<u16> clients = m_clients.getClientIDs();
2025 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2026 RemotePlayer *player = m_env->getPlayer(*i);
2030 PlayerSAO *sao = player->getPlayerSAO();
2035 if(sao->getBasePosition().getDistanceFrom(pos) >
2036 params.max_hear_distance)
2039 dst_clients.push_back(*i);
2043 if(dst_clients.empty())
2047 s32 id = m_next_sound_id++;
2048 // The sound will exist as a reference in m_playing_sounds
2049 m_playing_sounds[id] = ServerPlayingSound();
2050 ServerPlayingSound &psound = m_playing_sounds[id];
2051 psound.params = params;
2053 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2054 pkt << id << spec.name << (float) (spec.gain * params.gain)
2055 << (u8) params.type << pos << params.object << params.loop;
2057 for(std::vector<u16>::iterator i = dst_clients.begin();
2058 i != dst_clients.end(); ++i) {
2059 psound.clients.insert(*i);
2060 m_clients.send(*i, 0, &pkt, true);
2064 void Server::stopSound(s32 handle)
2066 // Get sound reference
2067 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2068 if (i == m_playing_sounds.end())
2070 ServerPlayingSound &psound = i->second;
2072 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2075 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2076 i != psound.clients.end(); ++i) {
2078 m_clients.send(*i, 0, &pkt, true);
2080 // Remove sound reference
2081 m_playing_sounds.erase(i);
2084 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2085 std::vector<u16> *far_players, float far_d_nodes)
2087 float maxd = far_d_nodes*BS;
2088 v3f p_f = intToFloat(p, BS);
2090 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2093 std::vector<u16> clients = m_clients.getClientIDs();
2094 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2097 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2098 PlayerSAO *sao = player->getPlayerSAO();
2102 // If player is far away, only set modified blocks not sent
2103 v3f player_pos = sao->getBasePosition();
2104 if (player_pos.getDistanceFrom(p_f) > maxd) {
2105 far_players->push_back(*i);
2112 m_clients.send(*i, 0, &pkt, true);
2116 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2117 std::vector<u16> *far_players, float far_d_nodes,
2118 bool remove_metadata)
2120 float maxd = far_d_nodes*BS;
2121 v3f p_f = intToFloat(p, BS);
2123 std::vector<u16> clients = m_clients.getClientIDs();
2124 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2127 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2128 PlayerSAO *sao = player->getPlayerSAO();
2132 // If player is far away, only set modified blocks not sent
2133 v3f player_pos = sao->getBasePosition();
2134 if(player_pos.getDistanceFrom(p_f) > maxd) {
2135 far_players->push_back(*i);
2141 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2143 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2145 pkt << p << n.param0 << n.param1 << n.param2
2146 << (u8) (remove_metadata ? 0 : 1);
2148 if (!remove_metadata) {
2149 if (client->net_proto_version <= 21) {
2150 // Old clients always clear metadata; fix it
2151 // by sending the full block again.
2152 client->SetBlockNotSent(getNodeBlockPos(p));
2159 if (pkt.getSize() > 0)
2160 m_clients.send(*i, 0, &pkt, true);
2164 void Server::setBlockNotSent(v3s16 p)
2166 std::vector<u16> clients = m_clients.getClientIDs();
2168 for(std::vector<u16>::iterator i = clients.begin();
2169 i != clients.end(); ++i) {
2170 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2171 client->SetBlockNotSent(p);
2176 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2178 DSTACK(FUNCTION_NAME);
2180 v3s16 p = block->getPos();
2183 Create a packet with the block in the right format
2186 std::ostringstream os(std::ios_base::binary);
2187 block->serialize(os, ver, false);
2188 block->serializeNetworkSpecific(os, net_proto_version);
2189 std::string s = os.str();
2191 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2194 pkt.putRawString(s.c_str(), s.size());
2198 void Server::SendBlocks(float dtime)
2200 DSTACK(FUNCTION_NAME);
2202 MutexAutoLock envlock(m_env_mutex);
2203 //TODO check if one big lock could be faster then multiple small ones
2205 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2207 std::vector<PrioritySortedBlockTransfer> queue;
2209 s32 total_sending = 0;
2212 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2214 std::vector<u16> clients = m_clients.getClientIDs();
2217 for(std::vector<u16>::iterator i = clients.begin();
2218 i != clients.end(); ++i) {
2219 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2224 total_sending += client->SendingCount();
2225 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2231 // Lowest priority number comes first.
2232 // Lowest is most important.
2233 std::sort(queue.begin(), queue.end());
2236 for(u32 i=0; i<queue.size(); i++)
2238 //TODO: Calculate limit dynamically
2239 if(total_sending >= g_settings->getS32
2240 ("max_simultaneous_block_sends_server_total"))
2243 PrioritySortedBlockTransfer q = queue[i];
2245 MapBlock *block = NULL;
2248 block = m_env->getMap().getBlockNoCreate(q.pos);
2250 catch(InvalidPositionException &e)
2255 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2260 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2262 client->SentBlock(q.pos);
2268 void Server::fillMediaCache()
2270 DSTACK(FUNCTION_NAME);
2272 infostream<<"Server: Calculating media file checksums"<<std::endl;
2274 // Collect all media file paths
2275 std::vector<std::string> paths;
2276 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2277 i != m_mods.end(); ++i) {
2278 const ModSpec &mod = *i;
2279 paths.push_back(mod.path + DIR_DELIM + "textures");
2280 paths.push_back(mod.path + DIR_DELIM + "sounds");
2281 paths.push_back(mod.path + DIR_DELIM + "media");
2282 paths.push_back(mod.path + DIR_DELIM + "models");
2284 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2286 // Collect media file information from paths into cache
2287 for(std::vector<std::string>::iterator i = paths.begin();
2288 i != paths.end(); ++i) {
2289 std::string mediapath = *i;
2290 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2291 for (u32 j = 0; j < dirlist.size(); j++) {
2292 if (dirlist[j].dir) // Ignode dirs
2294 std::string filename = dirlist[j].name;
2295 // If name contains illegal characters, ignore the file
2296 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2297 infostream<<"Server: ignoring illegal file name: \""
2298 << filename << "\"" << std::endl;
2301 // If name is not in a supported format, ignore it
2302 const char *supported_ext[] = {
2303 ".png", ".jpg", ".bmp", ".tga",
2304 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2306 ".x", ".b3d", ".md2", ".obj",
2309 if (removeStringEnd(filename, supported_ext) == ""){
2310 infostream << "Server: ignoring unsupported file extension: \""
2311 << filename << "\"" << std::endl;
2314 // Ok, attempt to load the file and add to cache
2315 std::string filepath = mediapath + DIR_DELIM + filename;
2317 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2319 errorstream << "Server::fillMediaCache(): Could not open \""
2320 << filename << "\" for reading" << std::endl;
2323 std::ostringstream tmp_os(std::ios_base::binary);
2327 fis.read(buf, 1024);
2328 std::streamsize len = fis.gcount();
2329 tmp_os.write(buf, len);
2338 errorstream<<"Server::fillMediaCache(): Failed to read \""
2339 << filename << "\"" << std::endl;
2342 if(tmp_os.str().length() == 0) {
2343 errorstream << "Server::fillMediaCache(): Empty file \""
2344 << filepath << "\"" << std::endl;
2349 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2351 unsigned char *digest = sha1.getDigest();
2352 std::string sha1_base64 = base64_encode(digest, 20);
2353 std::string sha1_hex = hex_encode((char*)digest, 20);
2357 m_media[filename] = MediaInfo(filepath, sha1_base64);
2358 verbosestream << "Server: " << sha1_hex << " is " << filename
2364 void Server::sendMediaAnnouncement(u16 peer_id)
2366 DSTACK(FUNCTION_NAME);
2368 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2372 std::ostringstream os(std::ios_base::binary);
2374 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2375 pkt << (u16) m_media.size();
2377 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2378 i != m_media.end(); ++i) {
2379 pkt << i->first << i->second.sha1_digest;
2382 pkt << g_settings->get("remote_media");
2386 struct SendableMedia
2392 SendableMedia(const std::string &name_="", const std::string &path_="",
2393 const std::string &data_=""):
2400 void Server::sendRequestedMedia(u16 peer_id,
2401 const std::vector<std::string> &tosend)
2403 DSTACK(FUNCTION_NAME);
2405 verbosestream<<"Server::sendRequestedMedia(): "
2406 <<"Sending files to client"<<std::endl;
2410 // Put 5kB in one bunch (this is not accurate)
2411 u32 bytes_per_bunch = 5000;
2413 std::vector< std::vector<SendableMedia> > file_bunches;
2414 file_bunches.push_back(std::vector<SendableMedia>());
2416 u32 file_size_bunch_total = 0;
2418 for(std::vector<std::string>::const_iterator i = tosend.begin();
2419 i != tosend.end(); ++i) {
2420 const std::string &name = *i;
2422 if (m_media.find(name) == m_media.end()) {
2423 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2424 <<"unknown file \""<<(name)<<"\""<<std::endl;
2428 //TODO get path + name
2429 std::string tpath = m_media[name].path;
2432 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2433 if(fis.good() == false){
2434 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2435 <<tpath<<"\" for reading"<<std::endl;
2438 std::ostringstream tmp_os(std::ios_base::binary);
2442 fis.read(buf, 1024);
2443 std::streamsize len = fis.gcount();
2444 tmp_os.write(buf, len);
2445 file_size_bunch_total += len;
2454 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2455 <<name<<"\""<<std::endl;
2458 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2459 <<tname<<"\""<<std::endl;*/
2461 file_bunches[file_bunches.size()-1].push_back(
2462 SendableMedia(name, tpath, tmp_os.str()));
2464 // Start next bunch if got enough data
2465 if(file_size_bunch_total >= bytes_per_bunch) {
2466 file_bunches.push_back(std::vector<SendableMedia>());
2467 file_size_bunch_total = 0;
2472 /* Create and send packets */
2474 u16 num_bunches = file_bunches.size();
2475 for(u16 i = 0; i < num_bunches; i++) {
2478 u16 total number of texture bunches
2479 u16 index of this bunch
2480 u32 number of files in this bunch
2489 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2490 pkt << num_bunches << i << (u32) file_bunches[i].size();
2492 for(std::vector<SendableMedia>::iterator
2493 j = file_bunches[i].begin();
2494 j != file_bunches[i].end(); ++j) {
2496 pkt.putLongString(j->data);
2499 verbosestream << "Server::sendRequestedMedia(): bunch "
2500 << i << "/" << num_bunches
2501 << " files=" << file_bunches[i].size()
2502 << " size=" << pkt.getSize() << std::endl;
2507 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2509 if(m_detached_inventories.count(name) == 0) {
2510 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2513 Inventory *inv = m_detached_inventories[name];
2514 std::ostringstream os(std::ios_base::binary);
2516 os << serializeString(name);
2520 std::string s = os.str();
2522 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2523 pkt.putRawString(s.c_str(), s.size());
2525 const std::string &check = m_detached_inventories_player[name];
2526 if (peer_id == PEER_ID_INEXISTENT) {
2528 return m_clients.sendToAll(0, &pkt, true);
2529 RemotePlayer *p = m_env->getPlayer(check.c_str());
2531 m_clients.send(p->peer_id, 0, &pkt, true);
2533 if (check == "" || getPlayerName(peer_id) == check)
2538 void Server::sendDetachedInventories(u16 peer_id)
2540 DSTACK(FUNCTION_NAME);
2542 for(std::map<std::string, Inventory*>::iterator
2543 i = m_detached_inventories.begin();
2544 i != m_detached_inventories.end(); ++i) {
2545 const std::string &name = i->first;
2546 //Inventory *inv = i->second;
2547 sendDetachedInventory(name, peer_id);
2555 void Server::DiePlayer(u16 peer_id)
2557 DSTACK(FUNCTION_NAME);
2558 PlayerSAO *playersao = getPlayerSAO(peer_id);
2559 // In some rare cases this can be NULL -- if the player is disconnected
2560 // when a Lua function modifies l_punch, for example
2564 infostream << "Server::DiePlayer(): Player "
2565 << playersao->getPlayer()->getName()
2566 << " dies" << std::endl;
2568 playersao->setHP(0);
2570 // Trigger scripted stuff
2571 m_script->on_dieplayer(playersao);
2573 SendPlayerHP(peer_id);
2574 SendDeathscreen(peer_id, false, v3f(0,0,0));
2577 void Server::RespawnPlayer(u16 peer_id)
2579 DSTACK(FUNCTION_NAME);
2581 PlayerSAO *playersao = getPlayerSAO(peer_id);
2584 infostream << "Server::RespawnPlayer(): Player "
2585 << playersao->getPlayer()->getName()
2586 << " respawns" << std::endl;
2588 playersao->setHP(PLAYER_MAX_HP);
2589 playersao->setBreath(PLAYER_MAX_BREATH);
2591 bool repositioned = m_script->on_respawnplayer(playersao);
2592 if (!repositioned) {
2593 v3f pos = findSpawnPos();
2594 // setPos will send the new position to client
2595 playersao->setPos(pos);
2598 SendPlayerHP(peer_id);
2602 void Server::DenySudoAccess(u16 peer_id)
2604 DSTACK(FUNCTION_NAME);
2606 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2611 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2612 const std::string &str_reason, bool reconnect)
2614 if (proto_ver >= 25) {
2615 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2617 std::wstring wreason = utf8_to_wide(
2618 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2619 accessDeniedStrings[(u8)reason]);
2620 SendAccessDenied_Legacy(peer_id, wreason);
2623 m_clients.event(peer_id, CSE_SetDenied);
2624 m_con.DisconnectPeer(peer_id);
2628 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2630 DSTACK(FUNCTION_NAME);
2632 SendAccessDenied(peer_id, reason, custom_reason);
2633 m_clients.event(peer_id, CSE_SetDenied);
2634 m_con.DisconnectPeer(peer_id);
2637 // 13/03/15: remove this function when protocol version 25 will become
2638 // the minimum version for MT users, maybe in 1 year
2639 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2641 DSTACK(FUNCTION_NAME);
2643 SendAccessDenied_Legacy(peer_id, reason);
2644 m_clients.event(peer_id, CSE_SetDenied);
2645 m_con.DisconnectPeer(peer_id);
2648 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2650 DSTACK(FUNCTION_NAME);
2653 RemoteClient* client = getClient(peer_id, CS_Invalid);
2655 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2657 // Right now, the auth mechs don't change between login and sudo mode.
2658 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2659 client->allowed_sudo_mechs = sudo_auth_mechs;
2661 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2662 << g_settings->getFloat("dedicated_server_step")
2666 m_clients.event(peer_id, CSE_AuthAccept);
2668 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2670 // We only support SRP right now
2671 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2673 resp_pkt << sudo_auth_mechs;
2675 m_clients.event(peer_id, CSE_SudoSuccess);
2679 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2681 DSTACK(FUNCTION_NAME);
2682 std::wstring message;
2685 Clear references to playing sounds
2687 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2688 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2689 ServerPlayingSound &psound = i->second;
2690 psound.clients.erase(peer_id);
2691 if (psound.clients.empty())
2692 m_playing_sounds.erase(i++);
2697 RemotePlayer *player = m_env->getPlayer(peer_id);
2699 /* Run scripts and remove from environment */
2700 if (player != NULL) {
2701 PlayerSAO *playersao = player->getPlayerSAO();
2704 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2706 playersao->disconnected();
2713 if(player != NULL && reason != CDR_DENY) {
2714 std::ostringstream os(std::ios_base::binary);
2715 std::vector<u16> clients = m_clients.getClientIDs();
2717 for(std::vector<u16>::iterator i = clients.begin();
2718 i != clients.end(); ++i) {
2720 RemotePlayer *player = m_env->getPlayer(*i);
2724 // Get name of player
2725 os << player->getName() << " ";
2728 std::string name = player->getName();
2729 actionstream << name << " "
2730 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2731 << " List of players: " << os.str() << std::endl;
2733 m_admin_chat->outgoing_queue.push_back(
2734 new ChatEventNick(CET_NICK_REMOVE, name));
2738 MutexAutoLock env_lock(m_env_mutex);
2739 m_clients.DeleteClient(peer_id);
2743 // Send leave chat message to all remaining clients
2744 if(message.length() != 0)
2745 SendChatMessage(PEER_ID_INEXISTENT,message);
2748 void Server::UpdateCrafting(RemotePlayer *player)
2750 DSTACK(FUNCTION_NAME);
2752 // Get a preview for crafting
2754 InventoryLocation loc;
2755 loc.setPlayer(player->getName());
2756 std::vector<ItemStack> output_replacements;
2757 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2758 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2759 (&player->inventory)->getList("craft"), loc);
2761 // Put the new preview in
2762 InventoryList *plist = player->inventory.getList("craftpreview");
2763 sanity_check(plist);
2764 sanity_check(plist->getSize() >= 1);
2765 plist->changeItem(0, preview);
2768 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2770 if (evt->type == CET_NICK_ADD) {
2771 // The terminal informed us of its nick choice
2772 m_admin_nick = ((ChatEventNick *)evt)->nick;
2773 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2774 errorstream << "You haven't set up an account." << std::endl
2775 << "Please log in using the client as '"
2776 << m_admin_nick << "' with a secure password." << std::endl
2777 << "Until then, you can't execute admin tasks via the console," << std::endl
2778 << "and everybody can claim the user account instead of you," << std::endl
2779 << "giving them full control over this server." << std::endl;
2782 assert(evt->type == CET_CHAT);
2783 handleAdminChat((ChatEventChat *)evt);
2787 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2788 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2790 // If something goes wrong, this player is to blame
2791 RollbackScopeActor rollback_scope(m_rollback,
2792 std::string("player:") + name);
2795 switch (player->canSendChatMessage()) {
2796 case RPLAYER_CHATRESULT_FLOODING: {
2797 std::wstringstream ws;
2798 ws << L"You cannot send more messages. You are limited to "
2799 << g_settings->getFloat("chat_message_limit_per_10sec")
2800 << L" messages per 10 seconds.";
2803 case RPLAYER_CHATRESULT_KICK:
2804 DenyAccess_Legacy(player->peer_id,
2805 L"You have been kicked due to message flooding.");
2807 case RPLAYER_CHATRESULT_OK:
2810 FATAL_ERROR("Unhandled chat filtering result found.");
2814 if (m_max_chatmessage_length > 0
2815 && wmessage.length() > m_max_chatmessage_length) {
2816 return L"Your message exceed the maximum chat message limit set on the server. "
2817 L"It was refused. Send a shorter message";
2820 // Run script hook, exit if script ate the chat message
2821 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2826 // Whether to send line to the player that sent the message, or to all players
2827 bool broadcast_line = true;
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 && 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 const std::string Server::getBuiltinLuaPath()
3405 return porting::path_share + DIR_DELIM + "builtin";
3408 std::string Server::getModStoragePath() const
3410 return m_path_world + DIR_DELIM + "mod_storage";
3413 v3f Server::findSpawnPos()
3415 ServerMap &map = m_env->getServerMap();
3417 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3418 return nodeposf * BS;
3421 bool is_good = false;
3423 // Try to find a good place a few times
3424 for(s32 i = 0; i < 4000 && !is_good; i++) {
3426 // We're going to try to throw the player to this position
3427 v2s16 nodepos2d = v2s16(
3428 -range + (myrand() % (range * 2)),
3429 -range + (myrand() % (range * 2)));
3431 // Get spawn level at point
3432 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3433 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3434 // the mapgen to signify an unsuitable spawn position
3435 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3438 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3441 for (s32 i = 0; i < 10; i++) {
3442 v3s16 blockpos = getNodeBlockPos(nodepos);
3443 map.emergeBlock(blockpos, true);
3444 content_t c = map.getNodeNoEx(nodepos).getContent();
3445 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3447 if (air_count >= 2) {
3448 nodeposf = intToFloat(nodepos, BS);
3449 // Don't spawn the player outside map boundaries
3450 if (objectpos_over_limit(nodeposf))
3463 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3465 bool newplayer = false;
3468 Try to get an existing player
3470 RemotePlayer *player = m_env->getPlayer(name);
3472 // If player is already connected, cancel
3473 if (player != NULL && player->peer_id != 0) {
3474 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3479 If player with the wanted peer_id already exists, cancel.
3481 if (m_env->getPlayer(peer_id) != NULL) {
3482 infostream<<"emergePlayer(): Player with wrong name but same"
3483 " peer_id already exists"<<std::endl;
3487 // Create a new player active object
3488 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3489 player = m_env->loadPlayer(name, playersao);
3491 // Create player if it doesn't exist
3494 player = new RemotePlayer(name, this->idef());
3495 // Set player position
3496 infostream<<"Server: Finding spawn place for player \""
3497 <<name<<"\""<<std::endl;
3498 playersao->setBasePosition(findSpawnPos());
3500 // Make sure the player is saved
3501 player->setModified(true);
3503 // Add player to environment
3504 m_env->addPlayer(player);
3506 // If the player exists, ensure that they respawn inside legal bounds
3507 // This fixes an assert crash when the player can't be added
3508 // to the environment
3509 if (objectpos_over_limit(playersao->getBasePosition())) {
3510 actionstream << "Respawn position for player \""
3511 << name << "\" outside limits, resetting" << std::endl;
3512 playersao->setBasePosition(findSpawnPos());
3516 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3518 player->protocol_version = proto_version;
3520 /* Clean up old HUD elements from previous sessions */
3523 /* Add object to environment */
3524 m_env->addActiveObject(playersao);
3528 m_script->on_newplayer(playersao);
3534 bool Server::registerModStorage(ModMetadata *storage)
3536 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3537 errorstream << "Unable to register same mod storage twice. Storage name: "
3538 << storage->getModName() << std::endl;
3542 m_mod_storages[storage->getModName()] = storage;
3546 void Server::unregisterModStorage(const std::string &name)
3548 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3549 if (it != m_mod_storages.end()) {
3550 // Save unconditionaly on unregistration
3551 it->second->save(getModStoragePath());
3552 m_mod_storages.erase(name);
3556 void dedicated_server_loop(Server &server, bool &kill)
3558 DSTACK(FUNCTION_NAME);
3560 verbosestream<<"dedicated_server_loop()"<<std::endl;
3562 IntervalLimiter m_profiler_interval;
3564 static const float steplen = g_settings->getFloat("dedicated_server_step");
3565 static const float profiler_print_interval =
3566 g_settings->getFloat("profiler_print_interval");
3569 // This is kind of a hack but can be done like this
3570 // because server.step() is very light
3572 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3573 sleep_ms((int)(steplen*1000.0));
3575 server.step(steplen);
3577 if(server.getShutdownRequested() || kill)
3579 infostream<<"Dedicated server quitting"<<std::endl;
3581 if(g_settings->getBool("server_announce"))
3582 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3590 if (profiler_print_interval != 0) {
3591 if(m_profiler_interval.step(steplen, profiler_print_interval))
3593 infostream<<"Profiler:"<<std::endl;
3594 g_profiler->print(infostream);
3595 g_profiler->clear();