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),
180 m_shutdown_timer(0.0f),
182 m_ignore_map_edit_events(false),
183 m_ignore_map_edit_events_peer_id(0),
185 m_mod_storage_save_timer(10.0f)
187 m_liquid_transform_timer = 0.0;
188 m_liquid_transform_every = 1.0;
189 m_masterserver_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ServerModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if (!modconf.isConsistent()) {
229 modconf.printUnsatisfiedModsError();
232 Settings worldmt_settings;
233 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
234 worldmt_settings.readConfigFile(worldmt.c_str());
235 std::vector<std::string> names = worldmt_settings.getNames();
236 std::set<std::string> load_mod_names;
237 for(std::vector<std::string>::iterator it = names.begin();
238 it != names.end(); ++it) {
239 std::string name = *it;
240 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
241 load_mod_names.insert(name.substr(9));
243 // complain about mods declared to be loaded, but not found
244 for(std::vector<ModSpec>::iterator it = m_mods.begin();
245 it != m_mods.end(); ++it)
246 load_mod_names.erase((*it).name);
247 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
248 it != unsatisfied_mods.end(); ++it)
249 load_mod_names.erase((*it).name);
250 if(!load_mod_names.empty()) {
251 errorstream << "The following mods could not be found:";
252 for(std::set<std::string>::iterator it = load_mod_names.begin();
253 it != load_mod_names.end(); ++it)
254 errorstream << " \"" << (*it) << "\"";
255 errorstream << std::endl;
259 MutexAutoLock envlock(m_env_mutex);
261 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
262 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
264 // Initialize scripting
265 infostream<<"Server: Initializing Lua"<<std::endl;
267 m_script = new ServerScripting(this);
269 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
272 infostream << "Server: Loading mods: ";
273 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
274 i != m_mods.end(); ++i) {
275 infostream << (*i).name << " ";
277 infostream << std::endl;
278 // Load and run "mod" scripts
279 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
280 it != m_mods.end(); ++it) {
281 const ModSpec &mod = *it;
282 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
283 throw ModError("Error loading mod \"" + mod.name +
284 "\": Mod name does not follow naming conventions: "
285 "Only chararacters [a-z0-9_] are allowed.");
287 std::string script_path = mod.path + DIR_DELIM + "init.lua";
288 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
289 << script_path << "\"]" << std::endl;
290 m_script->loadMod(script_path, mod.name);
293 // Read Textures and calculate sha1 sums
296 // Apply item aliases in the node definition manager
297 m_nodedef->updateAliases(m_itemdef);
299 // Apply texture overrides from texturepack/override.txt
300 std::string texture_path = g_settings->get("texture_path");
301 if (texture_path != "" && fs::IsDir(texture_path))
302 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
304 m_nodedef->setNodeRegistrationStatus(true);
306 // Perform pending node name resolutions
307 m_nodedef->runNodeResolveCallbacks();
309 // unmap node names for connected nodeboxes
310 m_nodedef->mapNodeboxConnections();
312 // init the recipe hashes to speed up crafting
313 m_craftdef->initHashes(this);
315 // Initialize Environment
316 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
318 m_clients.setEnv(m_env);
320 if (!servermap->settings_mgr.makeMapgenParams())
321 FATAL_ERROR("Couldn't create any mapgen type");
323 // Initialize mapgens
324 m_emerge->initMapgens(servermap->getMapgenParams());
326 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
327 if (m_enable_rollback_recording) {
328 // Create rollback manager
329 m_rollback = new RollbackManager(m_path_world, this);
332 // Give environment reference to scripting api
333 m_script->initializeEnvironment(m_env);
335 // Register us to receive map edit events
336 servermap->addEventReceiver(this);
338 // If file exists, load environment metadata
339 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
340 infostream << "Server: Loading environment metadata" << std::endl;
343 m_env->loadDefaultMeta();
346 // Add some test ActiveBlockModifiers to environment
347 add_legacy_abms(m_env, m_nodedef);
349 m_liquid_transform_every = g_settings->getFloat("liquid_update");
350 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
355 infostream<<"Server destructing"<<std::endl;
357 // Send shutdown message
358 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
361 MutexAutoLock envlock(m_env_mutex);
363 // Execute script shutdown hooks
364 m_script->on_shutdown();
366 infostream << "Server: Saving players" << std::endl;
367 m_env->saveLoadedPlayers();
369 infostream << "Server: Kicking players" << std::endl;
370 std::string kick_msg;
371 bool reconnect = false;
372 if (getShutdownRequested()) {
373 reconnect = m_shutdown_ask_reconnect;
374 kick_msg = m_shutdown_msg;
376 if (kick_msg == "") {
377 kick_msg = g_settings->get("kick_msg_shutdown");
379 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
380 kick_msg, reconnect);
382 infostream << "Server: Saving environment metadata" << std::endl;
390 // stop all emerge threads before deleting players that may have
391 // requested blocks to be emerged
392 m_emerge->stopThreads();
394 // Delete things in the reverse order of creation
404 // Deinitialize scripting
405 infostream<<"Server: Deinitializing scripting"<<std::endl;
408 // Delete detached inventories
409 for (std::map<std::string, Inventory*>::iterator
410 i = m_detached_inventories.begin();
411 i != m_detached_inventories.end(); ++i) {
416 void Server::start(Address bind_addr)
418 DSTACK(FUNCTION_NAME);
420 m_bind_addr = bind_addr;
422 infostream<<"Starting server on "
423 << bind_addr.serializeString() <<"..."<<std::endl;
425 // Stop thread if already running
428 // Initialize connection
429 m_con.SetTimeoutMs(30);
430 m_con.Serve(bind_addr);
435 // ASCII art for the win!
437 <<" .__ __ __ "<<std::endl
438 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
439 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
440 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
441 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
442 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
443 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
444 actionstream<<"Server for gameid=\""<<m_gamespec.id
445 <<"\" listening on "<<bind_addr.serializeString()<<":"
446 <<bind_addr.getPort() << "."<<std::endl;
451 DSTACK(FUNCTION_NAME);
453 infostream<<"Server: Stopping and waiting threads"<<std::endl;
455 // Stop threads (set run=false first so both start stopping)
457 //m_emergethread.setRun(false);
459 //m_emergethread.stop();
461 infostream<<"Server: Threads stopped"<<std::endl;
464 void Server::step(float dtime)
466 DSTACK(FUNCTION_NAME);
471 MutexAutoLock lock(m_step_dtime_mutex);
472 m_step_dtime += dtime;
474 // Throw if fatal error occurred in thread
475 std::string async_err = m_async_fatal_error.get();
476 if (!async_err.empty()) {
477 if (!m_simple_singleplayer_mode) {
478 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
479 g_settings->get("kick_msg_crash"),
480 g_settings->getBool("ask_reconnect_on_crash"));
482 throw ServerError("AsyncErr: " + async_err);
486 void Server::AsyncRunStep(bool initial_step)
488 DSTACK(FUNCTION_NAME);
490 g_profiler->add("Server::AsyncRunStep (num)", 1);
494 MutexAutoLock lock1(m_step_dtime_mutex);
495 dtime = m_step_dtime;
499 // Send blocks to clients
503 if((dtime < 0.001) && (initial_step == false))
506 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
508 //infostream<<"Server steps "<<dtime<<std::endl;
509 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
512 MutexAutoLock lock1(m_step_dtime_mutex);
513 m_step_dtime -= dtime;
520 m_uptime.set(m_uptime.get() + dtime);
526 Update time of day and overall game time
528 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
531 Send to clients at constant intervals
534 m_time_of_day_send_timer -= dtime;
535 if(m_time_of_day_send_timer < 0.0) {
536 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
537 u16 time = m_env->getTimeOfDay();
538 float time_speed = g_settings->getFloat("time_speed");
539 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
543 MutexAutoLock lock(m_env_mutex);
544 // Figure out and report maximum lag to environment
545 float max_lag = m_env->getMaxLagEstimate();
546 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
548 if(dtime > 0.1 && dtime > max_lag * 2.0)
549 infostream<<"Server: Maximum lag peaked to "<<dtime
553 m_env->reportMaxLagEstimate(max_lag);
555 ScopeProfiler sp(g_profiler, "SEnv step");
556 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
560 static const float map_timer_and_unload_dtime = 2.92;
561 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
563 MutexAutoLock lock(m_env_mutex);
564 // Run Map's timers and unload unused data
565 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
566 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
567 g_settings->getFloat("server_unload_unused_data_timeout"),
572 Listen to the admin chat, if available
575 if (!m_admin_chat->command_queue.empty()) {
576 MutexAutoLock lock(m_env_mutex);
577 while (!m_admin_chat->command_queue.empty()) {
578 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
579 handleChatInterfaceEvent(evt);
583 m_admin_chat->outgoing_queue.push_back(
584 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
591 /* Transform liquids */
592 m_liquid_transform_timer += dtime;
593 if(m_liquid_transform_timer >= m_liquid_transform_every)
595 m_liquid_transform_timer -= m_liquid_transform_every;
597 MutexAutoLock lock(m_env_mutex);
599 ScopeProfiler sp(g_profiler, "Server: liquid transform");
601 std::map<v3s16, MapBlock*> modified_blocks;
602 m_env->getMap().transformLiquids(modified_blocks);
607 core::map<v3s16, MapBlock*> lighting_modified_blocks;
608 ServerMap &map = ((ServerMap&)m_env->getMap());
609 map.updateLighting(modified_blocks, lighting_modified_blocks);
611 // Add blocks modified by lighting to modified_blocks
612 for(core::map<v3s16, MapBlock*>::Iterator
613 i = lighting_modified_blocks.getIterator();
614 i.atEnd() == false; i++)
616 MapBlock *block = i.getNode()->getValue();
617 modified_blocks.insert(block->getPos(), block);
621 Set the modified blocks unsent for all the clients
623 if(!modified_blocks.empty())
625 SetBlocksNotSent(modified_blocks);
628 m_clients.step(dtime);
630 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
632 // send masterserver announce
634 float &counter = m_masterserver_timer;
635 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
636 g_settings->getBool("server_announce")) {
637 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
638 ServerList::AA_START,
639 m_bind_addr.getPort(),
640 m_clients.getPlayerNames(),
642 m_env->getGameTime(),
645 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
655 Check added and deleted active objects
658 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
659 MutexAutoLock envlock(m_env_mutex);
662 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
663 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
665 // Radius inside which objects are active
666 static const s16 radius =
667 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
669 // Radius inside which players are active
670 static const bool is_transfer_limited =
671 g_settings->exists("unlimited_player_transfer_distance") &&
672 !g_settings->getBool("unlimited_player_transfer_distance");
673 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
674 s16 player_radius = player_transfer_dist;
675 if (player_radius == 0 && is_transfer_limited)
676 player_radius = radius;
678 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
679 i != clients.end(); ++i) {
680 RemoteClient *client = i->second;
682 // If definitions and textures have not been sent, don't
683 // send objects either
684 if (client->getState() < CS_DefinitionsSent)
687 RemotePlayer *player = m_env->getPlayer(client->peer_id);
688 if (player == NULL) {
689 // This can happen if the client timeouts somehow
690 /*warningstream<<FUNCTION_NAME<<": Client "
692 <<" has no associated player"<<std::endl;*/
696 PlayerSAO *playersao = player->getPlayerSAO();
697 if (playersao == NULL)
700 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
701 if (my_radius <= 0) my_radius = radius;
702 //infostream << "Server: Active Radius " << my_radius << std::endl;
704 std::queue<u16> removed_objects;
705 std::queue<u16> added_objects;
706 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
707 client->m_known_objects, removed_objects);
708 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
709 client->m_known_objects, added_objects);
711 // Ignore if nothing happened
712 if (removed_objects.empty() && added_objects.empty()) {
716 std::string data_buffer;
720 // Handle removed objects
721 writeU16((u8*)buf, removed_objects.size());
722 data_buffer.append(buf, 2);
723 while (!removed_objects.empty()) {
725 u16 id = removed_objects.front();
726 ServerActiveObject* obj = m_env->getActiveObject(id);
728 // Add to data buffer for sending
729 writeU16((u8*)buf, id);
730 data_buffer.append(buf, 2);
732 // Remove from known objects
733 client->m_known_objects.erase(id);
735 if(obj && obj->m_known_by_count > 0)
736 obj->m_known_by_count--;
737 removed_objects.pop();
740 // Handle added objects
741 writeU16((u8*)buf, added_objects.size());
742 data_buffer.append(buf, 2);
743 while (!added_objects.empty()) {
745 u16 id = added_objects.front();
746 ServerActiveObject* obj = m_env->getActiveObject(id);
749 u8 type = ACTIVEOBJECT_TYPE_INVALID;
751 warningstream<<FUNCTION_NAME
752 <<": NULL object"<<std::endl;
754 type = obj->getSendType();
756 // Add to data buffer for sending
757 writeU16((u8*)buf, id);
758 data_buffer.append(buf, 2);
759 writeU8((u8*)buf, type);
760 data_buffer.append(buf, 1);
763 data_buffer.append(serializeLongString(
764 obj->getClientInitializationData(client->net_proto_version)));
766 data_buffer.append(serializeLongString(""));
768 // Add to known objects
769 client->m_known_objects.insert(id);
772 obj->m_known_by_count++;
777 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
778 verbosestream << "Server: Sent object remove/add: "
779 << removed_objects.size() << " removed, "
780 << added_objects.size() << " added, "
781 << "packet size is " << pktSize << std::endl;
785 m_mod_storage_save_timer -= dtime;
786 if (m_mod_storage_save_timer <= 0.0f) {
787 infostream << "Saving registered mod storages." << std::endl;
788 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
789 for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
790 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
791 if (it->second->isModified()) {
792 it->second->save(getModStoragePath());
802 MutexAutoLock envlock(m_env_mutex);
803 ScopeProfiler sp(g_profiler, "Server: sending object messages");
806 // Value = data sent by object
807 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
809 // Get active object messages from environment
811 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
815 std::vector<ActiveObjectMessage>* message_list = NULL;
816 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
817 n = buffered_messages.find(aom.id);
818 if (n == buffered_messages.end()) {
819 message_list = new std::vector<ActiveObjectMessage>;
820 buffered_messages[aom.id] = message_list;
823 message_list = n->second;
825 message_list->push_back(aom);
829 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
830 // Route data to every client
831 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
832 i != clients.end(); ++i) {
833 RemoteClient *client = i->second;
834 std::string reliable_data;
835 std::string unreliable_data;
836 // Go through all objects in message buffer
837 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
838 j = buffered_messages.begin();
839 j != buffered_messages.end(); ++j) {
840 // If object is not known by client, skip it
842 if (client->m_known_objects.find(id) == client->m_known_objects.end())
845 // Get message list of object
846 std::vector<ActiveObjectMessage>* list = j->second;
847 // Go through every message
848 for (std::vector<ActiveObjectMessage>::iterator
849 k = list->begin(); k != list->end(); ++k) {
850 // Compose the full new data with header
851 ActiveObjectMessage aom = *k;
852 std::string new_data;
855 writeU16((u8*)&buf[0], aom.id);
856 new_data.append(buf, 2);
858 new_data += serializeString(aom.datastring);
859 // Add data to buffer
861 reliable_data += new_data;
863 unreliable_data += new_data;
867 reliable_data and unreliable_data are now ready.
870 if(reliable_data.size() > 0) {
871 SendActiveObjectMessages(client->peer_id, reliable_data);
874 if(unreliable_data.size() > 0) {
875 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
880 // Clear buffered_messages
881 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
882 i = buffered_messages.begin();
883 i != buffered_messages.end(); ++i) {
889 Send queued-for-sending map edit events.
892 // We will be accessing the environment
893 MutexAutoLock lock(m_env_mutex);
895 // Don't send too many at a time
898 // Single change sending is disabled if queue size is not small
899 bool disable_single_change_sending = false;
900 if(m_unsent_map_edit_queue.size() >= 4)
901 disable_single_change_sending = true;
903 int event_count = m_unsent_map_edit_queue.size();
905 // We'll log the amount of each
908 while(m_unsent_map_edit_queue.size() != 0)
910 MapEditEvent* event = m_unsent_map_edit_queue.front();
911 m_unsent_map_edit_queue.pop();
913 // Players far away from the change are stored here.
914 // Instead of sending the changes, MapBlocks are set not sent
916 std::vector<u16> far_players;
918 switch (event->type) {
921 prof.add("MEET_ADDNODE", 1);
922 sendAddNode(event->p, event->n, event->already_known_by_peer,
923 &far_players, disable_single_change_sending ? 5 : 30,
924 event->type == MEET_ADDNODE);
926 case MEET_REMOVENODE:
927 prof.add("MEET_REMOVENODE", 1);
928 sendRemoveNode(event->p, event->already_known_by_peer,
929 &far_players, disable_single_change_sending ? 5 : 30);
931 case MEET_BLOCK_NODE_METADATA_CHANGED:
932 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
933 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
934 setBlockNotSent(event->p);
937 infostream << "Server: MEET_OTHER" << std::endl;
938 prof.add("MEET_OTHER", 1);
939 for(std::set<v3s16>::iterator
940 i = event->modified_blocks.begin();
941 i != event->modified_blocks.end(); ++i) {
946 prof.add("unknown", 1);
947 warningstream << "Server: Unknown MapEditEvent "
948 << ((u32)event->type) << std::endl;
953 Set blocks not sent to far players
955 if(!far_players.empty()) {
956 // Convert list format to that wanted by SetBlocksNotSent
957 std::map<v3s16, MapBlock*> modified_blocks2;
958 for(std::set<v3s16>::iterator
959 i = event->modified_blocks.begin();
960 i != event->modified_blocks.end(); ++i) {
961 modified_blocks2[*i] =
962 m_env->getMap().getBlockNoCreateNoEx(*i);
965 // Set blocks not sent
966 for(std::vector<u16>::iterator
967 i = far_players.begin();
968 i != far_players.end(); ++i) {
969 if(RemoteClient *client = getClient(*i))
970 client->SetBlocksNotSent(modified_blocks2);
976 /*// Don't send too many at a time
978 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
982 if(event_count >= 5){
983 infostream<<"Server: MapEditEvents:"<<std::endl;
984 prof.print(infostream);
985 } else if(event_count != 0){
986 verbosestream<<"Server: MapEditEvents:"<<std::endl;
987 prof.print(verbosestream);
993 Trigger emergethread (it somehow gets to a non-triggered but
994 bysy state sometimes)
997 float &counter = m_emergethread_trigger_timer;
999 if (counter >= 2.0) {
1002 m_emerge->startThreads();
1006 // Save map, players and auth stuff
1008 float &counter = m_savemap_timer;
1010 static const float save_interval =
1011 g_settings->getFloat("server_map_save_interval");
1012 if (counter >= save_interval) {
1014 MutexAutoLock lock(m_env_mutex);
1016 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1019 if (m_banmanager->isModified()) {
1020 m_banmanager->save();
1023 // Save changed parts of map
1024 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1027 m_env->saveLoadedPlayers();
1029 // Save environment metadata
1035 static const float shutdown_msg_times[] =
1037 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
1040 if (m_shutdown_timer > 0.0f) {
1041 // Automated messages
1042 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
1043 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
1044 // If shutdown timer matches an automessage, shot it
1045 if (m_shutdown_timer > shutdown_msg_times[i] &&
1046 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1047 std::wstringstream ws;
1049 ws << L"*** Server shutting down in "
1050 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1053 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1054 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1060 m_shutdown_timer -= dtime;
1061 if (m_shutdown_timer < 0.0f) {
1062 m_shutdown_timer = 0.0f;
1063 m_shutdown_requested = true;
1068 void Server::Receive()
1070 DSTACK(FUNCTION_NAME);
1071 SharedBuffer<u8> data;
1075 m_con.Receive(&pkt);
1076 peer_id = pkt.getPeerId();
1079 catch(con::InvalidIncomingDataException &e) {
1080 infostream<<"Server::Receive(): "
1081 "InvalidIncomingDataException: what()="
1082 <<e.what()<<std::endl;
1084 catch(SerializationError &e) {
1085 infostream<<"Server::Receive(): "
1086 "SerializationError: what()="
1087 <<e.what()<<std::endl;
1089 catch(ClientStateError &e) {
1090 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1091 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1092 L"Try reconnecting or updating your client");
1094 catch(con::PeerNotFoundException &e) {
1099 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1101 std::string playername = "";
1102 PlayerSAO *playersao = NULL;
1105 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1106 if (client != NULL) {
1107 playername = client->getName();
1108 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1110 } catch (std::exception &e) {
1116 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1118 // If failed, cancel
1119 if ((playersao == NULL) || (player == NULL)) {
1120 if (player && player->peer_id != 0) {
1121 actionstream << "Server: Failed to emerge player \"" << playername
1122 << "\" (player allocated to an another client)" << std::endl;
1123 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1124 L"name. If your client closed unexpectedly, try again in "
1127 errorstream << "Server: " << playername << ": Failed to emerge player"
1129 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1135 Send complete position information
1137 SendMovePlayer(peer_id);
1140 SendPlayerPrivileges(peer_id);
1142 // Send inventory formspec
1143 SendPlayerInventoryFormspec(peer_id);
1146 SendInventory(playersao);
1148 // Send HP or death screen
1149 if (playersao->isDead())
1150 SendDeathscreen(peer_id, false, v3f(0,0,0));
1152 SendPlayerHPOrDie(playersao);
1155 SendPlayerBreath(playersao);
1157 // Note things in chat if not in simple singleplayer mode
1158 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1159 // Send information about server to player in chat
1160 SendChatMessage(peer_id, getStatusString());
1162 Address addr = getPeerAddress(player->peer_id);
1163 std::string ip_str = addr.serializeString();
1164 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1169 const std::vector<std::string> &names = m_clients.getPlayerNames();
1171 actionstream << player->getName() << " joins game. List of players: ";
1173 for (std::vector<std::string>::const_iterator i = names.begin();
1174 i != names.end(); ++i) {
1175 actionstream << *i << " ";
1178 actionstream << player->getName() <<std::endl;
1183 inline void Server::handleCommand(NetworkPacket* pkt)
1185 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1186 (this->*opHandle.handler)(pkt);
1189 void Server::ProcessData(NetworkPacket *pkt)
1191 DSTACK(FUNCTION_NAME);
1192 // Environment is locked first.
1193 MutexAutoLock envlock(m_env_mutex);
1195 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1196 u32 peer_id = pkt->getPeerId();
1199 Address address = getPeerAddress(peer_id);
1200 std::string addr_s = address.serializeString();
1202 if(m_banmanager->isIpBanned(addr_s)) {
1203 std::string ban_name = m_banmanager->getBanName(addr_s);
1204 infostream << "Server: A banned client tried to connect from "
1205 << addr_s << "; banned name was "
1206 << ban_name << std::endl;
1207 // This actually doesn't seem to transfer to the client
1208 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1209 + utf8_to_wide(ban_name));
1213 catch(con::PeerNotFoundException &e) {
1215 * no peer for this packet found
1216 * most common reason is peer timeout, e.g. peer didn't
1217 * respond for some time, your server was overloaded or
1220 infostream << "Server::ProcessData(): Canceling: peer "
1221 << peer_id << " not found" << std::endl;
1226 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1228 // Command must be handled into ToServerCommandHandler
1229 if (command >= TOSERVER_NUM_MSG_TYPES) {
1230 infostream << "Server: Ignoring unknown command "
1231 << command << std::endl;
1235 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1240 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1242 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1243 errorstream << "Server::ProcessData(): Cancelling: Peer"
1244 " serialization format invalid or not initialized."
1245 " Skipping incoming command=" << command << std::endl;
1249 /* Handle commands related to client startup */
1250 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1255 if (m_clients.getClientState(peer_id) < CS_Active) {
1256 if (command == TOSERVER_PLAYERPOS) return;
1258 errorstream << "Got packet command: " << command << " for peer id "
1259 << peer_id << " but client isn't active yet. Dropping packet "
1265 } catch (SendFailedException &e) {
1266 errorstream << "Server::ProcessData(): SendFailedException: "
1267 << "what=" << e.what()
1269 } catch (PacketError &e) {
1270 actionstream << "Server::ProcessData(): PacketError: "
1271 << "what=" << e.what()
1276 void Server::setTimeOfDay(u32 time)
1278 m_env->setTimeOfDay(time);
1279 m_time_of_day_send_timer = 0;
1282 void Server::onMapEditEvent(MapEditEvent *event)
1284 if(m_ignore_map_edit_events)
1286 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1288 MapEditEvent *e = event->clone();
1289 m_unsent_map_edit_queue.push(e);
1292 Inventory* Server::getInventory(const InventoryLocation &loc)
1295 case InventoryLocation::UNDEFINED:
1296 case InventoryLocation::CURRENT_PLAYER:
1298 case InventoryLocation::PLAYER:
1300 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1303 PlayerSAO *playersao = player->getPlayerSAO();
1306 return playersao->getInventory();
1309 case InventoryLocation::NODEMETA:
1311 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1314 return meta->getInventory();
1317 case InventoryLocation::DETACHED:
1319 if(m_detached_inventories.count(loc.name) == 0)
1321 return m_detached_inventories[loc.name];
1325 sanity_check(false); // abort
1330 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1333 case InventoryLocation::UNDEFINED:
1335 case InventoryLocation::PLAYER:
1340 RemotePlayer *player =
1341 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1346 PlayerSAO *playersao = player->getPlayerSAO();
1350 SendInventory(playersao);
1353 case InventoryLocation::NODEMETA:
1355 v3s16 blockpos = getNodeBlockPos(loc.p);
1357 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1359 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1361 setBlockNotSent(blockpos);
1364 case InventoryLocation::DETACHED:
1366 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1370 sanity_check(false); // abort
1375 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1377 std::vector<u16> clients = m_clients.getClientIDs();
1379 // Set the modified blocks unsent for all the clients
1380 for (std::vector<u16>::iterator i = clients.begin();
1381 i != clients.end(); ++i) {
1382 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1383 client->SetBlocksNotSent(block);
1388 void Server::peerAdded(con::Peer *peer)
1390 DSTACK(FUNCTION_NAME);
1391 verbosestream<<"Server::peerAdded(): peer->id="
1392 <<peer->id<<std::endl;
1395 c.type = con::PEER_ADDED;
1396 c.peer_id = peer->id;
1398 m_peer_change_queue.push(c);
1401 void Server::deletingPeer(con::Peer *peer, bool timeout)
1403 DSTACK(FUNCTION_NAME);
1404 verbosestream<<"Server::deletingPeer(): peer->id="
1405 <<peer->id<<", timeout="<<timeout<<std::endl;
1407 m_clients.event(peer->id, CSE_Disconnect);
1409 c.type = con::PEER_REMOVED;
1410 c.peer_id = peer->id;
1411 c.timeout = timeout;
1412 m_peer_change_queue.push(c);
1415 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1417 *retval = m_con.getPeerStat(peer_id,type);
1418 if (*retval == -1) return false;
1422 bool Server::getClientInfo(
1431 std::string* vers_string
1434 *state = m_clients.getClientState(peer_id);
1436 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1438 if (client == NULL) {
1443 *uptime = client->uptime();
1444 *ser_vers = client->serialization_version;
1445 *prot_vers = client->net_proto_version;
1447 *major = client->getMajor();
1448 *minor = client->getMinor();
1449 *patch = client->getPatch();
1450 *vers_string = client->getPatch();
1457 void Server::handlePeerChanges()
1459 while(m_peer_change_queue.size() > 0)
1461 con::PeerChange c = m_peer_change_queue.front();
1462 m_peer_change_queue.pop();
1464 verbosestream<<"Server: Handling peer change: "
1465 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1470 case con::PEER_ADDED:
1471 m_clients.CreateClient(c.peer_id);
1474 case con::PEER_REMOVED:
1475 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1479 FATAL_ERROR("Invalid peer change event received!");
1485 void Server::printToConsoleOnly(const std::string &text)
1488 m_admin_chat->outgoing_queue.push_back(
1489 new ChatEventChat("", utf8_to_wide(text)));
1491 std::cout << text << std::endl;
1495 void Server::Send(NetworkPacket* pkt)
1497 m_clients.send(pkt->getPeerId(),
1498 clientCommandFactoryTable[pkt->getCommand()].channel,
1500 clientCommandFactoryTable[pkt->getCommand()].reliable);
1503 void Server::SendMovement(u16 peer_id)
1505 DSTACK(FUNCTION_NAME);
1506 std::ostringstream os(std::ios_base::binary);
1508 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1510 pkt << g_settings->getFloat("movement_acceleration_default");
1511 pkt << g_settings->getFloat("movement_acceleration_air");
1512 pkt << g_settings->getFloat("movement_acceleration_fast");
1513 pkt << g_settings->getFloat("movement_speed_walk");
1514 pkt << g_settings->getFloat("movement_speed_crouch");
1515 pkt << g_settings->getFloat("movement_speed_fast");
1516 pkt << g_settings->getFloat("movement_speed_climb");
1517 pkt << g_settings->getFloat("movement_speed_jump");
1518 pkt << g_settings->getFloat("movement_liquid_fluidity");
1519 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1520 pkt << g_settings->getFloat("movement_liquid_sink");
1521 pkt << g_settings->getFloat("movement_gravity");
1526 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1528 if (!g_settings->getBool("enable_damage"))
1531 u16 peer_id = playersao->getPeerID();
1532 bool is_alive = playersao->getHP() > 0;
1535 SendPlayerHP(peer_id);
1540 void Server::SendHP(u16 peer_id, u8 hp)
1542 DSTACK(FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1549 void Server::SendBreath(u16 peer_id, u16 breath)
1551 DSTACK(FUNCTION_NAME);
1553 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1554 pkt << (u16) breath;
1558 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1559 const std::string &custom_reason, bool reconnect)
1561 assert(reason < SERVER_ACCESSDENIED_MAX);
1563 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1565 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1566 pkt << custom_reason;
1567 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1568 reason == SERVER_ACCESSDENIED_CRASH)
1569 pkt << custom_reason << (u8)reconnect;
1573 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1575 DSTACK(FUNCTION_NAME);
1577 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1582 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1583 v3f camera_point_target)
1585 DSTACK(FUNCTION_NAME);
1587 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1588 pkt << set_camera_point_target << camera_point_target;
1592 void Server::SendItemDef(u16 peer_id,
1593 IItemDefManager *itemdef, u16 protocol_version)
1595 DSTACK(FUNCTION_NAME);
1597 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1601 u32 length of the next item
1602 zlib-compressed serialized ItemDefManager
1604 std::ostringstream tmp_os(std::ios::binary);
1605 itemdef->serialize(tmp_os, protocol_version);
1606 std::ostringstream tmp_os2(std::ios::binary);
1607 compressZlib(tmp_os.str(), tmp_os2);
1608 pkt.putLongString(tmp_os2.str());
1611 verbosestream << "Server: Sending item definitions to id(" << peer_id
1612 << "): size=" << pkt.getSize() << std::endl;
1617 void Server::SendNodeDef(u16 peer_id,
1618 INodeDefManager *nodedef, u16 protocol_version)
1620 DSTACK(FUNCTION_NAME);
1622 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1626 u32 length of the next item
1627 zlib-compressed serialized NodeDefManager
1629 std::ostringstream tmp_os(std::ios::binary);
1630 nodedef->serialize(tmp_os, protocol_version);
1631 std::ostringstream tmp_os2(std::ios::binary);
1632 compressZlib(tmp_os.str(), tmp_os2);
1634 pkt.putLongString(tmp_os2.str());
1637 verbosestream << "Server: Sending node definitions to id(" << peer_id
1638 << "): size=" << pkt.getSize() << std::endl;
1644 Non-static send methods
1647 void Server::SendInventory(PlayerSAO* playerSAO)
1649 DSTACK(FUNCTION_NAME);
1651 UpdateCrafting(playerSAO->getPlayer());
1657 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1659 std::ostringstream os;
1660 playerSAO->getInventory()->serialize(os);
1662 std::string s = os.str();
1664 pkt.putRawString(s.c_str(), s.size());
1668 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1670 DSTACK(FUNCTION_NAME);
1672 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1675 if (peer_id != PEER_ID_INEXISTENT) {
1679 m_clients.sendToAll(&pkt);
1683 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1684 const std::string &formname)
1686 DSTACK(FUNCTION_NAME);
1688 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1689 if (formspec == "" ){
1690 //the client should close the formspec
1691 pkt.putLongString("");
1693 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1700 // Spawns a particle on peer with peer_id
1701 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1702 v3f pos, v3f velocity, v3f acceleration,
1703 float expirationtime, float size, bool collisiondetection,
1704 bool collision_removal,
1705 bool vertical, const std::string &texture,
1706 const struct TileAnimationParams &animation, u8 glow)
1708 DSTACK(FUNCTION_NAME);
1709 if (peer_id == PEER_ID_INEXISTENT) {
1710 // This sucks and should be replaced by a better solution in a refactor:
1711 std::vector<u16> clients = m_clients.getClientIDs();
1712 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1713 RemotePlayer *player = m_env->getPlayer(*i);
1716 SendSpawnParticle(*i, player->protocol_version,
1717 pos, velocity, acceleration,
1718 expirationtime, size, collisiondetection,
1719 collision_removal, vertical, texture, animation, glow);
1724 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1726 pkt << pos << velocity << acceleration << expirationtime
1727 << size << collisiondetection;
1728 pkt.putLongString(texture);
1730 pkt << collision_removal;
1731 // This is horrible but required (why are there two ways to serialize pkts?)
1732 std::ostringstream os(std::ios_base::binary);
1733 animation.serialize(os, protocol_version);
1734 pkt.putRawString(os.str());
1740 // Adds a ParticleSpawner on peer with peer_id
1741 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1742 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1743 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1744 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1745 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1746 const struct TileAnimationParams &animation, u8 glow)
1748 DSTACK(FUNCTION_NAME);
1749 if (peer_id == PEER_ID_INEXISTENT) {
1750 // This sucks and should be replaced:
1751 std::vector<u16> clients = m_clients.getClientIDs();
1752 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1753 RemotePlayer *player = m_env->getPlayer(*i);
1756 SendAddParticleSpawner(*i, player->protocol_version,
1757 amount, spawntime, minpos, maxpos,
1758 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1759 minsize, maxsize, collisiondetection, collision_removal,
1760 attached_id, vertical, texture, id, animation, glow);
1765 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1767 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1768 << minacc << maxacc << minexptime << maxexptime << minsize
1769 << maxsize << collisiondetection;
1771 pkt.putLongString(texture);
1773 pkt << id << vertical;
1774 pkt << collision_removal;
1776 // This is horrible but required
1777 std::ostringstream os(std::ios_base::binary);
1778 animation.serialize(os, protocol_version);
1779 pkt.putRawString(os.str());
1785 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1787 DSTACK(FUNCTION_NAME);
1789 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1791 // Ugly error in this packet
1794 if (peer_id != PEER_ID_INEXISTENT) {
1798 m_clients.sendToAll(&pkt);
1803 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1805 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1807 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1808 << form->text << form->number << form->item << form->dir
1809 << form->align << form->offset << form->world_pos << form->size;
1814 void Server::SendHUDRemove(u16 peer_id, u32 id)
1816 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1821 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1823 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1824 pkt << id << (u8) stat;
1828 case HUD_STAT_SCALE:
1829 case HUD_STAT_ALIGN:
1830 case HUD_STAT_OFFSET:
1831 pkt << *(v2f *) value;
1835 pkt << *(std::string *) value;
1837 case HUD_STAT_WORLD_POS:
1838 pkt << *(v3f *) value;
1841 pkt << *(v2s32 *) value;
1843 case HUD_STAT_NUMBER:
1847 pkt << *(u32 *) value;
1854 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1856 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1858 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1860 pkt << flags << mask;
1865 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1867 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1868 pkt << param << value;
1872 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1873 const std::string &type, const std::vector<std::string> ¶ms)
1875 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1876 pkt << bgcolor << type << (u16) params.size();
1878 for(size_t i=0; i<params.size(); i++)
1884 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1887 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1890 pkt << do_override << (u16) (ratio * 65535);
1895 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1897 DSTACK(FUNCTION_NAME);
1899 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1900 pkt << time << time_speed;
1902 if (peer_id == PEER_ID_INEXISTENT) {
1903 m_clients.sendToAll(&pkt);
1910 void Server::SendPlayerHP(u16 peer_id)
1912 DSTACK(FUNCTION_NAME);
1913 PlayerSAO *playersao = getPlayerSAO(peer_id);
1914 // In some rare case if the player is disconnected
1915 // while Lua call l_punch, for example, this can be NULL
1919 SendHP(peer_id, playersao->getHP());
1920 m_script->player_event(playersao,"health_changed");
1922 // Send to other clients
1923 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1924 ActiveObjectMessage aom(playersao->getId(), true, str);
1925 playersao->m_messages_out.push(aom);
1928 void Server::SendPlayerBreath(PlayerSAO *sao)
1930 DSTACK(FUNCTION_NAME);
1933 m_script->player_event(sao, "breath_changed");
1934 SendBreath(sao->getPeerID(), sao->getBreath());
1937 void Server::SendMovePlayer(u16 peer_id)
1939 DSTACK(FUNCTION_NAME);
1940 RemotePlayer *player = m_env->getPlayer(peer_id);
1942 PlayerSAO *sao = player->getPlayerSAO();
1945 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1946 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1949 v3f pos = sao->getBasePosition();
1950 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1951 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1952 << " pitch=" << sao->getPitch()
1953 << " yaw=" << sao->getYaw()
1960 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1962 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1965 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1966 << animation_frames[3] << animation_speed;
1971 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1973 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1974 pkt << first << third;
1977 void Server::SendPlayerPrivileges(u16 peer_id)
1979 RemotePlayer *player = m_env->getPlayer(peer_id);
1981 if(player->peer_id == PEER_ID_INEXISTENT)
1984 std::set<std::string> privs;
1985 m_script->getAuth(player->getName(), NULL, &privs);
1987 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1988 pkt << (u16) privs.size();
1990 for(std::set<std::string>::const_iterator i = privs.begin();
1991 i != privs.end(); ++i) {
1998 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2000 RemotePlayer *player = m_env->getPlayer(peer_id);
2002 if(player->peer_id == PEER_ID_INEXISTENT)
2005 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2006 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2010 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2012 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2013 pkt.putRawString(datas.c_str(), datas.size());
2015 return pkt.getSize();
2018 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2020 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2021 datas.size(), peer_id);
2023 pkt.putRawString(datas.c_str(), datas.size());
2025 m_clients.send(pkt.getPeerId(),
2026 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2031 s32 Server::playSound(const SimpleSoundSpec &spec,
2032 const ServerSoundParams ¶ms)
2034 // Find out initial position of sound
2035 bool pos_exists = false;
2036 v3f pos = params.getPos(m_env, &pos_exists);
2037 // If position is not found while it should be, cancel sound
2038 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2041 // Filter destination clients
2042 std::vector<u16> dst_clients;
2043 if(params.to_player != "")
2045 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2047 infostream<<"Server::playSound: Player \""<<params.to_player
2048 <<"\" not found"<<std::endl;
2051 if(player->peer_id == PEER_ID_INEXISTENT){
2052 infostream<<"Server::playSound: Player \""<<params.to_player
2053 <<"\" not connected"<<std::endl;
2056 dst_clients.push_back(player->peer_id);
2059 std::vector<u16> clients = m_clients.getClientIDs();
2061 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2062 RemotePlayer *player = m_env->getPlayer(*i);
2066 PlayerSAO *sao = player->getPlayerSAO();
2071 if(sao->getBasePosition().getDistanceFrom(pos) >
2072 params.max_hear_distance)
2075 dst_clients.push_back(*i);
2079 if(dst_clients.empty())
2083 s32 id = m_next_sound_id++;
2084 // The sound will exist as a reference in m_playing_sounds
2085 m_playing_sounds[id] = ServerPlayingSound();
2086 ServerPlayingSound &psound = m_playing_sounds[id];
2087 psound.params = params;
2089 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2090 pkt << id << spec.name << (float) (spec.gain * params.gain)
2091 << (u8) params.type << pos << params.object << params.loop;
2093 for(std::vector<u16>::iterator i = dst_clients.begin();
2094 i != dst_clients.end(); ++i) {
2095 psound.clients.insert(*i);
2096 m_clients.send(*i, 0, &pkt, true);
2100 void Server::stopSound(s32 handle)
2102 // Get sound reference
2103 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2104 if (i == m_playing_sounds.end())
2106 ServerPlayingSound &psound = i->second;
2108 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2111 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2112 i != psound.clients.end(); ++i) {
2114 m_clients.send(*i, 0, &pkt, true);
2116 // Remove sound reference
2117 m_playing_sounds.erase(i);
2120 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2121 std::vector<u16> *far_players, float far_d_nodes)
2123 float maxd = far_d_nodes*BS;
2124 v3f p_f = intToFloat(p, BS);
2126 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2129 std::vector<u16> clients = m_clients.getClientIDs();
2130 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2133 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2134 PlayerSAO *sao = player->getPlayerSAO();
2138 // If player is far away, only set modified blocks not sent
2139 v3f player_pos = sao->getBasePosition();
2140 if (player_pos.getDistanceFrom(p_f) > maxd) {
2141 far_players->push_back(*i);
2148 m_clients.send(*i, 0, &pkt, true);
2152 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2153 std::vector<u16> *far_players, float far_d_nodes,
2154 bool remove_metadata)
2156 float maxd = far_d_nodes*BS;
2157 v3f p_f = intToFloat(p, BS);
2159 std::vector<u16> clients = m_clients.getClientIDs();
2160 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2163 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2164 PlayerSAO *sao = player->getPlayerSAO();
2168 // If player is far away, only set modified blocks not sent
2169 v3f player_pos = sao->getBasePosition();
2170 if(player_pos.getDistanceFrom(p_f) > maxd) {
2171 far_players->push_back(*i);
2177 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2179 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2181 pkt << p << n.param0 << n.param1 << n.param2
2182 << (u8) (remove_metadata ? 0 : 1);
2187 if (pkt.getSize() > 0)
2188 m_clients.send(*i, 0, &pkt, true);
2192 void Server::setBlockNotSent(v3s16 p)
2194 std::vector<u16> clients = m_clients.getClientIDs();
2196 for(std::vector<u16>::iterator i = clients.begin();
2197 i != clients.end(); ++i) {
2198 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2199 client->SetBlockNotSent(p);
2204 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2206 DSTACK(FUNCTION_NAME);
2208 v3s16 p = block->getPos();
2211 Create a packet with the block in the right format
2214 std::ostringstream os(std::ios_base::binary);
2215 block->serialize(os, ver, false);
2216 block->serializeNetworkSpecific(os);
2217 std::string s = os.str();
2219 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2222 pkt.putRawString(s.c_str(), s.size());
2226 void Server::SendBlocks(float dtime)
2228 DSTACK(FUNCTION_NAME);
2230 MutexAutoLock envlock(m_env_mutex);
2231 //TODO check if one big lock could be faster then multiple small ones
2233 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2235 std::vector<PrioritySortedBlockTransfer> queue;
2237 s32 total_sending = 0;
2240 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2242 std::vector<u16> clients = m_clients.getClientIDs();
2245 for(std::vector<u16>::iterator i = clients.begin();
2246 i != clients.end(); ++i) {
2247 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2252 total_sending += client->SendingCount();
2253 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2259 // Lowest priority number comes first.
2260 // Lowest is most important.
2261 std::sort(queue.begin(), queue.end());
2264 for(u32 i=0; i<queue.size(); i++)
2266 //TODO: Calculate limit dynamically
2267 if(total_sending >= g_settings->getS32
2268 ("max_simultaneous_block_sends_server_total"))
2271 PrioritySortedBlockTransfer q = queue[i];
2273 MapBlock *block = NULL;
2276 block = m_env->getMap().getBlockNoCreate(q.pos);
2278 catch(InvalidPositionException &e)
2283 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2288 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2290 client->SentBlock(q.pos);
2296 void Server::fillMediaCache()
2298 DSTACK(FUNCTION_NAME);
2300 infostream<<"Server: Calculating media file checksums"<<std::endl;
2302 // Collect all media file paths
2303 std::vector<std::string> paths;
2304 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2305 i != m_mods.end(); ++i) {
2306 const ModSpec &mod = *i;
2307 paths.push_back(mod.path + DIR_DELIM + "textures");
2308 paths.push_back(mod.path + DIR_DELIM + "sounds");
2309 paths.push_back(mod.path + DIR_DELIM + "media");
2310 paths.push_back(mod.path + DIR_DELIM + "models");
2312 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2314 // Collect media file information from paths into cache
2315 for(std::vector<std::string>::iterator i = paths.begin();
2316 i != paths.end(); ++i) {
2317 std::string mediapath = *i;
2318 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2319 for (u32 j = 0; j < dirlist.size(); j++) {
2320 if (dirlist[j].dir) // Ignode dirs
2322 std::string filename = dirlist[j].name;
2323 // If name contains illegal characters, ignore the file
2324 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2325 infostream<<"Server: ignoring illegal file name: \""
2326 << filename << "\"" << std::endl;
2329 // If name is not in a supported format, ignore it
2330 const char *supported_ext[] = {
2331 ".png", ".jpg", ".bmp", ".tga",
2332 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2334 ".x", ".b3d", ".md2", ".obj",
2337 if (removeStringEnd(filename, supported_ext) == ""){
2338 infostream << "Server: ignoring unsupported file extension: \""
2339 << filename << "\"" << std::endl;
2342 // Ok, attempt to load the file and add to cache
2343 std::string filepath = mediapath + DIR_DELIM + filename;
2345 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2347 errorstream << "Server::fillMediaCache(): Could not open \""
2348 << filename << "\" for reading" << std::endl;
2351 std::ostringstream tmp_os(std::ios_base::binary);
2355 fis.read(buf, 1024);
2356 std::streamsize len = fis.gcount();
2357 tmp_os.write(buf, len);
2366 errorstream<<"Server::fillMediaCache(): Failed to read \""
2367 << filename << "\"" << std::endl;
2370 if(tmp_os.str().length() == 0) {
2371 errorstream << "Server::fillMediaCache(): Empty file \""
2372 << filepath << "\"" << std::endl;
2377 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2379 unsigned char *digest = sha1.getDigest();
2380 std::string sha1_base64 = base64_encode(digest, 20);
2381 std::string sha1_hex = hex_encode((char*)digest, 20);
2385 m_media[filename] = MediaInfo(filepath, sha1_base64);
2386 verbosestream << "Server: " << sha1_hex << " is " << filename
2392 void Server::sendMediaAnnouncement(u16 peer_id)
2394 DSTACK(FUNCTION_NAME);
2396 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2400 std::ostringstream os(std::ios_base::binary);
2402 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2403 pkt << (u16) m_media.size();
2405 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2406 i != m_media.end(); ++i) {
2407 pkt << i->first << i->second.sha1_digest;
2410 pkt << g_settings->get("remote_media");
2414 struct SendableMedia
2420 SendableMedia(const std::string &name_="", const std::string &path_="",
2421 const std::string &data_=""):
2428 void Server::sendRequestedMedia(u16 peer_id,
2429 const std::vector<std::string> &tosend)
2431 DSTACK(FUNCTION_NAME);
2433 verbosestream<<"Server::sendRequestedMedia(): "
2434 <<"Sending files to client"<<std::endl;
2438 // Put 5kB in one bunch (this is not accurate)
2439 u32 bytes_per_bunch = 5000;
2441 std::vector< std::vector<SendableMedia> > file_bunches;
2442 file_bunches.push_back(std::vector<SendableMedia>());
2444 u32 file_size_bunch_total = 0;
2446 for(std::vector<std::string>::const_iterator i = tosend.begin();
2447 i != tosend.end(); ++i) {
2448 const std::string &name = *i;
2450 if (m_media.find(name) == m_media.end()) {
2451 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2452 <<"unknown file \""<<(name)<<"\""<<std::endl;
2456 //TODO get path + name
2457 std::string tpath = m_media[name].path;
2460 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2461 if(fis.good() == false){
2462 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2463 <<tpath<<"\" for reading"<<std::endl;
2466 std::ostringstream tmp_os(std::ios_base::binary);
2470 fis.read(buf, 1024);
2471 std::streamsize len = fis.gcount();
2472 tmp_os.write(buf, len);
2473 file_size_bunch_total += len;
2482 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2483 <<name<<"\""<<std::endl;
2486 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2487 <<tname<<"\""<<std::endl;*/
2489 file_bunches[file_bunches.size()-1].push_back(
2490 SendableMedia(name, tpath, tmp_os.str()));
2492 // Start next bunch if got enough data
2493 if(file_size_bunch_total >= bytes_per_bunch) {
2494 file_bunches.push_back(std::vector<SendableMedia>());
2495 file_size_bunch_total = 0;
2500 /* Create and send packets */
2502 u16 num_bunches = file_bunches.size();
2503 for(u16 i = 0; i < num_bunches; i++) {
2506 u16 total number of texture bunches
2507 u16 index of this bunch
2508 u32 number of files in this bunch
2517 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2518 pkt << num_bunches << i << (u32) file_bunches[i].size();
2520 for(std::vector<SendableMedia>::iterator
2521 j = file_bunches[i].begin();
2522 j != file_bunches[i].end(); ++j) {
2524 pkt.putLongString(j->data);
2527 verbosestream << "Server::sendRequestedMedia(): bunch "
2528 << i << "/" << num_bunches
2529 << " files=" << file_bunches[i].size()
2530 << " size=" << pkt.getSize() << std::endl;
2535 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2537 if(m_detached_inventories.count(name) == 0) {
2538 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2541 Inventory *inv = m_detached_inventories[name];
2542 std::ostringstream os(std::ios_base::binary);
2544 os << serializeString(name);
2548 std::string s = os.str();
2550 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2551 pkt.putRawString(s.c_str(), s.size());
2553 const std::string &check = m_detached_inventories_player[name];
2554 if (peer_id == PEER_ID_INEXISTENT) {
2556 return m_clients.sendToAll(&pkt);
2557 RemotePlayer *p = m_env->getPlayer(check.c_str());
2559 m_clients.send(p->peer_id, 0, &pkt, true);
2561 if (check == "" || getPlayerName(peer_id) == check)
2566 void Server::sendDetachedInventories(u16 peer_id)
2568 DSTACK(FUNCTION_NAME);
2570 for(std::map<std::string, Inventory*>::iterator
2571 i = m_detached_inventories.begin();
2572 i != m_detached_inventories.end(); ++i) {
2573 const std::string &name = i->first;
2574 //Inventory *inv = i->second;
2575 sendDetachedInventory(name, peer_id);
2583 void Server::DiePlayer(u16 peer_id)
2585 DSTACK(FUNCTION_NAME);
2586 PlayerSAO *playersao = getPlayerSAO(peer_id);
2587 // In some rare cases this can be NULL -- if the player is disconnected
2588 // when a Lua function modifies l_punch, for example
2592 infostream << "Server::DiePlayer(): Player "
2593 << playersao->getPlayer()->getName()
2594 << " dies" << std::endl;
2596 playersao->setHP(0);
2598 // Trigger scripted stuff
2599 m_script->on_dieplayer(playersao);
2601 SendPlayerHP(peer_id);
2602 SendDeathscreen(peer_id, false, v3f(0,0,0));
2605 void Server::RespawnPlayer(u16 peer_id)
2607 DSTACK(FUNCTION_NAME);
2609 PlayerSAO *playersao = getPlayerSAO(peer_id);
2612 infostream << "Server::RespawnPlayer(): Player "
2613 << playersao->getPlayer()->getName()
2614 << " respawns" << std::endl;
2616 playersao->setHP(PLAYER_MAX_HP);
2617 playersao->setBreath(PLAYER_MAX_BREATH);
2619 bool repositioned = m_script->on_respawnplayer(playersao);
2620 if (!repositioned) {
2621 v3f pos = findSpawnPos();
2622 // setPos will send the new position to client
2623 playersao->setPos(pos);
2626 SendPlayerHP(peer_id);
2630 void Server::DenySudoAccess(u16 peer_id)
2632 DSTACK(FUNCTION_NAME);
2634 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2639 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2640 const std::string &str_reason, bool reconnect)
2642 if (proto_ver >= 25) {
2643 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2645 std::wstring wreason = utf8_to_wide(
2646 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2647 accessDeniedStrings[(u8)reason]);
2648 SendAccessDenied_Legacy(peer_id, wreason);
2651 m_clients.event(peer_id, CSE_SetDenied);
2652 m_con.DisconnectPeer(peer_id);
2656 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2658 DSTACK(FUNCTION_NAME);
2660 SendAccessDenied(peer_id, reason, custom_reason);
2661 m_clients.event(peer_id, CSE_SetDenied);
2662 m_con.DisconnectPeer(peer_id);
2665 // 13/03/15: remove this function when protocol version 25 will become
2666 // the minimum version for MT users, maybe in 1 year
2667 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2669 DSTACK(FUNCTION_NAME);
2671 SendAccessDenied_Legacy(peer_id, reason);
2672 m_clients.event(peer_id, CSE_SetDenied);
2673 m_con.DisconnectPeer(peer_id);
2676 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2678 DSTACK(FUNCTION_NAME);
2681 RemoteClient* client = getClient(peer_id, CS_Invalid);
2683 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2685 // Right now, the auth mechs don't change between login and sudo mode.
2686 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2687 client->allowed_sudo_mechs = sudo_auth_mechs;
2689 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2690 << g_settings->getFloat("dedicated_server_step")
2694 m_clients.event(peer_id, CSE_AuthAccept);
2696 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2698 // We only support SRP right now
2699 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2701 resp_pkt << sudo_auth_mechs;
2703 m_clients.event(peer_id, CSE_SudoSuccess);
2707 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2709 DSTACK(FUNCTION_NAME);
2710 std::wstring message;
2713 Clear references to playing sounds
2715 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2716 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2717 ServerPlayingSound &psound = i->second;
2718 psound.clients.erase(peer_id);
2719 if (psound.clients.empty())
2720 m_playing_sounds.erase(i++);
2725 RemotePlayer *player = m_env->getPlayer(peer_id);
2727 /* Run scripts and remove from environment */
2728 if (player != NULL) {
2729 PlayerSAO *playersao = player->getPlayerSAO();
2732 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2734 playersao->disconnected();
2741 if(player != NULL && reason != CDR_DENY) {
2742 std::ostringstream os(std::ios_base::binary);
2743 std::vector<u16> clients = m_clients.getClientIDs();
2745 for(std::vector<u16>::iterator i = clients.begin();
2746 i != clients.end(); ++i) {
2748 RemotePlayer *player = m_env->getPlayer(*i);
2752 // Get name of player
2753 os << player->getName() << " ";
2756 std::string name = player->getName();
2757 actionstream << name << " "
2758 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2759 << " List of players: " << os.str() << std::endl;
2761 m_admin_chat->outgoing_queue.push_back(
2762 new ChatEventNick(CET_NICK_REMOVE, name));
2766 MutexAutoLock env_lock(m_env_mutex);
2767 m_clients.DeleteClient(peer_id);
2771 // Send leave chat message to all remaining clients
2772 if(message.length() != 0)
2773 SendChatMessage(PEER_ID_INEXISTENT,message);
2776 void Server::UpdateCrafting(RemotePlayer *player)
2778 DSTACK(FUNCTION_NAME);
2780 // Get a preview for crafting
2782 InventoryLocation loc;
2783 loc.setPlayer(player->getName());
2784 std::vector<ItemStack> output_replacements;
2785 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2786 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2787 (&player->inventory)->getList("craft"), loc);
2789 // Put the new preview in
2790 InventoryList *plist = player->inventory.getList("craftpreview");
2791 sanity_check(plist);
2792 sanity_check(plist->getSize() >= 1);
2793 plist->changeItem(0, preview);
2796 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2798 if (evt->type == CET_NICK_ADD) {
2799 // The terminal informed us of its nick choice
2800 m_admin_nick = ((ChatEventNick *)evt)->nick;
2801 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2802 errorstream << "You haven't set up an account." << std::endl
2803 << "Please log in using the client as '"
2804 << m_admin_nick << "' with a secure password." << std::endl
2805 << "Until then, you can't execute admin tasks via the console," << std::endl
2806 << "and everybody can claim the user account instead of you," << std::endl
2807 << "giving them full control over this server." << std::endl;
2810 assert(evt->type == CET_CHAT);
2811 handleAdminChat((ChatEventChat *)evt);
2815 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2816 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2818 // If something goes wrong, this player is to blame
2819 RollbackScopeActor rollback_scope(m_rollback,
2820 std::string("player:") + name);
2823 switch (player->canSendChatMessage()) {
2824 case RPLAYER_CHATRESULT_FLOODING: {
2825 std::wstringstream ws;
2826 ws << L"You cannot send more messages. You are limited to "
2827 << g_settings->getFloat("chat_message_limit_per_10sec")
2828 << L" messages per 10 seconds.";
2831 case RPLAYER_CHATRESULT_KICK:
2832 DenyAccess_Legacy(player->peer_id,
2833 L"You have been kicked due to message flooding.");
2835 case RPLAYER_CHATRESULT_OK:
2838 FATAL_ERROR("Unhandled chat filtering result found.");
2842 if (m_max_chatmessage_length > 0
2843 && wmessage.length() > m_max_chatmessage_length) {
2844 return L"Your message exceed the maximum chat message limit set on the server. "
2845 L"It was refused. Send a shorter message";
2848 // Run script hook, exit if script ate the chat message
2849 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2854 // Whether to send line to the player that sent the message, or to all players
2855 bool broadcast_line = true;
2857 if (check_shout_priv && !checkPriv(name, "shout")) {
2858 line += L"-!- You don't have permission to shout.";
2859 broadcast_line = false;
2868 Tell calling method to send the message to sender
2870 if (!broadcast_line) {
2874 Send the message to others
2876 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2878 std::vector<u16> clients = m_clients.getClientIDs();
2881 Send the message back to the inital sender
2882 if they are using protocol version >= 29
2885 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2886 if (player && player->protocol_version >= 29)
2887 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2889 for (u16 i = 0; i < clients.size(); i++) {
2890 u16 cid = clients[i];
2891 if (cid != peer_id_to_avoid_sending)
2892 SendChatMessage(cid, line);
2898 void Server::handleAdminChat(const ChatEventChat *evt)
2900 std::string name = evt->nick;
2901 std::wstring wname = utf8_to_wide(name);
2902 std::wstring wmessage = evt->evt_msg;
2904 std::wstring answer = handleChat(name, wname, wmessage);
2906 // If asked to send answer to sender
2907 if (!answer.empty()) {
2908 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2912 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2914 RemoteClient *client = getClientNoEx(peer_id,state_min);
2916 throw ClientNotFoundException("Client not found");
2920 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2922 return m_clients.getClientNoEx(peer_id, state_min);
2925 std::string Server::getPlayerName(u16 peer_id)
2927 RemotePlayer *player = m_env->getPlayer(peer_id);
2929 return "[id="+itos(peer_id)+"]";
2930 return player->getName();
2933 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2935 RemotePlayer *player = m_env->getPlayer(peer_id);
2938 return player->getPlayerSAO();
2941 std::wstring Server::getStatusString()
2943 std::wostringstream os(std::ios_base::binary);
2946 os<<L"version="<<narrow_to_wide(g_version_string);
2948 os<<L", uptime="<<m_uptime.get();
2950 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2951 // Information about clients
2954 std::vector<u16> clients = m_clients.getClientIDs();
2955 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2957 RemotePlayer *player = m_env->getPlayer(*i);
2958 // Get name of player
2959 std::wstring name = L"unknown";
2961 name = narrow_to_wide(player->getName());
2962 // Add name to information string
2970 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2971 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2972 if(g_settings->get("motd") != "")
2973 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2977 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2979 std::set<std::string> privs;
2980 m_script->getAuth(name, NULL, &privs);
2984 bool Server::checkPriv(const std::string &name, const std::string &priv)
2986 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2987 return (privs.count(priv) != 0);
2990 void Server::reportPrivsModified(const std::string &name)
2993 std::vector<u16> clients = m_clients.getClientIDs();
2994 for(std::vector<u16>::iterator i = clients.begin();
2995 i != clients.end(); ++i) {
2996 RemotePlayer *player = m_env->getPlayer(*i);
2997 reportPrivsModified(player->getName());
3000 RemotePlayer *player = m_env->getPlayer(name.c_str());
3003 SendPlayerPrivileges(player->peer_id);
3004 PlayerSAO *sao = player->getPlayerSAO();
3007 sao->updatePrivileges(
3008 getPlayerEffectivePrivs(name),
3013 void Server::reportInventoryFormspecModified(const std::string &name)
3015 RemotePlayer *player = m_env->getPlayer(name.c_str());
3018 SendPlayerInventoryFormspec(player->peer_id);
3021 void Server::setIpBanned(const std::string &ip, const std::string &name)
3023 m_banmanager->add(ip, name);
3026 void Server::unsetIpBanned(const std::string &ip_or_name)
3028 m_banmanager->remove(ip_or_name);
3031 std::string Server::getBanDescription(const std::string &ip_or_name)
3033 return m_banmanager->getBanDescription(ip_or_name);
3036 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3038 // m_env will be NULL if the server is initializing
3042 if (m_admin_nick == name && !m_admin_nick.empty()) {
3043 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3046 RemotePlayer *player = m_env->getPlayer(name);
3051 if (player->peer_id == PEER_ID_INEXISTENT)
3054 SendChatMessage(player->peer_id, msg);
3057 bool Server::showFormspec(const char *playername, const std::string &formspec,
3058 const std::string &formname)
3060 // m_env will be NULL if the server is initializing
3064 RemotePlayer *player = m_env->getPlayer(playername);
3068 SendShowFormspecMessage(player->peer_id, formspec, formname);
3072 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3077 u32 id = player->addHud(form);
3079 SendHUDAdd(player->peer_id, id, form);
3084 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3088 HudElement* todel = player->removeHud(id);
3095 SendHUDRemove(player->peer_id, id);
3099 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3104 SendHUDChange(player->peer_id, id, stat, data);
3108 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3113 SendHUDSetFlags(player->peer_id, flags, mask);
3114 player->hud_flags &= ~mask;
3115 player->hud_flags |= flags;
3117 PlayerSAO* playersao = player->getPlayerSAO();
3119 if (playersao == NULL)
3122 m_script->player_event(playersao, "hud_changed");
3126 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3131 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3134 player->setHotbarItemcount(hotbar_itemcount);
3135 std::ostringstream os(std::ios::binary);
3136 writeS32(os, hotbar_itemcount);
3137 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3141 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3146 player->setHotbarImage(name);
3147 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3150 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3154 return player->getHotbarImage();
3157 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3162 player->setHotbarSelectedImage(name);
3163 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3166 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3167 v2s32 animation_frames[4], f32 frame_speed)
3172 player->setLocalAnimations(animation_frames, frame_speed);
3173 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3177 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3182 player->eye_offset_first = first;
3183 player->eye_offset_third = third;
3184 SendEyeOffset(player->peer_id, first, third);
3188 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3189 const std::string &type, const std::vector<std::string> ¶ms)
3194 player->setSky(bgcolor, type, params);
3195 SendSetSky(player->peer_id, bgcolor, type, params);
3199 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3205 player->overrideDayNightRatio(do_override, ratio);
3206 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3210 void Server::notifyPlayers(const std::wstring &msg)
3212 SendChatMessage(PEER_ID_INEXISTENT,msg);
3215 void Server::spawnParticle(const std::string &playername, v3f pos,
3216 v3f velocity, v3f acceleration,
3217 float expirationtime, float size, bool
3218 collisiondetection, bool collision_removal,
3219 bool vertical, const std::string &texture,
3220 const struct TileAnimationParams &animation, u8 glow)
3222 // m_env will be NULL if the server is initializing
3226 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3227 if (playername != "") {
3228 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3231 peer_id = player->peer_id;
3232 proto_ver = player->protocol_version;
3235 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3236 expirationtime, size, collisiondetection,
3237 collision_removal, vertical, texture, animation, glow);
3240 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3241 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3242 float minexptime, float maxexptime, float minsize, float maxsize,
3243 bool collisiondetection, bool collision_removal,
3244 ServerActiveObject *attached, bool vertical, const std::string &texture,
3245 const std::string &playername, const struct TileAnimationParams &animation,
3248 // m_env will be NULL if the server is initializing
3252 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3253 if (playername != "") {
3254 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3257 peer_id = player->peer_id;
3258 proto_ver = player->protocol_version;
3261 u16 attached_id = attached ? attached->getId() : 0;
3264 if (attached_id == 0)
3265 id = m_env->addParticleSpawner(spawntime);
3267 id = m_env->addParticleSpawner(spawntime, attached_id);
3269 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3270 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3271 minexptime, maxexptime, minsize, maxsize,
3272 collisiondetection, collision_removal, attached_id, vertical,
3273 texture, id, animation, glow);
3278 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3280 // m_env will be NULL if the server is initializing
3282 throw ServerError("Can't delete particle spawners during initialisation!");
3284 u16 peer_id = PEER_ID_INEXISTENT;
3285 if (playername != "") {
3286 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3289 peer_id = player->peer_id;
3292 m_env->deleteParticleSpawner(id);
3293 SendDeleteParticleSpawner(peer_id, id);
3296 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3298 if(m_detached_inventories.count(name) > 0){
3299 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3300 delete m_detached_inventories[name];
3302 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3304 Inventory *inv = new Inventory(m_itemdef);
3306 m_detached_inventories[name] = inv;
3307 m_detached_inventories_player[name] = player;
3308 //TODO find a better way to do this
3309 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3313 // actions: time-reversed list
3314 // Return value: success/failure
3315 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3316 std::list<std::string> *log)
3318 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3319 ServerMap *map = (ServerMap*)(&m_env->getMap());
3321 // Fail if no actions to handle
3322 if(actions.empty()){
3323 log->push_back("Nothing to do.");
3330 for(std::list<RollbackAction>::const_iterator
3331 i = actions.begin();
3332 i != actions.end(); ++i)
3334 const RollbackAction &action = *i;
3336 bool success = action.applyRevert(map, this, this);
3339 std::ostringstream os;
3340 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3341 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3343 log->push_back(os.str());
3345 std::ostringstream os;
3346 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3347 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3349 log->push_back(os.str());
3353 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3354 <<" failed"<<std::endl;
3356 // Call it done if less than half failed
3357 return num_failed <= num_tried/2;
3360 // IGameDef interface
3362 IItemDefManager *Server::getItemDefManager()
3367 INodeDefManager *Server::getNodeDefManager()
3372 ICraftDefManager *Server::getCraftDefManager()
3377 u16 Server::allocateUnknownNodeId(const std::string &name)
3379 return m_nodedef->allocateDummy(name);
3382 MtEventManager *Server::getEventManager()
3387 IWritableItemDefManager *Server::getWritableItemDefManager()
3392 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3397 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3402 const ModSpec *Server::getModSpec(const std::string &modname) const
3404 std::vector<ModSpec>::const_iterator it;
3405 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3406 const ModSpec &mod = *it;
3407 if (mod.name == modname)
3413 void Server::getModNames(std::vector<std::string> &modlist)
3415 std::vector<ModSpec>::iterator it;
3416 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3417 modlist.push_back(it->name);
3420 std::string Server::getBuiltinLuaPath()
3422 return porting::path_share + DIR_DELIM + "builtin";
3425 std::string Server::getModStoragePath() const
3427 return m_path_world + DIR_DELIM + "mod_storage";
3430 v3f Server::findSpawnPos()
3432 ServerMap &map = m_env->getServerMap();
3434 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3435 return nodeposf * BS;
3438 bool is_good = false;
3440 // Try to find a good place a few times
3441 for(s32 i = 0; i < 4000 && !is_good; i++) {
3443 // We're going to try to throw the player to this position
3444 v2s16 nodepos2d = v2s16(
3445 -range + (myrand() % (range * 2)),
3446 -range + (myrand() % (range * 2)));
3448 // Get spawn level at point
3449 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3450 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3451 // the mapgen to signify an unsuitable spawn position
3452 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3455 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3458 for (s32 i = 0; i < 10; i++) {
3459 v3s16 blockpos = getNodeBlockPos(nodepos);
3460 map.emergeBlock(blockpos, true);
3461 content_t c = map.getNodeNoEx(nodepos).getContent();
3462 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3464 if (air_count >= 2) {
3465 nodeposf = intToFloat(nodepos, BS);
3466 // Don't spawn the player outside map boundaries
3467 if (objectpos_over_limit(nodeposf))
3480 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3482 m_shutdown_timer = delay;
3483 m_shutdown_msg = msg;
3484 m_shutdown_ask_reconnect = reconnect;
3486 if (delay == 0.0f) {
3487 // No delay, shutdown immediately
3488 m_shutdown_requested = true;
3489 // only print to the infostream, a chat message saying
3490 // "Server Shutting Down" is sent when the server destructs.
3491 infostream << "*** Immediate Server shutdown requested." << std::endl;
3492 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3493 // Negative delay, cancel shutdown if requested
3494 m_shutdown_timer = 0.0f;
3495 m_shutdown_msg = "";
3496 m_shutdown_ask_reconnect = false;
3497 m_shutdown_requested = false;
3498 std::wstringstream ws;
3500 ws << L"*** Server shutdown canceled.";
3502 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3503 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3504 } else if (delay > 0.0f) {
3505 // Positive delay, tell the clients when the server will shut down
3506 std::wstringstream ws;
3508 ws << L"*** Server shutting down in "
3509 << duration_to_string(myround(m_shutdown_timer)).c_str()
3512 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3513 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3517 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3519 bool newplayer = false;
3522 Try to get an existing player
3524 RemotePlayer *player = m_env->getPlayer(name);
3526 // If player is already connected, cancel
3527 if (player != NULL && player->peer_id != 0) {
3528 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3533 If player with the wanted peer_id already exists, cancel.
3535 if (m_env->getPlayer(peer_id) != NULL) {
3536 infostream<<"emergePlayer(): Player with wrong name but same"
3537 " peer_id already exists"<<std::endl;
3541 // Create a new player active object
3542 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3543 player = m_env->loadPlayer(name, playersao);
3545 // Create player if it doesn't exist
3548 player = new RemotePlayer(name, this->idef());
3549 // Set player position
3550 infostream<<"Server: Finding spawn place for player \""
3551 <<name<<"\""<<std::endl;
3552 playersao->setBasePosition(findSpawnPos());
3554 // Make sure the player is saved
3555 player->setModified(true);
3557 // Add player to environment
3558 m_env->addPlayer(player);
3560 // If the player exists, ensure that they respawn inside legal bounds
3561 // This fixes an assert crash when the player can't be added
3562 // to the environment
3563 if (objectpos_over_limit(playersao->getBasePosition())) {
3564 actionstream << "Respawn position for player \""
3565 << name << "\" outside limits, resetting" << std::endl;
3566 playersao->setBasePosition(findSpawnPos());
3570 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3572 player->protocol_version = proto_version;
3574 /* Clean up old HUD elements from previous sessions */
3577 /* Add object to environment */
3578 m_env->addActiveObject(playersao);
3582 m_script->on_newplayer(playersao);
3588 bool Server::registerModStorage(ModMetadata *storage)
3590 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3591 errorstream << "Unable to register same mod storage twice. Storage name: "
3592 << storage->getModName() << std::endl;
3596 m_mod_storages[storage->getModName()] = storage;
3600 void Server::unregisterModStorage(const std::string &name)
3602 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3603 if (it != m_mod_storages.end()) {
3604 // Save unconditionaly on unregistration
3605 it->second->save(getModStoragePath());
3606 m_mod_storages.erase(name);
3610 void dedicated_server_loop(Server &server, bool &kill)
3612 DSTACK(FUNCTION_NAME);
3614 verbosestream<<"dedicated_server_loop()"<<std::endl;
3616 IntervalLimiter m_profiler_interval;
3618 static const float steplen = g_settings->getFloat("dedicated_server_step");
3619 static const float profiler_print_interval =
3620 g_settings->getFloat("profiler_print_interval");
3623 // This is kind of a hack but can be done like this
3624 // because server.step() is very light
3626 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3627 sleep_ms((int)(steplen*1000.0));
3629 server.step(steplen);
3631 if (server.getShutdownRequested() || kill)
3637 if (profiler_print_interval != 0) {
3638 if(m_profiler_interval.step(steplen, profiler_print_interval))
3640 infostream<<"Profiler:"<<std::endl;
3641 g_profiler->print(infostream);
3642 g_profiler->clear();
3647 infostream << "Dedicated server quitting" << std::endl;
3649 if (g_settings->getBool("server_announce"))
3650 ServerList::sendAnnounce(ServerList::AA_DELETE,
3651 server.m_bind_addr.getPort());