3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_server.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"
65 class ClientNotFoundException : public BaseException
68 ClientNotFoundException(const char *s):
73 class ServerThread : public Thread
77 ServerThread(Server *server):
88 void *ServerThread::run()
90 DSTACK(FUNCTION_NAME);
91 BEGIN_DEBUG_EXCEPTION_HANDLER
93 m_server->AsyncRunStep(true);
95 while (!stopRequested()) {
97 //TimeTaker timer("AsyncRunStep() + Receive()");
99 m_server->AsyncRunStep();
103 } catch (con::NoIncomingDataException &e) {
104 } catch (con::PeerNotFoundException &e) {
105 infostream<<"Server: PeerNotFoundException"<<std::endl;
106 } catch (ClientNotFoundException &e) {
107 } catch (con::ConnectionBindFailed &e) {
108 m_server->setAsyncFatalError(e.what());
109 } catch (LuaError &e) {
110 m_server->setAsyncFatalError(
111 "ServerThread::run Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
155 m_path_world(path_world),
156 m_gamespec(gamespec),
157 m_simple_singleplayer_mode(simple_singleplayer_mode),
158 m_dedicated(dedicated),
159 m_async_fatal_error(""),
168 m_enable_rollback_recording(false),
171 m_itemdef(createItemDefManager()),
172 m_nodedef(createNodeDefManager()),
173 m_craftdef(createCraftDefManager()),
174 m_event(new EventManager()),
176 m_time_of_day_send_timer(0),
179 m_shutdown_requested(false),
180 m_shutdown_ask_reconnect(false),
181 m_shutdown_timer(0.0f),
183 m_ignore_map_edit_events(false),
184 m_ignore_map_edit_events_peer_id(0),
186 m_mod_storage_save_timer(10.0f)
188 m_liquid_transform_timer = 0.0;
189 m_liquid_transform_every = 1.0;
190 m_masterserver_timer = 0.0;
191 m_emergethread_trigger_timer = 0.0;
192 m_savemap_timer = 0.0;
195 m_lag = g_settings->getFloat("dedicated_server_step");
198 throw ServerError("Supplied empty world path");
200 if(!gamespec.isValid())
201 throw ServerError("Supplied invalid gamespec");
203 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
204 if(m_simple_singleplayer_mode)
205 infostream<<" in simple singleplayer mode"<<std::endl;
207 infostream<<std::endl;
208 infostream<<"- world: "<<m_path_world<<std::endl;
209 infostream<<"- game: "<<m_gamespec.path<<std::endl;
211 // Create world if it doesn't exist
212 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
213 throw ServerError("Failed to initialize world");
215 // Create server thread
216 m_thread = new ServerThread(this);
218 // Create emerge manager
219 m_emerge = new EmergeManager(this);
221 // Create ban manager
222 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
223 m_banmanager = new BanManager(ban_path);
225 ServerModConfiguration modconf(m_path_world);
226 m_mods = modconf.getMods();
227 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
228 // complain about mods with unsatisfied dependencies
229 if (!modconf.isConsistent()) {
230 modconf.printUnsatisfiedModsError();
233 Settings worldmt_settings;
234 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
235 worldmt_settings.readConfigFile(worldmt.c_str());
236 std::vector<std::string> names = worldmt_settings.getNames();
237 std::set<std::string> load_mod_names;
238 for(std::vector<std::string>::iterator it = names.begin();
239 it != names.end(); ++it) {
240 std::string name = *it;
241 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
242 load_mod_names.insert(name.substr(9));
244 // complain about mods declared to be loaded, but not found
245 for(std::vector<ModSpec>::iterator it = m_mods.begin();
246 it != m_mods.end(); ++it)
247 load_mod_names.erase((*it).name);
248 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
249 it != unsatisfied_mods.end(); ++it)
250 load_mod_names.erase((*it).name);
251 if(!load_mod_names.empty()) {
252 errorstream << "The following mods could not be found:";
253 for(std::set<std::string>::iterator it = load_mod_names.begin();
254 it != load_mod_names.end(); ++it)
255 errorstream << " \"" << (*it) << "\"";
256 errorstream << std::endl;
260 MutexAutoLock envlock(m_env_mutex);
262 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
263 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
265 // Initialize scripting
266 infostream<<"Server: Initializing Lua"<<std::endl;
268 m_script = new ServerScripting(this);
270 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
273 infostream << "Server: Loading mods: ";
274 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
275 i != m_mods.end(); ++i) {
276 infostream << (*i).name << " ";
278 infostream << std::endl;
279 // Load and run "mod" scripts
280 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
281 it != m_mods.end(); ++it) {
282 const ModSpec &mod = *it;
283 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
284 throw ModError("Error loading mod \"" + mod.name +
285 "\": Mod name does not follow naming conventions: "
286 "Only chararacters [a-z0-9_] are allowed.");
288 std::string script_path = mod.path + DIR_DELIM + "init.lua";
289 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
290 << script_path << "\"]" << std::endl;
291 m_script->loadMod(script_path, mod.name);
294 // Read Textures and calculate sha1 sums
297 // Apply item aliases in the node definition manager
298 m_nodedef->updateAliases(m_itemdef);
300 // Apply texture overrides from texturepack/override.txt
301 std::string texture_path = g_settings->get("texture_path");
302 if (texture_path != "" && fs::IsDir(texture_path))
303 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
305 m_nodedef->setNodeRegistrationStatus(true);
307 // Perform pending node name resolutions
308 m_nodedef->runNodeResolveCallbacks();
310 // unmap node names for connected nodeboxes
311 m_nodedef->mapNodeboxConnections();
313 // init the recipe hashes to speed up crafting
314 m_craftdef->initHashes(this);
316 // Initialize Environment
317 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
319 m_clients.setEnv(m_env);
321 if (!servermap->settings_mgr.makeMapgenParams())
322 FATAL_ERROR("Couldn't create any mapgen type");
324 // Initialize mapgens
325 m_emerge->initMapgens(servermap->getMapgenParams());
327 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
328 if (m_enable_rollback_recording) {
329 // Create rollback manager
330 m_rollback = new RollbackManager(m_path_world, this);
333 // Give environment reference to scripting api
334 m_script->initializeEnvironment(m_env);
336 // Register us to receive map edit events
337 servermap->addEventReceiver(this);
339 // If file exists, load environment metadata
340 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
341 infostream << "Server: Loading environment metadata" << std::endl;
344 m_env->loadDefaultMeta();
347 // Add some test ActiveBlockModifiers to environment
348 add_legacy_abms(m_env, m_nodedef);
350 m_liquid_transform_every = g_settings->getFloat("liquid_update");
351 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
356 infostream<<"Server destructing"<<std::endl;
358 // Send shutdown message
359 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
362 MutexAutoLock envlock(m_env_mutex);
364 // Execute script shutdown hooks
365 m_script->on_shutdown();
367 infostream << "Server: Saving players" << std::endl;
368 m_env->saveLoadedPlayers();
370 infostream << "Server: Kicking players" << std::endl;
371 std::string kick_msg;
372 bool reconnect = false;
373 if (getShutdownRequested()) {
374 reconnect = m_shutdown_ask_reconnect;
375 kick_msg = m_shutdown_msg;
377 if (kick_msg == "") {
378 kick_msg = g_settings->get("kick_msg_shutdown");
380 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
381 kick_msg, reconnect);
383 infostream << "Server: Saving environment metadata" << std::endl;
391 // stop all emerge threads before deleting players that may have
392 // requested blocks to be emerged
393 m_emerge->stopThreads();
395 // Delete things in the reverse order of creation
405 // Deinitialize scripting
406 infostream<<"Server: Deinitializing scripting"<<std::endl;
409 // Delete detached inventories
410 for (std::map<std::string, Inventory*>::iterator
411 i = m_detached_inventories.begin();
412 i != m_detached_inventories.end(); ++i) {
417 void Server::start(Address bind_addr)
419 DSTACK(FUNCTION_NAME);
421 m_bind_addr = bind_addr;
423 infostream<<"Starting server on "
424 << bind_addr.serializeString() <<"..."<<std::endl;
426 // Stop thread if already running
429 // Initialize connection
430 m_con.SetTimeoutMs(30);
431 m_con.Serve(bind_addr);
436 // ASCII art for the win!
438 <<" .__ __ __ "<<std::endl
439 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
440 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
441 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
442 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
443 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
444 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
445 actionstream<<"Server for gameid=\""<<m_gamespec.id
446 <<"\" listening on "<<bind_addr.serializeString()<<":"
447 <<bind_addr.getPort() << "."<<std::endl;
452 DSTACK(FUNCTION_NAME);
454 infostream<<"Server: Stopping and waiting threads"<<std::endl;
456 // Stop threads (set run=false first so both start stopping)
458 //m_emergethread.setRun(false);
460 //m_emergethread.stop();
462 infostream<<"Server: Threads stopped"<<std::endl;
465 void Server::step(float dtime)
467 DSTACK(FUNCTION_NAME);
472 MutexAutoLock lock(m_step_dtime_mutex);
473 m_step_dtime += dtime;
475 // Throw if fatal error occurred in thread
476 std::string async_err = m_async_fatal_error.get();
477 if (!async_err.empty()) {
478 if (!m_simple_singleplayer_mode) {
479 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
480 g_settings->get("kick_msg_crash"),
481 g_settings->getBool("ask_reconnect_on_crash"));
483 throw ServerError("AsyncErr: " + async_err);
487 void Server::AsyncRunStep(bool initial_step)
489 DSTACK(FUNCTION_NAME);
491 g_profiler->add("Server::AsyncRunStep (num)", 1);
495 MutexAutoLock lock1(m_step_dtime_mutex);
496 dtime = m_step_dtime;
500 // Send blocks to clients
504 if((dtime < 0.001) && (initial_step == false))
507 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
509 //infostream<<"Server steps "<<dtime<<std::endl;
510 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
513 MutexAutoLock lock1(m_step_dtime_mutex);
514 m_step_dtime -= dtime;
521 m_uptime.set(m_uptime.get() + dtime);
527 Update time of day and overall game time
529 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
532 Send to clients at constant intervals
535 m_time_of_day_send_timer -= dtime;
536 if(m_time_of_day_send_timer < 0.0) {
537 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
538 u16 time = m_env->getTimeOfDay();
539 float time_speed = g_settings->getFloat("time_speed");
540 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
544 MutexAutoLock lock(m_env_mutex);
545 // Figure out and report maximum lag to environment
546 float max_lag = m_env->getMaxLagEstimate();
547 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
549 if(dtime > 0.1 && dtime > max_lag * 2.0)
550 infostream<<"Server: Maximum lag peaked to "<<dtime
554 m_env->reportMaxLagEstimate(max_lag);
556 ScopeProfiler sp(g_profiler, "SEnv step");
557 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
561 static const float map_timer_and_unload_dtime = 2.92;
562 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
564 MutexAutoLock lock(m_env_mutex);
565 // Run Map's timers and unload unused data
566 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
567 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
568 g_settings->getFloat("server_unload_unused_data_timeout"),
573 Listen to the admin chat, if available
576 if (!m_admin_chat->command_queue.empty()) {
577 MutexAutoLock lock(m_env_mutex);
578 while (!m_admin_chat->command_queue.empty()) {
579 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
580 handleChatInterfaceEvent(evt);
584 m_admin_chat->outgoing_queue.push_back(
585 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
592 /* Transform liquids */
593 m_liquid_transform_timer += dtime;
594 if(m_liquid_transform_timer >= m_liquid_transform_every)
596 m_liquid_transform_timer -= m_liquid_transform_every;
598 MutexAutoLock lock(m_env_mutex);
600 ScopeProfiler sp(g_profiler, "Server: liquid transform");
602 std::map<v3s16, MapBlock*> modified_blocks;
603 m_env->getMap().transformLiquids(modified_blocks, m_env);
608 core::map<v3s16, MapBlock*> lighting_modified_blocks;
609 ServerMap &map = ((ServerMap&)m_env->getMap());
610 map.updateLighting(modified_blocks, lighting_modified_blocks);
612 // Add blocks modified by lighting to modified_blocks
613 for(core::map<v3s16, MapBlock*>::Iterator
614 i = lighting_modified_blocks.getIterator();
615 i.atEnd() == false; i++)
617 MapBlock *block = i.getNode()->getValue();
618 modified_blocks.insert(block->getPos(), block);
622 Set the modified blocks unsent for all the clients
624 if(!modified_blocks.empty())
626 SetBlocksNotSent(modified_blocks);
629 m_clients.step(dtime);
631 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
633 // send masterserver announce
635 float &counter = m_masterserver_timer;
636 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
637 g_settings->getBool("server_announce")) {
638 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
639 ServerList::AA_START,
640 m_bind_addr.getPort(),
641 m_clients.getPlayerNames(),
643 m_env->getGameTime(),
646 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
656 Check added and deleted active objects
659 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
660 MutexAutoLock envlock(m_env_mutex);
663 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
664 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
666 // Radius inside which objects are active
667 static const s16 radius =
668 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
670 // Radius inside which players are active
671 static const bool is_transfer_limited =
672 g_settings->exists("unlimited_player_transfer_distance") &&
673 !g_settings->getBool("unlimited_player_transfer_distance");
674 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
675 s16 player_radius = player_transfer_dist;
676 if (player_radius == 0 && is_transfer_limited)
677 player_radius = radius;
679 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
680 i != clients.end(); ++i) {
681 RemoteClient *client = i->second;
683 // If definitions and textures have not been sent, don't
684 // send objects either
685 if (client->getState() < CS_DefinitionsSent)
688 RemotePlayer *player = m_env->getPlayer(client->peer_id);
689 if (player == NULL) {
690 // This can happen if the client timeouts somehow
691 /*warningstream<<FUNCTION_NAME<<": Client "
693 <<" has no associated player"<<std::endl;*/
697 PlayerSAO *playersao = player->getPlayerSAO();
698 if (playersao == NULL)
701 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
702 if (my_radius <= 0) my_radius = radius;
703 //infostream << "Server: Active Radius " << my_radius << std::endl;
705 std::queue<u16> removed_objects;
706 std::queue<u16> added_objects;
707 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
708 client->m_known_objects, removed_objects);
709 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
710 client->m_known_objects, added_objects);
712 // Ignore if nothing happened
713 if (removed_objects.empty() && added_objects.empty()) {
717 std::string data_buffer;
721 // Handle removed objects
722 writeU16((u8*)buf, removed_objects.size());
723 data_buffer.append(buf, 2);
724 while (!removed_objects.empty()) {
726 u16 id = removed_objects.front();
727 ServerActiveObject* obj = m_env->getActiveObject(id);
729 // Add to data buffer for sending
730 writeU16((u8*)buf, id);
731 data_buffer.append(buf, 2);
733 // Remove from known objects
734 client->m_known_objects.erase(id);
736 if(obj && obj->m_known_by_count > 0)
737 obj->m_known_by_count--;
738 removed_objects.pop();
741 // Handle added objects
742 writeU16((u8*)buf, added_objects.size());
743 data_buffer.append(buf, 2);
744 while (!added_objects.empty()) {
746 u16 id = added_objects.front();
747 ServerActiveObject* obj = m_env->getActiveObject(id);
750 u8 type = ACTIVEOBJECT_TYPE_INVALID;
752 warningstream<<FUNCTION_NAME
753 <<": NULL object"<<std::endl;
755 type = obj->getSendType();
757 // Add to data buffer for sending
758 writeU16((u8*)buf, id);
759 data_buffer.append(buf, 2);
760 writeU8((u8*)buf, type);
761 data_buffer.append(buf, 1);
764 data_buffer.append(serializeLongString(
765 obj->getClientInitializationData(client->net_proto_version)));
767 data_buffer.append(serializeLongString(""));
769 // Add to known objects
770 client->m_known_objects.insert(id);
773 obj->m_known_by_count++;
778 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
779 verbosestream << "Server: Sent object remove/add: "
780 << removed_objects.size() << " removed, "
781 << added_objects.size() << " added, "
782 << "packet size is " << pktSize << std::endl;
786 m_mod_storage_save_timer -= dtime;
787 if (m_mod_storage_save_timer <= 0.0f) {
788 infostream << "Saving registered mod storages." << std::endl;
789 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
790 for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
791 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
792 if (it->second->isModified()) {
793 it->second->save(getModStoragePath());
803 MutexAutoLock envlock(m_env_mutex);
804 ScopeProfiler sp(g_profiler, "Server: sending object messages");
807 // Value = data sent by object
808 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
810 // Get active object messages from environment
812 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
816 std::vector<ActiveObjectMessage>* message_list = NULL;
817 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
818 n = buffered_messages.find(aom.id);
819 if (n == buffered_messages.end()) {
820 message_list = new std::vector<ActiveObjectMessage>;
821 buffered_messages[aom.id] = message_list;
824 message_list = n->second;
826 message_list->push_back(aom);
830 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
831 // Route data to every client
832 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
833 i != clients.end(); ++i) {
834 RemoteClient *client = i->second;
835 std::string reliable_data;
836 std::string unreliable_data;
837 // Go through all objects in message buffer
838 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
839 j = buffered_messages.begin();
840 j != buffered_messages.end(); ++j) {
841 // If object is not known by client, skip it
843 if (client->m_known_objects.find(id) == client->m_known_objects.end())
846 // Get message list of object
847 std::vector<ActiveObjectMessage>* list = j->second;
848 // Go through every message
849 for (std::vector<ActiveObjectMessage>::iterator
850 k = list->begin(); k != list->end(); ++k) {
851 // Compose the full new data with header
852 ActiveObjectMessage aom = *k;
853 std::string new_data;
856 writeU16((u8*)&buf[0], aom.id);
857 new_data.append(buf, 2);
859 new_data += serializeString(aom.datastring);
860 // Add data to buffer
862 reliable_data += new_data;
864 unreliable_data += new_data;
868 reliable_data and unreliable_data are now ready.
871 if(reliable_data.size() > 0) {
872 SendActiveObjectMessages(client->peer_id, reliable_data);
875 if(unreliable_data.size() > 0) {
876 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
881 // Clear buffered_messages
882 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
883 i = buffered_messages.begin();
884 i != buffered_messages.end(); ++i) {
890 Send queued-for-sending map edit events.
893 // We will be accessing the environment
894 MutexAutoLock lock(m_env_mutex);
896 // Don't send too many at a time
899 // Single change sending is disabled if queue size is not small
900 bool disable_single_change_sending = false;
901 if(m_unsent_map_edit_queue.size() >= 4)
902 disable_single_change_sending = true;
904 int event_count = m_unsent_map_edit_queue.size();
906 // We'll log the amount of each
909 while(m_unsent_map_edit_queue.size() != 0)
911 MapEditEvent* event = m_unsent_map_edit_queue.front();
912 m_unsent_map_edit_queue.pop();
914 // Players far away from the change are stored here.
915 // Instead of sending the changes, MapBlocks are set not sent
917 std::vector<u16> far_players;
919 switch (event->type) {
922 prof.add("MEET_ADDNODE", 1);
923 sendAddNode(event->p, event->n, event->already_known_by_peer,
924 &far_players, disable_single_change_sending ? 5 : 30,
925 event->type == MEET_ADDNODE);
927 case MEET_REMOVENODE:
928 prof.add("MEET_REMOVENODE", 1);
929 sendRemoveNode(event->p, event->already_known_by_peer,
930 &far_players, disable_single_change_sending ? 5 : 30);
932 case MEET_BLOCK_NODE_METADATA_CHANGED:
933 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
934 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
935 setBlockNotSent(event->p);
938 infostream << "Server: MEET_OTHER" << std::endl;
939 prof.add("MEET_OTHER", 1);
940 for(std::set<v3s16>::iterator
941 i = event->modified_blocks.begin();
942 i != event->modified_blocks.end(); ++i) {
947 prof.add("unknown", 1);
948 warningstream << "Server: Unknown MapEditEvent "
949 << ((u32)event->type) << std::endl;
954 Set blocks not sent to far players
956 if(!far_players.empty()) {
957 // Convert list format to that wanted by SetBlocksNotSent
958 std::map<v3s16, MapBlock*> modified_blocks2;
959 for(std::set<v3s16>::iterator
960 i = event->modified_blocks.begin();
961 i != event->modified_blocks.end(); ++i) {
962 modified_blocks2[*i] =
963 m_env->getMap().getBlockNoCreateNoEx(*i);
966 // Set blocks not sent
967 for(std::vector<u16>::iterator
968 i = far_players.begin();
969 i != far_players.end(); ++i) {
970 if(RemoteClient *client = getClient(*i))
971 client->SetBlocksNotSent(modified_blocks2);
977 /*// Don't send too many at a time
979 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
983 if(event_count >= 5){
984 infostream<<"Server: MapEditEvents:"<<std::endl;
985 prof.print(infostream);
986 } else if(event_count != 0){
987 verbosestream<<"Server: MapEditEvents:"<<std::endl;
988 prof.print(verbosestream);
994 Trigger emergethread (it somehow gets to a non-triggered but
995 bysy state sometimes)
998 float &counter = m_emergethread_trigger_timer;
1000 if (counter >= 2.0) {
1003 m_emerge->startThreads();
1007 // Save map, players and auth stuff
1009 float &counter = m_savemap_timer;
1011 static const float save_interval =
1012 g_settings->getFloat("server_map_save_interval");
1013 if (counter >= save_interval) {
1015 MutexAutoLock lock(m_env_mutex);
1017 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1020 if (m_banmanager->isModified()) {
1021 m_banmanager->save();
1024 // Save changed parts of map
1025 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1028 m_env->saveLoadedPlayers();
1030 // Save environment metadata
1036 static const float shutdown_msg_times[] =
1038 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
1041 if (m_shutdown_timer > 0.0f) {
1042 // Automated messages
1043 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
1044 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
1045 // If shutdown timer matches an automessage, shot it
1046 if (m_shutdown_timer > shutdown_msg_times[i] &&
1047 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1048 std::wstringstream ws;
1050 ws << L"*** Server shutting down in "
1051 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1054 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1055 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1061 m_shutdown_timer -= dtime;
1062 if (m_shutdown_timer < 0.0f) {
1063 m_shutdown_timer = 0.0f;
1064 m_shutdown_requested = true;
1069 void Server::Receive()
1071 DSTACK(FUNCTION_NAME);
1072 SharedBuffer<u8> data;
1076 m_con.Receive(&pkt);
1077 peer_id = pkt.getPeerId();
1080 catch(con::InvalidIncomingDataException &e) {
1081 infostream<<"Server::Receive(): "
1082 "InvalidIncomingDataException: what()="
1083 <<e.what()<<std::endl;
1085 catch(SerializationError &e) {
1086 infostream<<"Server::Receive(): "
1087 "SerializationError: what()="
1088 <<e.what()<<std::endl;
1090 catch(ClientStateError &e) {
1091 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1092 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1093 L"Try reconnecting or updating your client");
1095 catch(con::PeerNotFoundException &e) {
1100 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1102 std::string playername = "";
1103 PlayerSAO *playersao = NULL;
1106 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1107 if (client != NULL) {
1108 playername = client->getName();
1109 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1111 } catch (std::exception &e) {
1117 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1119 // If failed, cancel
1120 if ((playersao == NULL) || (player == NULL)) {
1121 if (player && player->peer_id != 0) {
1122 actionstream << "Server: Failed to emerge player \"" << playername
1123 << "\" (player allocated to an another client)" << std::endl;
1124 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1125 L"name. If your client closed unexpectedly, try again in "
1128 errorstream << "Server: " << playername << ": Failed to emerge player"
1130 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1136 Send complete position information
1138 SendMovePlayer(peer_id);
1141 SendPlayerPrivileges(peer_id);
1143 // Send inventory formspec
1144 SendPlayerInventoryFormspec(peer_id);
1147 SendInventory(playersao);
1149 // Send HP or death screen
1150 if (playersao->isDead())
1151 SendDeathscreen(peer_id, false, v3f(0,0,0));
1153 SendPlayerHPOrDie(playersao);
1156 SendPlayerBreath(playersao);
1158 // Note things in chat if not in simple singleplayer mode
1159 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1160 // Send information about server to player in chat
1161 SendChatMessage(peer_id, getStatusString());
1163 Address addr = getPeerAddress(player->peer_id);
1164 std::string ip_str = addr.serializeString();
1165 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1170 const std::vector<std::string> &names = m_clients.getPlayerNames();
1172 actionstream << player->getName() << " joins game. List of players: ";
1174 for (std::vector<std::string>::const_iterator i = names.begin();
1175 i != names.end(); ++i) {
1176 actionstream << *i << " ";
1179 actionstream << player->getName() <<std::endl;
1184 inline void Server::handleCommand(NetworkPacket* pkt)
1186 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1187 (this->*opHandle.handler)(pkt);
1190 void Server::ProcessData(NetworkPacket *pkt)
1192 DSTACK(FUNCTION_NAME);
1193 // Environment is locked first.
1194 MutexAutoLock envlock(m_env_mutex);
1196 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1197 u32 peer_id = pkt->getPeerId();
1200 Address address = getPeerAddress(peer_id);
1201 std::string addr_s = address.serializeString();
1203 if(m_banmanager->isIpBanned(addr_s)) {
1204 std::string ban_name = m_banmanager->getBanName(addr_s);
1205 infostream << "Server: A banned client tried to connect from "
1206 << addr_s << "; banned name was "
1207 << ban_name << std::endl;
1208 // This actually doesn't seem to transfer to the client
1209 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1210 + utf8_to_wide(ban_name));
1214 catch(con::PeerNotFoundException &e) {
1216 * no peer for this packet found
1217 * most common reason is peer timeout, e.g. peer didn't
1218 * respond for some time, your server was overloaded or
1221 infostream << "Server::ProcessData(): Canceling: peer "
1222 << peer_id << " not found" << std::endl;
1227 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1229 // Command must be handled into ToServerCommandHandler
1230 if (command >= TOSERVER_NUM_MSG_TYPES) {
1231 infostream << "Server: Ignoring unknown command "
1232 << command << std::endl;
1236 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1241 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1243 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1244 errorstream << "Server::ProcessData(): Cancelling: Peer"
1245 " serialization format invalid or not initialized."
1246 " Skipping incoming command=" << command << std::endl;
1250 /* Handle commands related to client startup */
1251 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1256 if (m_clients.getClientState(peer_id) < CS_Active) {
1257 if (command == TOSERVER_PLAYERPOS) return;
1259 errorstream << "Got packet command: " << command << " for peer id "
1260 << peer_id << " but client isn't active yet. Dropping packet "
1266 } catch (SendFailedException &e) {
1267 errorstream << "Server::ProcessData(): SendFailedException: "
1268 << "what=" << e.what()
1270 } catch (PacketError &e) {
1271 actionstream << "Server::ProcessData(): PacketError: "
1272 << "what=" << e.what()
1277 void Server::setTimeOfDay(u32 time)
1279 m_env->setTimeOfDay(time);
1280 m_time_of_day_send_timer = 0;
1283 void Server::onMapEditEvent(MapEditEvent *event)
1285 if(m_ignore_map_edit_events)
1287 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1289 MapEditEvent *e = event->clone();
1290 m_unsent_map_edit_queue.push(e);
1293 Inventory* Server::getInventory(const InventoryLocation &loc)
1296 case InventoryLocation::UNDEFINED:
1297 case InventoryLocation::CURRENT_PLAYER:
1299 case InventoryLocation::PLAYER:
1301 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1304 PlayerSAO *playersao = player->getPlayerSAO();
1307 return playersao->getInventory();
1310 case InventoryLocation::NODEMETA:
1312 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1315 return meta->getInventory();
1318 case InventoryLocation::DETACHED:
1320 if(m_detached_inventories.count(loc.name) == 0)
1322 return m_detached_inventories[loc.name];
1326 sanity_check(false); // abort
1331 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1334 case InventoryLocation::UNDEFINED:
1336 case InventoryLocation::PLAYER:
1341 RemotePlayer *player =
1342 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1347 PlayerSAO *playersao = player->getPlayerSAO();
1351 SendInventory(playersao);
1354 case InventoryLocation::NODEMETA:
1356 v3s16 blockpos = getNodeBlockPos(loc.p);
1358 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1360 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1362 setBlockNotSent(blockpos);
1365 case InventoryLocation::DETACHED:
1367 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1371 sanity_check(false); // abort
1376 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1378 std::vector<u16> clients = m_clients.getClientIDs();
1380 // Set the modified blocks unsent for all the clients
1381 for (std::vector<u16>::iterator i = clients.begin();
1382 i != clients.end(); ++i) {
1383 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1384 client->SetBlocksNotSent(block);
1389 void Server::peerAdded(con::Peer *peer)
1391 DSTACK(FUNCTION_NAME);
1392 verbosestream<<"Server::peerAdded(): peer->id="
1393 <<peer->id<<std::endl;
1396 c.type = con::PEER_ADDED;
1397 c.peer_id = peer->id;
1399 m_peer_change_queue.push(c);
1402 void Server::deletingPeer(con::Peer *peer, bool timeout)
1404 DSTACK(FUNCTION_NAME);
1405 verbosestream<<"Server::deletingPeer(): peer->id="
1406 <<peer->id<<", timeout="<<timeout<<std::endl;
1408 m_clients.event(peer->id, CSE_Disconnect);
1410 c.type = con::PEER_REMOVED;
1411 c.peer_id = peer->id;
1412 c.timeout = timeout;
1413 m_peer_change_queue.push(c);
1416 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1418 *retval = m_con.getPeerStat(peer_id,type);
1419 if (*retval == -1) return false;
1423 bool Server::getClientInfo(
1432 std::string* vers_string
1435 *state = m_clients.getClientState(peer_id);
1437 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1439 if (client == NULL) {
1444 *uptime = client->uptime();
1445 *ser_vers = client->serialization_version;
1446 *prot_vers = client->net_proto_version;
1448 *major = client->getMajor();
1449 *minor = client->getMinor();
1450 *patch = client->getPatch();
1451 *vers_string = client->getPatch();
1458 void Server::handlePeerChanges()
1460 while(m_peer_change_queue.size() > 0)
1462 con::PeerChange c = m_peer_change_queue.front();
1463 m_peer_change_queue.pop();
1465 verbosestream<<"Server: Handling peer change: "
1466 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1471 case con::PEER_ADDED:
1472 m_clients.CreateClient(c.peer_id);
1475 case con::PEER_REMOVED:
1476 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1480 FATAL_ERROR("Invalid peer change event received!");
1486 void Server::printToConsoleOnly(const std::string &text)
1489 m_admin_chat->outgoing_queue.push_back(
1490 new ChatEventChat("", utf8_to_wide(text)));
1492 std::cout << text << std::endl;
1496 void Server::Send(NetworkPacket* pkt)
1498 m_clients.send(pkt->getPeerId(),
1499 clientCommandFactoryTable[pkt->getCommand()].channel,
1501 clientCommandFactoryTable[pkt->getCommand()].reliable);
1504 void Server::SendMovement(u16 peer_id)
1506 DSTACK(FUNCTION_NAME);
1507 std::ostringstream os(std::ios_base::binary);
1509 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1511 pkt << g_settings->getFloat("movement_acceleration_default");
1512 pkt << g_settings->getFloat("movement_acceleration_air");
1513 pkt << g_settings->getFloat("movement_acceleration_fast");
1514 pkt << g_settings->getFloat("movement_speed_walk");
1515 pkt << g_settings->getFloat("movement_speed_crouch");
1516 pkt << g_settings->getFloat("movement_speed_fast");
1517 pkt << g_settings->getFloat("movement_speed_climb");
1518 pkt << g_settings->getFloat("movement_speed_jump");
1519 pkt << g_settings->getFloat("movement_liquid_fluidity");
1520 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1521 pkt << g_settings->getFloat("movement_liquid_sink");
1522 pkt << g_settings->getFloat("movement_gravity");
1527 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1529 if (!g_settings->getBool("enable_damage"))
1532 u16 peer_id = playersao->getPeerID();
1533 bool is_alive = playersao->getHP() > 0;
1536 SendPlayerHP(peer_id);
1541 void Server::SendHP(u16 peer_id, u8 hp)
1543 DSTACK(FUNCTION_NAME);
1545 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1550 void Server::SendBreath(u16 peer_id, u16 breath)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1555 pkt << (u16) breath;
1559 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1560 const std::string &custom_reason, bool reconnect)
1562 assert(reason < SERVER_ACCESSDENIED_MAX);
1564 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1566 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1567 pkt << custom_reason;
1568 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1569 reason == SERVER_ACCESSDENIED_CRASH)
1570 pkt << custom_reason << (u8)reconnect;
1574 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1576 DSTACK(FUNCTION_NAME);
1578 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1583 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1584 v3f camera_point_target)
1586 DSTACK(FUNCTION_NAME);
1588 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1589 pkt << set_camera_point_target << camera_point_target;
1593 void Server::SendItemDef(u16 peer_id,
1594 IItemDefManager *itemdef, u16 protocol_version)
1596 DSTACK(FUNCTION_NAME);
1598 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1602 u32 length of the next item
1603 zlib-compressed serialized ItemDefManager
1605 std::ostringstream tmp_os(std::ios::binary);
1606 itemdef->serialize(tmp_os, protocol_version);
1607 std::ostringstream tmp_os2(std::ios::binary);
1608 compressZlib(tmp_os.str(), tmp_os2);
1609 pkt.putLongString(tmp_os2.str());
1612 verbosestream << "Server: Sending item definitions to id(" << peer_id
1613 << "): size=" << pkt.getSize() << std::endl;
1618 void Server::SendNodeDef(u16 peer_id,
1619 INodeDefManager *nodedef, u16 protocol_version)
1621 DSTACK(FUNCTION_NAME);
1623 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1627 u32 length of the next item
1628 zlib-compressed serialized NodeDefManager
1630 std::ostringstream tmp_os(std::ios::binary);
1631 nodedef->serialize(tmp_os, protocol_version);
1632 std::ostringstream tmp_os2(std::ios::binary);
1633 compressZlib(tmp_os.str(), tmp_os2);
1635 pkt.putLongString(tmp_os2.str());
1638 verbosestream << "Server: Sending node definitions to id(" << peer_id
1639 << "): size=" << pkt.getSize() << std::endl;
1645 Non-static send methods
1648 void Server::SendInventory(PlayerSAO* playerSAO)
1650 DSTACK(FUNCTION_NAME);
1652 UpdateCrafting(playerSAO->getPlayer());
1658 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1660 std::ostringstream os;
1661 playerSAO->getInventory()->serialize(os);
1663 std::string s = os.str();
1665 pkt.putRawString(s.c_str(), s.size());
1669 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1671 DSTACK(FUNCTION_NAME);
1673 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1676 if (peer_id != PEER_ID_INEXISTENT) {
1680 m_clients.sendToAll(&pkt);
1684 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1685 const std::string &formname)
1687 DSTACK(FUNCTION_NAME);
1689 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1690 if (formspec == "" ){
1691 //the client should close the formspec
1692 pkt.putLongString("");
1694 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1701 // Spawns a particle on peer with peer_id
1702 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1703 v3f pos, v3f velocity, v3f acceleration,
1704 float expirationtime, float size, bool collisiondetection,
1705 bool collision_removal,
1706 bool vertical, const std::string &texture,
1707 const struct TileAnimationParams &animation, u8 glow)
1709 DSTACK(FUNCTION_NAME);
1710 if (peer_id == PEER_ID_INEXISTENT) {
1711 // This sucks and should be replaced by a better solution in a refactor:
1712 std::vector<u16> clients = m_clients.getClientIDs();
1713 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1714 RemotePlayer *player = m_env->getPlayer(*i);
1717 SendSpawnParticle(*i, player->protocol_version,
1718 pos, velocity, acceleration,
1719 expirationtime, size, collisiondetection,
1720 collision_removal, vertical, texture, animation, glow);
1725 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1727 pkt << pos << velocity << acceleration << expirationtime
1728 << size << collisiondetection;
1729 pkt.putLongString(texture);
1731 pkt << collision_removal;
1732 // This is horrible but required (why are there two ways to serialize pkts?)
1733 std::ostringstream os(std::ios_base::binary);
1734 animation.serialize(os, protocol_version);
1735 pkt.putRawString(os.str());
1741 // Adds a ParticleSpawner on peer with peer_id
1742 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1743 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1744 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1745 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1746 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1747 const struct TileAnimationParams &animation, u8 glow)
1749 DSTACK(FUNCTION_NAME);
1750 if (peer_id == PEER_ID_INEXISTENT) {
1751 // This sucks and should be replaced:
1752 std::vector<u16> clients = m_clients.getClientIDs();
1753 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1754 RemotePlayer *player = m_env->getPlayer(*i);
1757 SendAddParticleSpawner(*i, player->protocol_version,
1758 amount, spawntime, minpos, maxpos,
1759 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1760 minsize, maxsize, collisiondetection, collision_removal,
1761 attached_id, vertical, texture, id, animation, glow);
1766 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1768 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1769 << minacc << maxacc << minexptime << maxexptime << minsize
1770 << maxsize << collisiondetection;
1772 pkt.putLongString(texture);
1774 pkt << id << vertical;
1775 pkt << collision_removal;
1777 // This is horrible but required
1778 std::ostringstream os(std::ios_base::binary);
1779 animation.serialize(os, protocol_version);
1780 pkt.putRawString(os.str());
1786 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1788 DSTACK(FUNCTION_NAME);
1790 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1792 // Ugly error in this packet
1795 if (peer_id != PEER_ID_INEXISTENT) {
1799 m_clients.sendToAll(&pkt);
1804 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1806 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1808 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1809 << form->text << form->number << form->item << form->dir
1810 << form->align << form->offset << form->world_pos << form->size;
1815 void Server::SendHUDRemove(u16 peer_id, u32 id)
1817 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1822 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1824 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1825 pkt << id << (u8) stat;
1829 case HUD_STAT_SCALE:
1830 case HUD_STAT_ALIGN:
1831 case HUD_STAT_OFFSET:
1832 pkt << *(v2f *) value;
1836 pkt << *(std::string *) value;
1838 case HUD_STAT_WORLD_POS:
1839 pkt << *(v3f *) value;
1842 pkt << *(v2s32 *) value;
1844 case HUD_STAT_NUMBER:
1848 pkt << *(u32 *) value;
1855 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1857 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1859 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1861 pkt << flags << mask;
1866 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1868 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1869 pkt << param << value;
1873 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1874 const std::string &type, const std::vector<std::string> ¶ms)
1876 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1877 pkt << bgcolor << type << (u16) params.size();
1879 for(size_t i=0; i<params.size(); i++)
1885 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1888 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1891 pkt << do_override << (u16) (ratio * 65535);
1896 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1898 DSTACK(FUNCTION_NAME);
1900 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1901 pkt << time << time_speed;
1903 if (peer_id == PEER_ID_INEXISTENT) {
1904 m_clients.sendToAll(&pkt);
1911 void Server::SendPlayerHP(u16 peer_id)
1913 DSTACK(FUNCTION_NAME);
1914 PlayerSAO *playersao = getPlayerSAO(peer_id);
1915 // In some rare case if the player is disconnected
1916 // while Lua call l_punch, for example, this can be NULL
1920 SendHP(peer_id, playersao->getHP());
1921 m_script->player_event(playersao,"health_changed");
1923 // Send to other clients
1924 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1925 ActiveObjectMessage aom(playersao->getId(), true, str);
1926 playersao->m_messages_out.push(aom);
1929 void Server::SendPlayerBreath(PlayerSAO *sao)
1931 DSTACK(FUNCTION_NAME);
1934 m_script->player_event(sao, "breath_changed");
1935 SendBreath(sao->getPeerID(), sao->getBreath());
1938 void Server::SendMovePlayer(u16 peer_id)
1940 DSTACK(FUNCTION_NAME);
1941 RemotePlayer *player = m_env->getPlayer(peer_id);
1943 PlayerSAO *sao = player->getPlayerSAO();
1946 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1947 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1950 v3f pos = sao->getBasePosition();
1951 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1952 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1953 << " pitch=" << sao->getPitch()
1954 << " yaw=" << sao->getYaw()
1961 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1963 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1966 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1967 << animation_frames[3] << animation_speed;
1972 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1974 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1975 pkt << first << third;
1978 void Server::SendPlayerPrivileges(u16 peer_id)
1980 RemotePlayer *player = m_env->getPlayer(peer_id);
1982 if(player->peer_id == PEER_ID_INEXISTENT)
1985 std::set<std::string> privs;
1986 m_script->getAuth(player->getName(), NULL, &privs);
1988 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1989 pkt << (u16) privs.size();
1991 for(std::set<std::string>::const_iterator i = privs.begin();
1992 i != privs.end(); ++i) {
1999 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2001 RemotePlayer *player = m_env->getPlayer(peer_id);
2003 if(player->peer_id == PEER_ID_INEXISTENT)
2006 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2007 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2011 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2013 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2014 pkt.putRawString(datas.c_str(), datas.size());
2016 return pkt.getSize();
2019 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2021 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2022 datas.size(), peer_id);
2024 pkt.putRawString(datas.c_str(), datas.size());
2026 m_clients.send(pkt.getPeerId(),
2027 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2032 s32 Server::playSound(const SimpleSoundSpec &spec,
2033 const ServerSoundParams ¶ms)
2035 // Find out initial position of sound
2036 bool pos_exists = false;
2037 v3f pos = params.getPos(m_env, &pos_exists);
2038 // If position is not found while it should be, cancel sound
2039 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2042 // Filter destination clients
2043 std::vector<u16> dst_clients;
2044 if(params.to_player != "")
2046 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2048 infostream<<"Server::playSound: Player \""<<params.to_player
2049 <<"\" not found"<<std::endl;
2052 if(player->peer_id == PEER_ID_INEXISTENT){
2053 infostream<<"Server::playSound: Player \""<<params.to_player
2054 <<"\" not connected"<<std::endl;
2057 dst_clients.push_back(player->peer_id);
2060 std::vector<u16> clients = m_clients.getClientIDs();
2062 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2063 RemotePlayer *player = m_env->getPlayer(*i);
2067 PlayerSAO *sao = player->getPlayerSAO();
2072 if(sao->getBasePosition().getDistanceFrom(pos) >
2073 params.max_hear_distance)
2076 dst_clients.push_back(*i);
2080 if(dst_clients.empty())
2084 s32 id = m_next_sound_id++;
2085 // The sound will exist as a reference in m_playing_sounds
2086 m_playing_sounds[id] = ServerPlayingSound();
2087 ServerPlayingSound &psound = m_playing_sounds[id];
2088 psound.params = params;
2090 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2091 pkt << id << spec.name << (float) (spec.gain * params.gain)
2092 << (u8) params.type << pos << params.object << params.loop;
2094 for(std::vector<u16>::iterator i = dst_clients.begin();
2095 i != dst_clients.end(); ++i) {
2096 psound.clients.insert(*i);
2097 m_clients.send(*i, 0, &pkt, true);
2101 void Server::stopSound(s32 handle)
2103 // Get sound reference
2104 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2105 if (i == m_playing_sounds.end())
2107 ServerPlayingSound &psound = i->second;
2109 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2112 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2113 i != psound.clients.end(); ++i) {
2115 m_clients.send(*i, 0, &pkt, true);
2117 // Remove sound reference
2118 m_playing_sounds.erase(i);
2121 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2122 std::vector<u16> *far_players, float far_d_nodes)
2124 float maxd = far_d_nodes*BS;
2125 v3f p_f = intToFloat(p, BS);
2127 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2130 std::vector<u16> clients = m_clients.getClientIDs();
2131 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2134 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2135 PlayerSAO *sao = player->getPlayerSAO();
2139 // If player is far away, only set modified blocks not sent
2140 v3f player_pos = sao->getBasePosition();
2141 if (player_pos.getDistanceFrom(p_f) > maxd) {
2142 far_players->push_back(*i);
2149 m_clients.send(*i, 0, &pkt, true);
2153 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2154 std::vector<u16> *far_players, float far_d_nodes,
2155 bool remove_metadata)
2157 float maxd = far_d_nodes*BS;
2158 v3f p_f = intToFloat(p, BS);
2160 std::vector<u16> clients = m_clients.getClientIDs();
2161 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2164 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2165 PlayerSAO *sao = player->getPlayerSAO();
2169 // If player is far away, only set modified blocks not sent
2170 v3f player_pos = sao->getBasePosition();
2171 if(player_pos.getDistanceFrom(p_f) > maxd) {
2172 far_players->push_back(*i);
2178 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2180 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2182 pkt << p << n.param0 << n.param1 << n.param2
2183 << (u8) (remove_metadata ? 0 : 1);
2188 if (pkt.getSize() > 0)
2189 m_clients.send(*i, 0, &pkt, true);
2193 void Server::setBlockNotSent(v3s16 p)
2195 std::vector<u16> clients = m_clients.getClientIDs();
2197 for(std::vector<u16>::iterator i = clients.begin();
2198 i != clients.end(); ++i) {
2199 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2200 client->SetBlockNotSent(p);
2205 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2207 DSTACK(FUNCTION_NAME);
2209 v3s16 p = block->getPos();
2212 Create a packet with the block in the right format
2215 std::ostringstream os(std::ios_base::binary);
2216 block->serialize(os, ver, false);
2217 block->serializeNetworkSpecific(os);
2218 std::string s = os.str();
2220 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2223 pkt.putRawString(s.c_str(), s.size());
2227 void Server::SendBlocks(float dtime)
2229 DSTACK(FUNCTION_NAME);
2231 MutexAutoLock envlock(m_env_mutex);
2232 //TODO check if one big lock could be faster then multiple small ones
2234 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2236 std::vector<PrioritySortedBlockTransfer> queue;
2238 s32 total_sending = 0;
2241 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2243 std::vector<u16> clients = m_clients.getClientIDs();
2246 for(std::vector<u16>::iterator i = clients.begin();
2247 i != clients.end(); ++i) {
2248 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2253 total_sending += client->SendingCount();
2254 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2260 // Lowest priority number comes first.
2261 // Lowest is most important.
2262 std::sort(queue.begin(), queue.end());
2265 for(u32 i=0; i<queue.size(); i++)
2267 //TODO: Calculate limit dynamically
2268 if(total_sending >= g_settings->getS32
2269 ("max_simultaneous_block_sends_server_total"))
2272 PrioritySortedBlockTransfer q = queue[i];
2274 MapBlock *block = NULL;
2277 block = m_env->getMap().getBlockNoCreate(q.pos);
2279 catch(InvalidPositionException &e)
2284 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2289 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2291 client->SentBlock(q.pos);
2297 void Server::fillMediaCache()
2299 DSTACK(FUNCTION_NAME);
2301 infostream<<"Server: Calculating media file checksums"<<std::endl;
2303 // Collect all media file paths
2304 std::vector<std::string> paths;
2305 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2306 i != m_mods.end(); ++i) {
2307 const ModSpec &mod = *i;
2308 paths.push_back(mod.path + DIR_DELIM + "textures");
2309 paths.push_back(mod.path + DIR_DELIM + "sounds");
2310 paths.push_back(mod.path + DIR_DELIM + "media");
2311 paths.push_back(mod.path + DIR_DELIM + "models");
2313 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2315 // Collect media file information from paths into cache
2316 for(std::vector<std::string>::iterator i = paths.begin();
2317 i != paths.end(); ++i) {
2318 std::string mediapath = *i;
2319 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2320 for (u32 j = 0; j < dirlist.size(); j++) {
2321 if (dirlist[j].dir) // Ignode dirs
2323 std::string filename = dirlist[j].name;
2324 // If name contains illegal characters, ignore the file
2325 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2326 infostream<<"Server: ignoring illegal file name: \""
2327 << filename << "\"" << std::endl;
2330 // If name is not in a supported format, ignore it
2331 const char *supported_ext[] = {
2332 ".png", ".jpg", ".bmp", ".tga",
2333 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2335 ".x", ".b3d", ".md2", ".obj",
2338 if (removeStringEnd(filename, supported_ext) == ""){
2339 infostream << "Server: ignoring unsupported file extension: \""
2340 << filename << "\"" << std::endl;
2343 // Ok, attempt to load the file and add to cache
2344 std::string filepath = mediapath + DIR_DELIM + filename;
2346 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2348 errorstream << "Server::fillMediaCache(): Could not open \""
2349 << filename << "\" for reading" << std::endl;
2352 std::ostringstream tmp_os(std::ios_base::binary);
2356 fis.read(buf, 1024);
2357 std::streamsize len = fis.gcount();
2358 tmp_os.write(buf, len);
2367 errorstream<<"Server::fillMediaCache(): Failed to read \""
2368 << filename << "\"" << std::endl;
2371 if(tmp_os.str().length() == 0) {
2372 errorstream << "Server::fillMediaCache(): Empty file \""
2373 << filepath << "\"" << std::endl;
2378 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2380 unsigned char *digest = sha1.getDigest();
2381 std::string sha1_base64 = base64_encode(digest, 20);
2382 std::string sha1_hex = hex_encode((char*)digest, 20);
2386 m_media[filename] = MediaInfo(filepath, sha1_base64);
2387 verbosestream << "Server: " << sha1_hex << " is " << filename
2393 void Server::sendMediaAnnouncement(u16 peer_id)
2395 DSTACK(FUNCTION_NAME);
2397 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2401 std::ostringstream os(std::ios_base::binary);
2403 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2404 pkt << (u16) m_media.size();
2406 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2407 i != m_media.end(); ++i) {
2408 pkt << i->first << i->second.sha1_digest;
2411 pkt << g_settings->get("remote_media");
2415 struct SendableMedia
2421 SendableMedia(const std::string &name_="", const std::string &path_="",
2422 const std::string &data_=""):
2429 void Server::sendRequestedMedia(u16 peer_id,
2430 const std::vector<std::string> &tosend)
2432 DSTACK(FUNCTION_NAME);
2434 verbosestream<<"Server::sendRequestedMedia(): "
2435 <<"Sending files to client"<<std::endl;
2439 // Put 5kB in one bunch (this is not accurate)
2440 u32 bytes_per_bunch = 5000;
2442 std::vector< std::vector<SendableMedia> > file_bunches;
2443 file_bunches.push_back(std::vector<SendableMedia>());
2445 u32 file_size_bunch_total = 0;
2447 for(std::vector<std::string>::const_iterator i = tosend.begin();
2448 i != tosend.end(); ++i) {
2449 const std::string &name = *i;
2451 if (m_media.find(name) == m_media.end()) {
2452 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2453 <<"unknown file \""<<(name)<<"\""<<std::endl;
2457 //TODO get path + name
2458 std::string tpath = m_media[name].path;
2461 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2462 if(fis.good() == false){
2463 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2464 <<tpath<<"\" for reading"<<std::endl;
2467 std::ostringstream tmp_os(std::ios_base::binary);
2471 fis.read(buf, 1024);
2472 std::streamsize len = fis.gcount();
2473 tmp_os.write(buf, len);
2474 file_size_bunch_total += len;
2483 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2484 <<name<<"\""<<std::endl;
2487 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2488 <<tname<<"\""<<std::endl;*/
2490 file_bunches[file_bunches.size()-1].push_back(
2491 SendableMedia(name, tpath, tmp_os.str()));
2493 // Start next bunch if got enough data
2494 if(file_size_bunch_total >= bytes_per_bunch) {
2495 file_bunches.push_back(std::vector<SendableMedia>());
2496 file_size_bunch_total = 0;
2501 /* Create and send packets */
2503 u16 num_bunches = file_bunches.size();
2504 for(u16 i = 0; i < num_bunches; i++) {
2507 u16 total number of texture bunches
2508 u16 index of this bunch
2509 u32 number of files in this bunch
2518 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2519 pkt << num_bunches << i << (u32) file_bunches[i].size();
2521 for(std::vector<SendableMedia>::iterator
2522 j = file_bunches[i].begin();
2523 j != file_bunches[i].end(); ++j) {
2525 pkt.putLongString(j->data);
2528 verbosestream << "Server::sendRequestedMedia(): bunch "
2529 << i << "/" << num_bunches
2530 << " files=" << file_bunches[i].size()
2531 << " size=" << pkt.getSize() << std::endl;
2536 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2538 if(m_detached_inventories.count(name) == 0) {
2539 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2542 Inventory *inv = m_detached_inventories[name];
2543 std::ostringstream os(std::ios_base::binary);
2545 os << serializeString(name);
2549 std::string s = os.str();
2551 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2552 pkt.putRawString(s.c_str(), s.size());
2554 const std::string &check = m_detached_inventories_player[name];
2555 if (peer_id == PEER_ID_INEXISTENT) {
2557 return m_clients.sendToAll(&pkt);
2558 RemotePlayer *p = m_env->getPlayer(check.c_str());
2560 m_clients.send(p->peer_id, 0, &pkt, true);
2562 if (check == "" || getPlayerName(peer_id) == check)
2567 void Server::sendDetachedInventories(u16 peer_id)
2569 DSTACK(FUNCTION_NAME);
2571 for(std::map<std::string, Inventory*>::iterator
2572 i = m_detached_inventories.begin();
2573 i != m_detached_inventories.end(); ++i) {
2574 const std::string &name = i->first;
2575 //Inventory *inv = i->second;
2576 sendDetachedInventory(name, peer_id);
2584 void Server::DiePlayer(u16 peer_id)
2586 DSTACK(FUNCTION_NAME);
2587 PlayerSAO *playersao = getPlayerSAO(peer_id);
2588 // In some rare cases this can be NULL -- if the player is disconnected
2589 // when a Lua function modifies l_punch, for example
2593 infostream << "Server::DiePlayer(): Player "
2594 << playersao->getPlayer()->getName()
2595 << " dies" << std::endl;
2597 playersao->setHP(0);
2599 // Trigger scripted stuff
2600 m_script->on_dieplayer(playersao);
2602 SendPlayerHP(peer_id);
2603 SendDeathscreen(peer_id, false, v3f(0,0,0));
2606 void Server::RespawnPlayer(u16 peer_id)
2608 DSTACK(FUNCTION_NAME);
2610 PlayerSAO *playersao = getPlayerSAO(peer_id);
2613 infostream << "Server::RespawnPlayer(): Player "
2614 << playersao->getPlayer()->getName()
2615 << " respawns" << std::endl;
2617 playersao->setHP(PLAYER_MAX_HP);
2618 playersao->setBreath(PLAYER_MAX_BREATH);
2620 bool repositioned = m_script->on_respawnplayer(playersao);
2621 if (!repositioned) {
2622 // setPos will send the new position to client
2623 playersao->setPos(findSpawnPos());
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)
3520 Try to get an existing player
3522 RemotePlayer *player = m_env->getPlayer(name);
3524 // If player is already connected, cancel
3525 if (player != NULL && player->peer_id != 0) {
3526 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3531 If player with the wanted peer_id already exists, cancel.
3533 if (m_env->getPlayer(peer_id) != NULL) {
3534 infostream<<"emergePlayer(): Player with wrong name but same"
3535 " peer_id already exists"<<std::endl;
3540 player = new RemotePlayer(name, idef());
3543 bool newplayer = false;
3546 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3548 // Complete init with server parts
3549 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3550 player->protocol_version = proto_version;
3554 m_script->on_newplayer(playersao);
3560 bool Server::registerModStorage(ModMetadata *storage)
3562 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3563 errorstream << "Unable to register same mod storage twice. Storage name: "
3564 << storage->getModName() << std::endl;
3568 m_mod_storages[storage->getModName()] = storage;
3572 void Server::unregisterModStorage(const std::string &name)
3574 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3575 if (it != m_mod_storages.end()) {
3576 // Save unconditionaly on unregistration
3577 it->second->save(getModStoragePath());
3578 m_mod_storages.erase(name);
3582 void dedicated_server_loop(Server &server, bool &kill)
3584 DSTACK(FUNCTION_NAME);
3586 verbosestream<<"dedicated_server_loop()"<<std::endl;
3588 IntervalLimiter m_profiler_interval;
3590 static const float steplen = g_settings->getFloat("dedicated_server_step");
3591 static const float profiler_print_interval =
3592 g_settings->getFloat("profiler_print_interval");
3595 // This is kind of a hack but can be done like this
3596 // because server.step() is very light
3598 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3599 sleep_ms((int)(steplen*1000.0));
3601 server.step(steplen);
3603 if (server.getShutdownRequested() || kill)
3609 if (profiler_print_interval != 0) {
3610 if(m_profiler_interval.step(steplen, profiler_print_interval))
3612 infostream<<"Profiler:"<<std::endl;
3613 g_profiler->print(infostream);
3614 g_profiler->clear();
3619 infostream << "Dedicated server quitting" << std::endl;
3621 if (g_settings->getBool("server_announce"))
3622 ServerList::sendAnnounce(ServerList::AA_DELETE,
3623 server.m_bind_addr.getPort());