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 static const float radius =
1711 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1713 if (peer_id == PEER_ID_INEXISTENT) {
1714 std::vector<u16> clients = m_clients.getClientIDs();
1716 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1717 RemotePlayer *player = m_env->getPlayer(*i);
1721 PlayerSAO *sao = player->getPlayerSAO();
1725 // Do not send to distant clients
1726 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1729 SendSpawnParticle(*i, player->protocol_version,
1730 pos, velocity, acceleration,
1731 expirationtime, size, collisiondetection,
1732 collision_removal, vertical, texture, animation, glow);
1737 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1739 pkt << pos << velocity << acceleration << expirationtime
1740 << size << collisiondetection;
1741 pkt.putLongString(texture);
1743 pkt << collision_removal;
1744 // This is horrible but required (why are there two ways to serialize pkts?)
1745 std::ostringstream os(std::ios_base::binary);
1746 animation.serialize(os, protocol_version);
1747 pkt.putRawString(os.str());
1753 // Adds a ParticleSpawner on peer with peer_id
1754 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1755 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1756 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1757 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1758 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1759 const struct TileAnimationParams &animation, u8 glow)
1761 DSTACK(FUNCTION_NAME);
1762 if (peer_id == PEER_ID_INEXISTENT) {
1763 // This sucks and should be replaced:
1764 std::vector<u16> clients = m_clients.getClientIDs();
1765 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1766 RemotePlayer *player = m_env->getPlayer(*i);
1769 SendAddParticleSpawner(*i, player->protocol_version,
1770 amount, spawntime, minpos, maxpos,
1771 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1772 minsize, maxsize, collisiondetection, collision_removal,
1773 attached_id, vertical, texture, id, animation, glow);
1778 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1780 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1781 << minacc << maxacc << minexptime << maxexptime << minsize
1782 << maxsize << collisiondetection;
1784 pkt.putLongString(texture);
1786 pkt << id << vertical;
1787 pkt << collision_removal;
1789 // This is horrible but required
1790 std::ostringstream os(std::ios_base::binary);
1791 animation.serialize(os, protocol_version);
1792 pkt.putRawString(os.str());
1798 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1800 DSTACK(FUNCTION_NAME);
1802 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1804 // Ugly error in this packet
1807 if (peer_id != PEER_ID_INEXISTENT) {
1811 m_clients.sendToAll(&pkt);
1816 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1818 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1820 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1821 << form->text << form->number << form->item << form->dir
1822 << form->align << form->offset << form->world_pos << form->size;
1827 void Server::SendHUDRemove(u16 peer_id, u32 id)
1829 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1834 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1836 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1837 pkt << id << (u8) stat;
1841 case HUD_STAT_SCALE:
1842 case HUD_STAT_ALIGN:
1843 case HUD_STAT_OFFSET:
1844 pkt << *(v2f *) value;
1848 pkt << *(std::string *) value;
1850 case HUD_STAT_WORLD_POS:
1851 pkt << *(v3f *) value;
1854 pkt << *(v2s32 *) value;
1856 case HUD_STAT_NUMBER:
1860 pkt << *(u32 *) value;
1867 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1869 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1871 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1873 pkt << flags << mask;
1878 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1880 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1881 pkt << param << value;
1885 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1886 const std::string &type, const std::vector<std::string> ¶ms,
1889 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1890 pkt << bgcolor << type << (u16) params.size();
1892 for(size_t i=0; i<params.size(); i++)
1900 void Server::SendCloudParams(u16 peer_id, float density,
1901 const video::SColor &color_bright,
1902 const video::SColor &color_ambient,
1907 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1908 pkt << density << color_bright << color_ambient
1909 << height << thickness << speed;
1914 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1917 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1920 pkt << do_override << (u16) (ratio * 65535);
1925 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1927 DSTACK(FUNCTION_NAME);
1929 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1930 pkt << time << time_speed;
1932 if (peer_id == PEER_ID_INEXISTENT) {
1933 m_clients.sendToAll(&pkt);
1940 void Server::SendPlayerHP(u16 peer_id)
1942 DSTACK(FUNCTION_NAME);
1943 PlayerSAO *playersao = getPlayerSAO(peer_id);
1944 // In some rare case if the player is disconnected
1945 // while Lua call l_punch, for example, this can be NULL
1949 SendHP(peer_id, playersao->getHP());
1950 m_script->player_event(playersao,"health_changed");
1952 // Send to other clients
1953 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1954 ActiveObjectMessage aom(playersao->getId(), true, str);
1955 playersao->m_messages_out.push(aom);
1958 void Server::SendPlayerBreath(PlayerSAO *sao)
1960 DSTACK(FUNCTION_NAME);
1963 m_script->player_event(sao, "breath_changed");
1964 SendBreath(sao->getPeerID(), sao->getBreath());
1967 void Server::SendMovePlayer(u16 peer_id)
1969 DSTACK(FUNCTION_NAME);
1970 RemotePlayer *player = m_env->getPlayer(peer_id);
1972 PlayerSAO *sao = player->getPlayerSAO();
1975 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1976 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1979 v3f pos = sao->getBasePosition();
1980 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1981 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1982 << " pitch=" << sao->getPitch()
1983 << " yaw=" << sao->getYaw()
1990 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1992 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1995 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1996 << animation_frames[3] << animation_speed;
2001 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
2003 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
2004 pkt << first << third;
2007 void Server::SendPlayerPrivileges(u16 peer_id)
2009 RemotePlayer *player = m_env->getPlayer(peer_id);
2011 if(player->peer_id == PEER_ID_INEXISTENT)
2014 std::set<std::string> privs;
2015 m_script->getAuth(player->getName(), NULL, &privs);
2017 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
2018 pkt << (u16) privs.size();
2020 for(std::set<std::string>::const_iterator i = privs.begin();
2021 i != privs.end(); ++i) {
2028 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2030 RemotePlayer *player = m_env->getPlayer(peer_id);
2032 if(player->peer_id == PEER_ID_INEXISTENT)
2035 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2036 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2040 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2042 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2043 pkt.putRawString(datas.c_str(), datas.size());
2045 return pkt.getSize();
2048 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2050 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2051 datas.size(), peer_id);
2053 pkt.putRawString(datas.c_str(), datas.size());
2055 m_clients.send(pkt.getPeerId(),
2056 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2061 s32 Server::playSound(const SimpleSoundSpec &spec,
2062 const ServerSoundParams ¶ms)
2064 // Find out initial position of sound
2065 bool pos_exists = false;
2066 v3f pos = params.getPos(m_env, &pos_exists);
2067 // If position is not found while it should be, cancel sound
2068 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2071 // Filter destination clients
2072 std::vector<u16> dst_clients;
2073 if(params.to_player != "")
2075 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2077 infostream<<"Server::playSound: Player \""<<params.to_player
2078 <<"\" not found"<<std::endl;
2081 if(player->peer_id == PEER_ID_INEXISTENT){
2082 infostream<<"Server::playSound: Player \""<<params.to_player
2083 <<"\" not connected"<<std::endl;
2086 dst_clients.push_back(player->peer_id);
2089 std::vector<u16> clients = m_clients.getClientIDs();
2091 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2092 RemotePlayer *player = m_env->getPlayer(*i);
2096 PlayerSAO *sao = player->getPlayerSAO();
2101 if(sao->getBasePosition().getDistanceFrom(pos) >
2102 params.max_hear_distance)
2105 dst_clients.push_back(*i);
2109 if(dst_clients.empty())
2113 s32 id = m_next_sound_id++;
2114 // The sound will exist as a reference in m_playing_sounds
2115 m_playing_sounds[id] = ServerPlayingSound();
2116 ServerPlayingSound &psound = m_playing_sounds[id];
2117 psound.params = params;
2120 float gain = params.gain * spec.gain;
2121 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2122 pkt << id << spec.name << gain
2123 << (u8) params.type << pos << params.object
2124 << params.loop << params.fade;
2126 // Backwards compability
2127 bool play_sound = gain > 0;
2129 for (std::vector<u16>::iterator i = dst_clients.begin();
2130 i != dst_clients.end(); ++i) {
2131 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2132 psound.clients.insert(*i);
2133 m_clients.send(*i, 0, &pkt, true);
2138 void Server::stopSound(s32 handle)
2140 // Get sound reference
2141 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2142 if (i == m_playing_sounds.end())
2144 ServerPlayingSound &psound = i->second;
2146 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2149 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2150 i != psound.clients.end(); ++i) {
2152 m_clients.send(*i, 0, &pkt, true);
2154 // Remove sound reference
2155 m_playing_sounds.erase(i);
2158 void Server::fadeSound(s32 handle, float step, float gain)
2160 // Get sound reference
2161 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i =
2162 m_playing_sounds.find(handle);
2163 if (i == m_playing_sounds.end())
2166 ServerPlayingSound &psound = i->second;
2167 psound.params.gain = gain;
2169 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2170 pkt << handle << step << gain;
2172 // Backwards compability
2173 bool play_sound = gain > 0;
2174 ServerPlayingSound compat_psound = psound;
2175 compat_psound.clients.clear();
2177 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2178 compat_pkt << handle;
2180 for (UNORDERED_SET<u16>::iterator it = psound.clients.begin();
2181 it != psound.clients.end();) {
2182 if (m_clients.getProtocolVersion(*it) >= 32) {
2184 m_clients.send(*it, 0, &pkt, true);
2187 compat_psound.clients.insert(*it);
2189 m_clients.send(*it, 0, &compat_pkt, true);
2190 psound.clients.erase(it++);
2194 // Remove sound reference
2195 if (!play_sound || psound.clients.size() == 0)
2196 m_playing_sounds.erase(i);
2198 if (play_sound && compat_psound.clients.size() > 0) {
2199 // Play new sound volume on older clients
2200 playSound(compat_psound.spec, compat_psound.params);
2204 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2205 std::vector<u16> *far_players, float far_d_nodes)
2207 float maxd = far_d_nodes*BS;
2208 v3f p_f = intToFloat(p, BS);
2210 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2213 std::vector<u16> clients = m_clients.getClientIDs();
2214 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2217 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2218 PlayerSAO *sao = player->getPlayerSAO();
2222 // If player is far away, only set modified blocks not sent
2223 v3f player_pos = sao->getBasePosition();
2224 if (player_pos.getDistanceFrom(p_f) > maxd) {
2225 far_players->push_back(*i);
2232 m_clients.send(*i, 0, &pkt, true);
2236 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2237 std::vector<u16> *far_players, float far_d_nodes,
2238 bool remove_metadata)
2240 float maxd = far_d_nodes*BS;
2241 v3f p_f = intToFloat(p, BS);
2243 std::vector<u16> clients = m_clients.getClientIDs();
2244 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2247 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2248 PlayerSAO *sao = player->getPlayerSAO();
2252 // If player is far away, only set modified blocks not sent
2253 v3f player_pos = sao->getBasePosition();
2254 if(player_pos.getDistanceFrom(p_f) > maxd) {
2255 far_players->push_back(*i);
2261 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2263 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2265 pkt << p << n.param0 << n.param1 << n.param2
2266 << (u8) (remove_metadata ? 0 : 1);
2271 if (pkt.getSize() > 0)
2272 m_clients.send(*i, 0, &pkt, true);
2276 void Server::setBlockNotSent(v3s16 p)
2278 std::vector<u16> clients = m_clients.getClientIDs();
2280 for(std::vector<u16>::iterator i = clients.begin();
2281 i != clients.end(); ++i) {
2282 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2283 client->SetBlockNotSent(p);
2288 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2290 DSTACK(FUNCTION_NAME);
2292 v3s16 p = block->getPos();
2295 Create a packet with the block in the right format
2298 std::ostringstream os(std::ios_base::binary);
2299 block->serialize(os, ver, false);
2300 block->serializeNetworkSpecific(os);
2301 std::string s = os.str();
2303 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2306 pkt.putRawString(s.c_str(), s.size());
2310 void Server::SendBlocks(float dtime)
2312 DSTACK(FUNCTION_NAME);
2314 MutexAutoLock envlock(m_env_mutex);
2315 //TODO check if one big lock could be faster then multiple small ones
2317 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2319 std::vector<PrioritySortedBlockTransfer> queue;
2321 s32 total_sending = 0;
2324 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2326 std::vector<u16> clients = m_clients.getClientIDs();
2329 for(std::vector<u16>::iterator i = clients.begin();
2330 i != clients.end(); ++i) {
2331 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2336 total_sending += client->SendingCount();
2337 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2343 // Lowest priority number comes first.
2344 // Lowest is most important.
2345 std::sort(queue.begin(), queue.end());
2348 for(u32 i=0; i<queue.size(); i++)
2350 //TODO: Calculate limit dynamically
2351 if(total_sending >= g_settings->getS32
2352 ("max_simultaneous_block_sends_server_total"))
2355 PrioritySortedBlockTransfer q = queue[i];
2357 MapBlock *block = NULL;
2360 block = m_env->getMap().getBlockNoCreate(q.pos);
2362 catch(InvalidPositionException &e)
2367 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2372 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2374 client->SentBlock(q.pos);
2380 void Server::fillMediaCache()
2382 DSTACK(FUNCTION_NAME);
2384 infostream<<"Server: Calculating media file checksums"<<std::endl;
2386 // Collect all media file paths
2387 std::vector<std::string> paths;
2388 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2389 i != m_mods.end(); ++i) {
2390 const ModSpec &mod = *i;
2391 paths.push_back(mod.path + DIR_DELIM + "textures");
2392 paths.push_back(mod.path + DIR_DELIM + "sounds");
2393 paths.push_back(mod.path + DIR_DELIM + "media");
2394 paths.push_back(mod.path + DIR_DELIM + "models");
2396 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2398 // Collect media file information from paths into cache
2399 for(std::vector<std::string>::iterator i = paths.begin();
2400 i != paths.end(); ++i) {
2401 std::string mediapath = *i;
2402 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2403 for (u32 j = 0; j < dirlist.size(); j++) {
2404 if (dirlist[j].dir) // Ignode dirs
2406 std::string filename = dirlist[j].name;
2407 // If name contains illegal characters, ignore the file
2408 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2409 infostream<<"Server: ignoring illegal file name: \""
2410 << filename << "\"" << std::endl;
2413 // If name is not in a supported format, ignore it
2414 const char *supported_ext[] = {
2415 ".png", ".jpg", ".bmp", ".tga",
2416 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2418 ".x", ".b3d", ".md2", ".obj",
2421 if (removeStringEnd(filename, supported_ext) == ""){
2422 infostream << "Server: ignoring unsupported file extension: \""
2423 << filename << "\"" << std::endl;
2426 // Ok, attempt to load the file and add to cache
2427 std::string filepath = mediapath + DIR_DELIM + filename;
2429 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2431 errorstream << "Server::fillMediaCache(): Could not open \""
2432 << filename << "\" for reading" << std::endl;
2435 std::ostringstream tmp_os(std::ios_base::binary);
2439 fis.read(buf, 1024);
2440 std::streamsize len = fis.gcount();
2441 tmp_os.write(buf, len);
2450 errorstream<<"Server::fillMediaCache(): Failed to read \""
2451 << filename << "\"" << std::endl;
2454 if(tmp_os.str().length() == 0) {
2455 errorstream << "Server::fillMediaCache(): Empty file \""
2456 << filepath << "\"" << std::endl;
2461 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2463 unsigned char *digest = sha1.getDigest();
2464 std::string sha1_base64 = base64_encode(digest, 20);
2465 std::string sha1_hex = hex_encode((char*)digest, 20);
2469 m_media[filename] = MediaInfo(filepath, sha1_base64);
2470 verbosestream << "Server: " << sha1_hex << " is " << filename
2476 void Server::sendMediaAnnouncement(u16 peer_id)
2478 DSTACK(FUNCTION_NAME);
2480 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2484 std::ostringstream os(std::ios_base::binary);
2486 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2487 pkt << (u16) m_media.size();
2489 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2490 i != m_media.end(); ++i) {
2491 pkt << i->first << i->second.sha1_digest;
2494 pkt << g_settings->get("remote_media");
2498 struct SendableMedia
2504 SendableMedia(const std::string &name_="", const std::string &path_="",
2505 const std::string &data_=""):
2512 void Server::sendRequestedMedia(u16 peer_id,
2513 const std::vector<std::string> &tosend)
2515 DSTACK(FUNCTION_NAME);
2517 verbosestream<<"Server::sendRequestedMedia(): "
2518 <<"Sending files to client"<<std::endl;
2522 // Put 5kB in one bunch (this is not accurate)
2523 u32 bytes_per_bunch = 5000;
2525 std::vector< std::vector<SendableMedia> > file_bunches;
2526 file_bunches.push_back(std::vector<SendableMedia>());
2528 u32 file_size_bunch_total = 0;
2530 for(std::vector<std::string>::const_iterator i = tosend.begin();
2531 i != tosend.end(); ++i) {
2532 const std::string &name = *i;
2534 if (m_media.find(name) == m_media.end()) {
2535 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2536 <<"unknown file \""<<(name)<<"\""<<std::endl;
2540 //TODO get path + name
2541 std::string tpath = m_media[name].path;
2544 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2545 if(fis.good() == false){
2546 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2547 <<tpath<<"\" for reading"<<std::endl;
2550 std::ostringstream tmp_os(std::ios_base::binary);
2554 fis.read(buf, 1024);
2555 std::streamsize len = fis.gcount();
2556 tmp_os.write(buf, len);
2557 file_size_bunch_total += len;
2566 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2567 <<name<<"\""<<std::endl;
2570 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2571 <<tname<<"\""<<std::endl;*/
2573 file_bunches[file_bunches.size()-1].push_back(
2574 SendableMedia(name, tpath, tmp_os.str()));
2576 // Start next bunch if got enough data
2577 if(file_size_bunch_total >= bytes_per_bunch) {
2578 file_bunches.push_back(std::vector<SendableMedia>());
2579 file_size_bunch_total = 0;
2584 /* Create and send packets */
2586 u16 num_bunches = file_bunches.size();
2587 for(u16 i = 0; i < num_bunches; i++) {
2590 u16 total number of texture bunches
2591 u16 index of this bunch
2592 u32 number of files in this bunch
2601 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2602 pkt << num_bunches << i << (u32) file_bunches[i].size();
2604 for(std::vector<SendableMedia>::iterator
2605 j = file_bunches[i].begin();
2606 j != file_bunches[i].end(); ++j) {
2608 pkt.putLongString(j->data);
2611 verbosestream << "Server::sendRequestedMedia(): bunch "
2612 << i << "/" << num_bunches
2613 << " files=" << file_bunches[i].size()
2614 << " size=" << pkt.getSize() << std::endl;
2619 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2621 if(m_detached_inventories.count(name) == 0) {
2622 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2625 Inventory *inv = m_detached_inventories[name];
2626 std::ostringstream os(std::ios_base::binary);
2628 os << serializeString(name);
2632 std::string s = os.str();
2634 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2635 pkt.putRawString(s.c_str(), s.size());
2637 const std::string &check = m_detached_inventories_player[name];
2638 if (peer_id == PEER_ID_INEXISTENT) {
2640 return m_clients.sendToAll(&pkt);
2641 RemotePlayer *p = m_env->getPlayer(check.c_str());
2643 m_clients.send(p->peer_id, 0, &pkt, true);
2645 if (check == "" || getPlayerName(peer_id) == check)
2650 void Server::sendDetachedInventories(u16 peer_id)
2652 DSTACK(FUNCTION_NAME);
2654 for(std::map<std::string, Inventory*>::iterator
2655 i = m_detached_inventories.begin();
2656 i != m_detached_inventories.end(); ++i) {
2657 const std::string &name = i->first;
2658 //Inventory *inv = i->second;
2659 sendDetachedInventory(name, peer_id);
2667 void Server::DiePlayer(u16 peer_id)
2669 DSTACK(FUNCTION_NAME);
2670 PlayerSAO *playersao = getPlayerSAO(peer_id);
2671 // In some rare cases this can be NULL -- if the player is disconnected
2672 // when a Lua function modifies l_punch, for example
2676 infostream << "Server::DiePlayer(): Player "
2677 << playersao->getPlayer()->getName()
2678 << " dies" << std::endl;
2680 playersao->setHP(0);
2682 // Trigger scripted stuff
2683 m_script->on_dieplayer(playersao);
2685 SendPlayerHP(peer_id);
2686 SendDeathscreen(peer_id, false, v3f(0,0,0));
2689 void Server::RespawnPlayer(u16 peer_id)
2691 DSTACK(FUNCTION_NAME);
2693 PlayerSAO *playersao = getPlayerSAO(peer_id);
2696 infostream << "Server::RespawnPlayer(): Player "
2697 << playersao->getPlayer()->getName()
2698 << " respawns" << std::endl;
2700 playersao->setHP(PLAYER_MAX_HP);
2701 playersao->setBreath(PLAYER_MAX_BREATH);
2703 bool repositioned = m_script->on_respawnplayer(playersao);
2704 if (!repositioned) {
2705 // setPos will send the new position to client
2706 playersao->setPos(findSpawnPos());
2709 SendPlayerHP(peer_id);
2713 void Server::DenySudoAccess(u16 peer_id)
2715 DSTACK(FUNCTION_NAME);
2717 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2722 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2723 const std::string &str_reason, bool reconnect)
2725 if (proto_ver >= 25) {
2726 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2728 std::wstring wreason = utf8_to_wide(
2729 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2730 accessDeniedStrings[(u8)reason]);
2731 SendAccessDenied_Legacy(peer_id, wreason);
2734 m_clients.event(peer_id, CSE_SetDenied);
2735 m_con.DisconnectPeer(peer_id);
2739 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2741 DSTACK(FUNCTION_NAME);
2743 SendAccessDenied(peer_id, reason, custom_reason);
2744 m_clients.event(peer_id, CSE_SetDenied);
2745 m_con.DisconnectPeer(peer_id);
2748 // 13/03/15: remove this function when protocol version 25 will become
2749 // the minimum version for MT users, maybe in 1 year
2750 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2752 DSTACK(FUNCTION_NAME);
2754 SendAccessDenied_Legacy(peer_id, reason);
2755 m_clients.event(peer_id, CSE_SetDenied);
2756 m_con.DisconnectPeer(peer_id);
2759 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2761 DSTACK(FUNCTION_NAME);
2764 RemoteClient* client = getClient(peer_id, CS_Invalid);
2766 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2768 // Right now, the auth mechs don't change between login and sudo mode.
2769 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2770 client->allowed_sudo_mechs = sudo_auth_mechs;
2772 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2773 << g_settings->getFloat("dedicated_server_step")
2777 m_clients.event(peer_id, CSE_AuthAccept);
2779 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2781 // We only support SRP right now
2782 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2784 resp_pkt << sudo_auth_mechs;
2786 m_clients.event(peer_id, CSE_SudoSuccess);
2790 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2792 DSTACK(FUNCTION_NAME);
2793 std::wstring message;
2796 Clear references to playing sounds
2798 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2799 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2800 ServerPlayingSound &psound = i->second;
2801 psound.clients.erase(peer_id);
2802 if (psound.clients.empty())
2803 m_playing_sounds.erase(i++);
2808 RemotePlayer *player = m_env->getPlayer(peer_id);
2810 /* Run scripts and remove from environment */
2811 if (player != NULL) {
2812 PlayerSAO *playersao = player->getPlayerSAO();
2815 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2817 playersao->disconnected();
2824 if(player != NULL && reason != CDR_DENY) {
2825 std::ostringstream os(std::ios_base::binary);
2826 std::vector<u16> clients = m_clients.getClientIDs();
2828 for(std::vector<u16>::iterator i = clients.begin();
2829 i != clients.end(); ++i) {
2831 RemotePlayer *player = m_env->getPlayer(*i);
2835 // Get name of player
2836 os << player->getName() << " ";
2839 std::string name = player->getName();
2840 actionstream << name << " "
2841 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2842 << " List of players: " << os.str() << std::endl;
2844 m_admin_chat->outgoing_queue.push_back(
2845 new ChatEventNick(CET_NICK_REMOVE, name));
2849 MutexAutoLock env_lock(m_env_mutex);
2850 m_clients.DeleteClient(peer_id);
2854 // Send leave chat message to all remaining clients
2855 if(message.length() != 0)
2856 SendChatMessage(PEER_ID_INEXISTENT,message);
2859 void Server::UpdateCrafting(RemotePlayer *player)
2861 DSTACK(FUNCTION_NAME);
2863 // Get a preview for crafting
2865 InventoryLocation loc;
2866 loc.setPlayer(player->getName());
2867 std::vector<ItemStack> output_replacements;
2868 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2869 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2870 (&player->inventory)->getList("craft"), loc);
2872 // Put the new preview in
2873 InventoryList *plist = player->inventory.getList("craftpreview");
2874 sanity_check(plist);
2875 sanity_check(plist->getSize() >= 1);
2876 plist->changeItem(0, preview);
2879 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2881 if (evt->type == CET_NICK_ADD) {
2882 // The terminal informed us of its nick choice
2883 m_admin_nick = ((ChatEventNick *)evt)->nick;
2884 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2885 errorstream << "You haven't set up an account." << std::endl
2886 << "Please log in using the client as '"
2887 << m_admin_nick << "' with a secure password." << std::endl
2888 << "Until then, you can't execute admin tasks via the console," << std::endl
2889 << "and everybody can claim the user account instead of you," << std::endl
2890 << "giving them full control over this server." << std::endl;
2893 assert(evt->type == CET_CHAT);
2894 handleAdminChat((ChatEventChat *)evt);
2898 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2899 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2901 // If something goes wrong, this player is to blame
2902 RollbackScopeActor rollback_scope(m_rollback,
2903 std::string("player:") + name);
2906 switch (player->canSendChatMessage()) {
2907 case RPLAYER_CHATRESULT_FLOODING: {
2908 std::wstringstream ws;
2909 ws << L"You cannot send more messages. You are limited to "
2910 << g_settings->getFloat("chat_message_limit_per_10sec")
2911 << L" messages per 10 seconds.";
2914 case RPLAYER_CHATRESULT_KICK:
2915 DenyAccess_Legacy(player->peer_id,
2916 L"You have been kicked due to message flooding.");
2918 case RPLAYER_CHATRESULT_OK:
2921 FATAL_ERROR("Unhandled chat filtering result found.");
2925 if (m_max_chatmessage_length > 0
2926 && wmessage.length() > m_max_chatmessage_length) {
2927 return L"Your message exceed the maximum chat message limit set on the server. "
2928 L"It was refused. Send a shorter message";
2931 // Run script hook, exit if script ate the chat message
2932 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2937 // Whether to send line to the player that sent the message, or to all players
2938 bool broadcast_line = true;
2940 if (check_shout_priv && !checkPriv(name, "shout")) {
2941 line += L"-!- You don't have permission to shout.";
2942 broadcast_line = false;
2951 Tell calling method to send the message to sender
2953 if (!broadcast_line) {
2957 Send the message to others
2959 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2961 std::vector<u16> clients = m_clients.getClientIDs();
2964 Send the message back to the inital sender
2965 if they are using protocol version >= 29
2968 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2969 if (player && player->protocol_version >= 29)
2970 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2972 for (u16 i = 0; i < clients.size(); i++) {
2973 u16 cid = clients[i];
2974 if (cid != peer_id_to_avoid_sending)
2975 SendChatMessage(cid, line);
2981 void Server::handleAdminChat(const ChatEventChat *evt)
2983 std::string name = evt->nick;
2984 std::wstring wname = utf8_to_wide(name);
2985 std::wstring wmessage = evt->evt_msg;
2987 std::wstring answer = handleChat(name, wname, wmessage);
2989 // If asked to send answer to sender
2990 if (!answer.empty()) {
2991 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2995 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2997 RemoteClient *client = getClientNoEx(peer_id,state_min);
2999 throw ClientNotFoundException("Client not found");
3003 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
3005 return m_clients.getClientNoEx(peer_id, state_min);
3008 std::string Server::getPlayerName(u16 peer_id)
3010 RemotePlayer *player = m_env->getPlayer(peer_id);
3012 return "[id="+itos(peer_id)+"]";
3013 return player->getName();
3016 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3018 RemotePlayer *player = m_env->getPlayer(peer_id);
3021 return player->getPlayerSAO();
3024 std::wstring Server::getStatusString()
3026 std::wostringstream os(std::ios_base::binary);
3029 os<<L"version="<<narrow_to_wide(g_version_string);
3031 os<<L", uptime="<<m_uptime.get();
3033 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3034 // Information about clients
3037 std::vector<u16> clients = m_clients.getClientIDs();
3038 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3040 RemotePlayer *player = m_env->getPlayer(*i);
3041 // Get name of player
3042 std::wstring name = L"unknown";
3044 name = narrow_to_wide(player->getName());
3045 // Add name to information string
3053 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3054 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3055 if(g_settings->get("motd") != "")
3056 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3060 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3062 std::set<std::string> privs;
3063 m_script->getAuth(name, NULL, &privs);
3067 bool Server::checkPriv(const std::string &name, const std::string &priv)
3069 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3070 return (privs.count(priv) != 0);
3073 void Server::reportPrivsModified(const std::string &name)
3076 std::vector<u16> clients = m_clients.getClientIDs();
3077 for(std::vector<u16>::iterator i = clients.begin();
3078 i != clients.end(); ++i) {
3079 RemotePlayer *player = m_env->getPlayer(*i);
3080 reportPrivsModified(player->getName());
3083 RemotePlayer *player = m_env->getPlayer(name.c_str());
3086 SendPlayerPrivileges(player->peer_id);
3087 PlayerSAO *sao = player->getPlayerSAO();
3090 sao->updatePrivileges(
3091 getPlayerEffectivePrivs(name),
3096 void Server::reportInventoryFormspecModified(const std::string &name)
3098 RemotePlayer *player = m_env->getPlayer(name.c_str());
3101 SendPlayerInventoryFormspec(player->peer_id);
3104 void Server::setIpBanned(const std::string &ip, const std::string &name)
3106 m_banmanager->add(ip, name);
3109 void Server::unsetIpBanned(const std::string &ip_or_name)
3111 m_banmanager->remove(ip_or_name);
3114 std::string Server::getBanDescription(const std::string &ip_or_name)
3116 return m_banmanager->getBanDescription(ip_or_name);
3119 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3121 // m_env will be NULL if the server is initializing
3125 if (m_admin_nick == name && !m_admin_nick.empty()) {
3126 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3129 RemotePlayer *player = m_env->getPlayer(name);
3134 if (player->peer_id == PEER_ID_INEXISTENT)
3137 SendChatMessage(player->peer_id, msg);
3140 bool Server::showFormspec(const char *playername, const std::string &formspec,
3141 const std::string &formname)
3143 // m_env will be NULL if the server is initializing
3147 RemotePlayer *player = m_env->getPlayer(playername);
3151 SendShowFormspecMessage(player->peer_id, formspec, formname);
3155 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3160 u32 id = player->addHud(form);
3162 SendHUDAdd(player->peer_id, id, form);
3167 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3171 HudElement* todel = player->removeHud(id);
3178 SendHUDRemove(player->peer_id, id);
3182 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3187 SendHUDChange(player->peer_id, id, stat, data);
3191 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3196 SendHUDSetFlags(player->peer_id, flags, mask);
3197 player->hud_flags &= ~mask;
3198 player->hud_flags |= flags;
3200 PlayerSAO* playersao = player->getPlayerSAO();
3202 if (playersao == NULL)
3205 m_script->player_event(playersao, "hud_changed");
3209 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3214 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3217 player->setHotbarItemcount(hotbar_itemcount);
3218 std::ostringstream os(std::ios::binary);
3219 writeS32(os, hotbar_itemcount);
3220 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3224 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3229 player->setHotbarImage(name);
3230 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3233 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3237 return player->getHotbarImage();
3240 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3245 player->setHotbarSelectedImage(name);
3246 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3249 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3250 v2s32 animation_frames[4], f32 frame_speed)
3255 player->setLocalAnimations(animation_frames, frame_speed);
3256 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3260 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3265 player->eye_offset_first = first;
3266 player->eye_offset_third = third;
3267 SendEyeOffset(player->peer_id, first, third);
3271 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3272 const std::string &type, const std::vector<std::string> ¶ms,
3278 player->setSky(bgcolor, type, params, clouds);
3279 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3283 bool Server::setClouds(RemotePlayer *player, float density,
3284 const video::SColor &color_bright,
3285 const video::SColor &color_ambient,
3293 SendCloudParams(player->peer_id, density,
3294 color_bright, color_ambient, height,
3299 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3305 player->overrideDayNightRatio(do_override, ratio);
3306 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3310 void Server::notifyPlayers(const std::wstring &msg)
3312 SendChatMessage(PEER_ID_INEXISTENT,msg);
3315 void Server::spawnParticle(const std::string &playername, v3f pos,
3316 v3f velocity, v3f acceleration,
3317 float expirationtime, float size, bool
3318 collisiondetection, bool collision_removal,
3319 bool vertical, const std::string &texture,
3320 const struct TileAnimationParams &animation, u8 glow)
3322 // m_env will be NULL if the server is initializing
3326 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3327 if (playername != "") {
3328 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3331 peer_id = player->peer_id;
3332 proto_ver = player->protocol_version;
3335 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3336 expirationtime, size, collisiondetection,
3337 collision_removal, vertical, texture, animation, glow);
3340 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3341 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3342 float minexptime, float maxexptime, float minsize, float maxsize,
3343 bool collisiondetection, bool collision_removal,
3344 ServerActiveObject *attached, bool vertical, const std::string &texture,
3345 const std::string &playername, const struct TileAnimationParams &animation,
3348 // m_env will be NULL if the server is initializing
3352 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3353 if (playername != "") {
3354 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3357 peer_id = player->peer_id;
3358 proto_ver = player->protocol_version;
3361 u16 attached_id = attached ? attached->getId() : 0;
3364 if (attached_id == 0)
3365 id = m_env->addParticleSpawner(spawntime);
3367 id = m_env->addParticleSpawner(spawntime, attached_id);
3369 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3370 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3371 minexptime, maxexptime, minsize, maxsize,
3372 collisiondetection, collision_removal, attached_id, vertical,
3373 texture, id, animation, glow);
3378 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3380 // m_env will be NULL if the server is initializing
3382 throw ServerError("Can't delete particle spawners during initialisation!");
3384 u16 peer_id = PEER_ID_INEXISTENT;
3385 if (playername != "") {
3386 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3389 peer_id = player->peer_id;
3392 m_env->deleteParticleSpawner(id);
3393 SendDeleteParticleSpawner(peer_id, id);
3396 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3398 if(m_detached_inventories.count(name) > 0){
3399 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3400 delete m_detached_inventories[name];
3402 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3404 Inventory *inv = new Inventory(m_itemdef);
3406 m_detached_inventories[name] = inv;
3407 m_detached_inventories_player[name] = player;
3408 //TODO find a better way to do this
3409 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3413 // actions: time-reversed list
3414 // Return value: success/failure
3415 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3416 std::list<std::string> *log)
3418 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3419 ServerMap *map = (ServerMap*)(&m_env->getMap());
3421 // Fail if no actions to handle
3422 if(actions.empty()){
3423 log->push_back("Nothing to do.");
3430 for(std::list<RollbackAction>::const_iterator
3431 i = actions.begin();
3432 i != actions.end(); ++i)
3434 const RollbackAction &action = *i;
3436 bool success = action.applyRevert(map, this, this);
3439 std::ostringstream os;
3440 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3441 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3443 log->push_back(os.str());
3445 std::ostringstream os;
3446 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3447 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3449 log->push_back(os.str());
3453 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3454 <<" failed"<<std::endl;
3456 // Call it done if less than half failed
3457 return num_failed <= num_tried/2;
3460 // IGameDef interface
3462 IItemDefManager *Server::getItemDefManager()
3467 INodeDefManager *Server::getNodeDefManager()
3472 ICraftDefManager *Server::getCraftDefManager()
3477 u16 Server::allocateUnknownNodeId(const std::string &name)
3479 return m_nodedef->allocateDummy(name);
3482 MtEventManager *Server::getEventManager()
3487 IWritableItemDefManager *Server::getWritableItemDefManager()
3492 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3497 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3502 const ModSpec *Server::getModSpec(const std::string &modname) const
3504 std::vector<ModSpec>::const_iterator it;
3505 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3506 const ModSpec &mod = *it;
3507 if (mod.name == modname)
3513 void Server::getModNames(std::vector<std::string> &modlist)
3515 std::vector<ModSpec>::iterator it;
3516 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3517 modlist.push_back(it->name);
3520 std::string Server::getBuiltinLuaPath()
3522 return porting::path_share + DIR_DELIM + "builtin";
3525 std::string Server::getModStoragePath() const
3527 return m_path_world + DIR_DELIM + "mod_storage";
3530 v3f Server::findSpawnPos()
3532 ServerMap &map = m_env->getServerMap();
3534 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3535 return nodeposf * BS;
3538 bool is_good = false;
3540 // Try to find a good place a few times
3541 for(s32 i = 0; i < 4000 && !is_good; i++) {
3543 // We're going to try to throw the player to this position
3544 v2s16 nodepos2d = v2s16(
3545 -range + (myrand() % (range * 2)),
3546 -range + (myrand() % (range * 2)));
3548 // Get spawn level at point
3549 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3550 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3551 // the mapgen to signify an unsuitable spawn position
3552 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3555 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3558 for (s32 i = 0; i < 10; i++) {
3559 v3s16 blockpos = getNodeBlockPos(nodepos);
3560 map.emergeBlock(blockpos, true);
3561 content_t c = map.getNodeNoEx(nodepos).getContent();
3562 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3564 if (air_count >= 2) {
3565 nodeposf = intToFloat(nodepos, BS);
3566 // Don't spawn the player outside map boundaries
3567 if (objectpos_over_limit(nodeposf))
3580 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3582 m_shutdown_timer = delay;
3583 m_shutdown_msg = msg;
3584 m_shutdown_ask_reconnect = reconnect;
3586 if (delay == 0.0f) {
3587 // No delay, shutdown immediately
3588 m_shutdown_requested = true;
3589 // only print to the infostream, a chat message saying
3590 // "Server Shutting Down" is sent when the server destructs.
3591 infostream << "*** Immediate Server shutdown requested." << std::endl;
3592 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3593 // Negative delay, cancel shutdown if requested
3594 m_shutdown_timer = 0.0f;
3595 m_shutdown_msg = "";
3596 m_shutdown_ask_reconnect = false;
3597 m_shutdown_requested = false;
3598 std::wstringstream ws;
3600 ws << L"*** Server shutdown canceled.";
3602 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3603 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3604 } else if (delay > 0.0f) {
3605 // Positive delay, tell the clients when the server will shut down
3606 std::wstringstream ws;
3608 ws << L"*** Server shutting down in "
3609 << duration_to_string(myround(m_shutdown_timer)).c_str()
3612 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3613 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3617 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3620 Try to get an existing player
3622 RemotePlayer *player = m_env->getPlayer(name);
3624 // If player is already connected, cancel
3625 if (player != NULL && player->peer_id != 0) {
3626 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3631 If player with the wanted peer_id already exists, cancel.
3633 if (m_env->getPlayer(peer_id) != NULL) {
3634 infostream<<"emergePlayer(): Player with wrong name but same"
3635 " peer_id already exists"<<std::endl;
3640 player = new RemotePlayer(name, idef());
3643 bool newplayer = false;
3646 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3648 // Complete init with server parts
3649 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3650 player->protocol_version = proto_version;
3654 m_script->on_newplayer(playersao);
3660 bool Server::registerModStorage(ModMetadata *storage)
3662 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3663 errorstream << "Unable to register same mod storage twice. Storage name: "
3664 << storage->getModName() << std::endl;
3668 m_mod_storages[storage->getModName()] = storage;
3672 void Server::unregisterModStorage(const std::string &name)
3674 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3675 if (it != m_mod_storages.end()) {
3676 // Save unconditionaly on unregistration
3677 it->second->save(getModStoragePath());
3678 m_mod_storages.erase(name);
3682 void dedicated_server_loop(Server &server, bool &kill)
3684 DSTACK(FUNCTION_NAME);
3686 verbosestream<<"dedicated_server_loop()"<<std::endl;
3688 IntervalLimiter m_profiler_interval;
3690 static const float steplen = g_settings->getFloat("dedicated_server_step");
3691 static const float profiler_print_interval =
3692 g_settings->getFloat("profiler_print_interval");
3695 // This is kind of a hack but can be done like this
3696 // because server.step() is very light
3698 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3699 sleep_ms((int)(steplen*1000.0));
3701 server.step(steplen);
3703 if (server.getShutdownRequested() || kill)
3709 if (profiler_print_interval != 0) {
3710 if(m_profiler_interval.step(steplen, profiler_print_interval))
3712 infostream<<"Profiler:"<<std::endl;
3713 g_profiler->print(infostream);
3714 g_profiler->clear();
3719 infostream << "Dedicated server quitting" << std::endl;
3721 if (g_settings->getBool("server_announce"))
3722 ServerList::sendAnnounce(ServerList::AA_DELETE,
3723 server.m_bind_addr.getPort());