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_game.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"
56 #include "util/mathconstants.h"
58 #include "util/serialize.h"
59 #include "util/thread.h"
60 #include "defaultsettings.h"
61 #include "util/base64.h"
62 #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,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_async_fatal_error(""),
166 m_enable_rollback_recording(false),
169 m_itemdef(createItemDefManager()),
170 m_nodedef(createNodeDefManager()),
171 m_craftdef(createCraftDefManager()),
172 m_event(new EventManager()),
174 m_time_of_day_send_timer(0),
177 m_shutdown_requested(false),
178 m_shutdown_ask_reconnect(false),
180 m_ignore_map_edit_events(false),
181 m_ignore_map_edit_events_peer_id(0),
185 m_liquid_transform_timer = 0.0;
186 m_liquid_transform_every = 1.0;
187 m_masterserver_timer = 0.0;
188 m_emergethread_trigger_timer = 0.0;
189 m_savemap_timer = 0.0;
192 m_lag = g_settings->getFloat("dedicated_server_step");
195 throw ServerError("Supplied empty world path");
197 if(!gamespec.isValid())
198 throw ServerError("Supplied invalid gamespec");
200 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
201 if(m_simple_singleplayer_mode)
202 infostream<<" in simple singleplayer mode"<<std::endl;
204 infostream<<std::endl;
205 infostream<<"- world: "<<m_path_world<<std::endl;
206 infostream<<"- game: "<<m_gamespec.path<<std::endl;
208 // Create world if it doesn't exist
209 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
210 throw ServerError("Failed to initialize world");
212 // Create server thread
213 m_thread = new ServerThread(this);
215 // Create emerge manager
216 m_emerge = new EmergeManager(this);
218 // Create ban manager
219 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
220 m_banmanager = new BanManager(ban_path);
222 ModConfiguration modconf(m_path_world);
223 m_mods = modconf.getMods();
224 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
225 // complain about mods with unsatisfied dependencies
226 if(!modconf.isConsistent()) {
227 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
228 it != unsatisfied_mods.end(); ++it) {
230 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
231 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
232 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
233 errorstream << " \"" << *dep_it << "\"";
234 errorstream << std::endl;
238 Settings worldmt_settings;
239 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
240 worldmt_settings.readConfigFile(worldmt.c_str());
241 std::vector<std::string> names = worldmt_settings.getNames();
242 std::set<std::string> load_mod_names;
243 for(std::vector<std::string>::iterator it = names.begin();
244 it != names.end(); ++it) {
245 std::string name = *it;
246 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
247 load_mod_names.insert(name.substr(9));
249 // complain about mods declared to be loaded, but not found
250 for(std::vector<ModSpec>::iterator it = m_mods.begin();
251 it != m_mods.end(); ++it)
252 load_mod_names.erase((*it).name);
253 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
254 it != unsatisfied_mods.end(); ++it)
255 load_mod_names.erase((*it).name);
256 if(!load_mod_names.empty()) {
257 errorstream << "The following mods could not be found:";
258 for(std::set<std::string>::iterator it = load_mod_names.begin();
259 it != load_mod_names.end(); ++it)
260 errorstream << " \"" << (*it) << "\"";
261 errorstream << std::endl;
265 MutexAutoLock envlock(m_env_mutex);
267 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
268 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
270 // Initialize scripting
271 infostream<<"Server: Initializing Lua"<<std::endl;
273 m_script = new GameScripting(this);
275 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
277 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
280 infostream << "Server: Loading mods: ";
281 for(std::vector<ModSpec>::iterator i = m_mods.begin();
282 i != m_mods.end(); ++i) {
283 const ModSpec &mod = *i;
284 infostream << mod.name << " ";
286 infostream << std::endl;
287 // Load and run "mod" scripts
288 for (std::vector<ModSpec>::iterator it = m_mods.begin();
289 it != m_mods.end(); ++it) {
290 const ModSpec &mod = *it;
291 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
292 throw ModError("Error loading mod \"" + mod.name +
293 "\": Mod name does not follow naming conventions: "
294 "Only chararacters [a-z0-9_] are allowed.");
296 std::string script_path = mod.path + DIR_DELIM + "init.lua";
297 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
298 << script_path << "\"]" << std::endl;
299 m_script->loadMod(script_path, mod.name);
302 // Read Textures and calculate sha1 sums
305 // Apply item aliases in the node definition manager
306 m_nodedef->updateAliases(m_itemdef);
308 // Apply texture overrides from texturepack/override.txt
309 std::string texture_path = g_settings->get("texture_path");
310 if (texture_path != "" && fs::IsDir(texture_path))
311 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
313 m_nodedef->setNodeRegistrationStatus(true);
315 // Perform pending node name resolutions
316 m_nodedef->runNodeResolveCallbacks();
318 // unmap node names for connected nodeboxes
319 m_nodedef->mapNodeboxConnections();
321 // init the recipe hashes to speed up crafting
322 m_craftdef->initHashes(this);
324 // Initialize Environment
325 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
327 m_clients.setEnv(m_env);
329 if (!servermap->settings_mgr.makeMapgenParams())
330 FATAL_ERROR("Couldn't create any mapgen type");
332 // Initialize mapgens
333 m_emerge->initMapgens(servermap->getMapgenParams());
335 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
336 if (m_enable_rollback_recording) {
337 // Create rollback manager
338 m_rollback = new RollbackManager(m_path_world, this);
341 // Give environment reference to scripting api
342 m_script->initializeEnvironment(m_env);
344 // Register us to receive map edit events
345 servermap->addEventReceiver(this);
347 // If file exists, load environment metadata
348 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
349 infostream << "Server: Loading environment metadata" << std::endl;
352 m_env->loadDefaultMeta();
355 // Add some test ActiveBlockModifiers to environment
356 add_legacy_abms(m_env, m_nodedef);
358 m_liquid_transform_every = g_settings->getFloat("liquid_update");
359 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
364 infostream<<"Server destructing"<<std::endl;
366 // Send shutdown message
367 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
370 MutexAutoLock envlock(m_env_mutex);
372 // Execute script shutdown hooks
373 m_script->on_shutdown();
375 infostream << "Server: Saving players" << std::endl;
376 m_env->saveLoadedPlayers();
378 infostream << "Server: Kicking players" << std::endl;
379 std::string kick_msg;
380 bool reconnect = false;
381 if (getShutdownRequested()) {
382 reconnect = m_shutdown_ask_reconnect;
383 kick_msg = m_shutdown_msg;
385 if (kick_msg == "") {
386 kick_msg = g_settings->get("kick_msg_shutdown");
388 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
389 kick_msg, reconnect);
391 infostream << "Server: Saving environment metadata" << std::endl;
399 // stop all emerge threads before deleting players that may have
400 // requested blocks to be emerged
401 m_emerge->stopThreads();
403 // Delete things in the reverse order of creation
413 // Deinitialize scripting
414 infostream<<"Server: Deinitializing scripting"<<std::endl;
417 // Delete detached inventories
418 for (std::map<std::string, Inventory*>::iterator
419 i = m_detached_inventories.begin();
420 i != m_detached_inventories.end(); ++i) {
425 void Server::start(Address bind_addr)
427 DSTACK(FUNCTION_NAME);
429 m_bind_addr = bind_addr;
431 infostream<<"Starting server on "
432 << bind_addr.serializeString() <<"..."<<std::endl;
434 // Stop thread if already running
437 // Initialize connection
438 m_con.SetTimeoutMs(30);
439 m_con.Serve(bind_addr);
444 // ASCII art for the win!
446 <<" .__ __ __ "<<std::endl
447 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
448 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
449 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
450 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
451 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
452 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
453 actionstream<<"Server for gameid=\""<<m_gamespec.id
454 <<"\" listening on "<<bind_addr.serializeString()<<":"
455 <<bind_addr.getPort() << "."<<std::endl;
460 DSTACK(FUNCTION_NAME);
462 infostream<<"Server: Stopping and waiting threads"<<std::endl;
464 // Stop threads (set run=false first so both start stopping)
466 //m_emergethread.setRun(false);
468 //m_emergethread.stop();
470 infostream<<"Server: Threads stopped"<<std::endl;
473 void Server::step(float dtime)
475 DSTACK(FUNCTION_NAME);
480 MutexAutoLock lock(m_step_dtime_mutex);
481 m_step_dtime += dtime;
483 // Throw if fatal error occurred in thread
484 std::string async_err = m_async_fatal_error.get();
485 if (!async_err.empty()) {
486 if (!m_simple_singleplayer_mode) {
487 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
488 g_settings->get("kick_msg_crash"),
489 g_settings->getBool("ask_reconnect_on_crash"));
491 throw ServerError("AsyncErr: " + async_err);
495 void Server::AsyncRunStep(bool initial_step)
497 DSTACK(FUNCTION_NAME);
499 g_profiler->add("Server::AsyncRunStep (num)", 1);
503 MutexAutoLock lock1(m_step_dtime_mutex);
504 dtime = m_step_dtime;
508 // Send blocks to clients
512 if((dtime < 0.001) && (initial_step == false))
515 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
517 //infostream<<"Server steps "<<dtime<<std::endl;
518 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
521 MutexAutoLock lock1(m_step_dtime_mutex);
522 m_step_dtime -= dtime;
529 m_uptime.set(m_uptime.get() + dtime);
535 Update time of day and overall game time
537 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
540 Send to clients at constant intervals
543 m_time_of_day_send_timer -= dtime;
544 if(m_time_of_day_send_timer < 0.0) {
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
552 MutexAutoLock lock(m_env_mutex);
553 // Figure out and report maximum lag to environment
554 float max_lag = m_env->getMaxLagEstimate();
555 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
557 if(dtime > 0.1 && dtime > max_lag * 2.0)
558 infostream<<"Server: Maximum lag peaked to "<<dtime
562 m_env->reportMaxLagEstimate(max_lag);
564 ScopeProfiler sp(g_profiler, "SEnv step");
565 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
569 static const float map_timer_and_unload_dtime = 2.92;
570 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
572 MutexAutoLock lock(m_env_mutex);
573 // Run Map's timers and unload unused data
574 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
575 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
576 g_settings->getFloat("server_unload_unused_data_timeout"),
581 Listen to the admin chat, if available
584 if (!m_admin_chat->command_queue.empty()) {
585 MutexAutoLock lock(m_env_mutex);
586 while (!m_admin_chat->command_queue.empty()) {
587 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
588 handleChatInterfaceEvent(evt);
592 m_admin_chat->outgoing_queue.push_back(
593 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
600 /* Transform liquids */
601 m_liquid_transform_timer += dtime;
602 if(m_liquid_transform_timer >= m_liquid_transform_every)
604 m_liquid_transform_timer -= m_liquid_transform_every;
606 MutexAutoLock lock(m_env_mutex);
608 ScopeProfiler sp(g_profiler, "Server: liquid transform");
610 std::map<v3s16, MapBlock*> modified_blocks;
611 m_env->getMap().transformLiquids(modified_blocks);
616 core::map<v3s16, MapBlock*> lighting_modified_blocks;
617 ServerMap &map = ((ServerMap&)m_env->getMap());
618 map.updateLighting(modified_blocks, lighting_modified_blocks);
620 // Add blocks modified by lighting to modified_blocks
621 for(core::map<v3s16, MapBlock*>::Iterator
622 i = lighting_modified_blocks.getIterator();
623 i.atEnd() == false; i++)
625 MapBlock *block = i.getNode()->getValue();
626 modified_blocks.insert(block->getPos(), block);
630 Set the modified blocks unsent for all the clients
632 if(!modified_blocks.empty())
634 SetBlocksNotSent(modified_blocks);
637 m_clients.step(dtime);
639 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
641 // send masterserver announce
643 float &counter = m_masterserver_timer;
644 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
645 g_settings->getBool("server_announce"))
647 ServerList::sendAnnounce(counter ? "update" : "start",
648 m_bind_addr.getPort(),
649 m_clients.getPlayerNames(),
651 m_env->getGameTime(),
654 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
663 Check added and deleted active objects
666 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
667 MutexAutoLock envlock(m_env_mutex);
670 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
671 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
673 // Radius inside which objects are active
674 static const s16 radius =
675 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
677 // Radius inside which players are active
678 static const bool is_transfer_limited =
679 g_settings->exists("unlimited_player_transfer_distance") &&
680 !g_settings->getBool("unlimited_player_transfer_distance");
681 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
682 s16 player_radius = player_transfer_dist;
683 if (player_radius == 0 && is_transfer_limited)
684 player_radius = radius;
686 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
687 i != clients.end(); ++i) {
688 RemoteClient *client = i->second;
690 // If definitions and textures have not been sent, don't
691 // send objects either
692 if (client->getState() < CS_DefinitionsSent)
695 RemotePlayer *player = m_env->getPlayer(client->peer_id);
696 if (player == NULL) {
697 // This can happen if the client timeouts somehow
698 /*warningstream<<FUNCTION_NAME<<": Client "
700 <<" has no associated player"<<std::endl;*/
704 PlayerSAO *playersao = player->getPlayerSAO();
705 if (playersao == NULL)
708 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
709 if (my_radius <= 0) my_radius = radius;
710 //infostream << "Server: Active Radius " << my_radius << std::endl;
712 std::queue<u16> removed_objects;
713 std::queue<u16> added_objects;
714 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
715 client->m_known_objects, removed_objects);
716 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
717 client->m_known_objects, added_objects);
719 // Ignore if nothing happened
720 if (removed_objects.empty() && added_objects.empty()) {
724 std::string data_buffer;
728 // Handle removed objects
729 writeU16((u8*)buf, removed_objects.size());
730 data_buffer.append(buf, 2);
731 while (!removed_objects.empty()) {
733 u16 id = removed_objects.front();
734 ServerActiveObject* obj = m_env->getActiveObject(id);
736 // Add to data buffer for sending
737 writeU16((u8*)buf, id);
738 data_buffer.append(buf, 2);
740 // Remove from known objects
741 client->m_known_objects.erase(id);
743 if(obj && obj->m_known_by_count > 0)
744 obj->m_known_by_count--;
745 removed_objects.pop();
748 // Handle added objects
749 writeU16((u8*)buf, added_objects.size());
750 data_buffer.append(buf, 2);
751 while (!added_objects.empty()) {
753 u16 id = added_objects.front();
754 ServerActiveObject* obj = m_env->getActiveObject(id);
757 u8 type = ACTIVEOBJECT_TYPE_INVALID;
759 warningstream<<FUNCTION_NAME
760 <<": NULL object"<<std::endl;
762 type = obj->getSendType();
764 // Add to data buffer for sending
765 writeU16((u8*)buf, id);
766 data_buffer.append(buf, 2);
767 writeU8((u8*)buf, type);
768 data_buffer.append(buf, 1);
771 data_buffer.append(serializeLongString(
772 obj->getClientInitializationData(client->net_proto_version)));
774 data_buffer.append(serializeLongString(""));
776 // Add to known objects
777 client->m_known_objects.insert(id);
780 obj->m_known_by_count++;
785 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
786 verbosestream << "Server: Sent object remove/add: "
787 << removed_objects.size() << " removed, "
788 << added_objects.size() << " added, "
789 << "packet size is " << pktSize << std::endl;
798 MutexAutoLock envlock(m_env_mutex);
799 ScopeProfiler sp(g_profiler, "Server: sending object messages");
802 // Value = data sent by object
803 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
805 // Get active object messages from environment
807 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
811 std::vector<ActiveObjectMessage>* message_list = NULL;
812 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
813 n = buffered_messages.find(aom.id);
814 if (n == buffered_messages.end()) {
815 message_list = new std::vector<ActiveObjectMessage>;
816 buffered_messages[aom.id] = message_list;
819 message_list = n->second;
821 message_list->push_back(aom);
825 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
826 // Route data to every client
827 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
828 i != clients.end(); ++i) {
829 RemoteClient *client = i->second;
830 std::string reliable_data;
831 std::string unreliable_data;
832 // Go through all objects in message buffer
833 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
834 j = buffered_messages.begin();
835 j != buffered_messages.end(); ++j) {
836 // If object is not known by client, skip it
838 if (client->m_known_objects.find(id) == client->m_known_objects.end())
841 // Get message list of object
842 std::vector<ActiveObjectMessage>* list = j->second;
843 // Go through every message
844 for (std::vector<ActiveObjectMessage>::iterator
845 k = list->begin(); k != list->end(); ++k) {
846 // Compose the full new data with header
847 ActiveObjectMessage aom = *k;
848 std::string new_data;
851 writeU16((u8*)&buf[0], aom.id);
852 new_data.append(buf, 2);
854 new_data += serializeString(aom.datastring);
855 // Add data to buffer
857 reliable_data += new_data;
859 unreliable_data += new_data;
863 reliable_data and unreliable_data are now ready.
866 if(reliable_data.size() > 0) {
867 SendActiveObjectMessages(client->peer_id, reliable_data);
870 if(unreliable_data.size() > 0) {
871 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
876 // Clear buffered_messages
877 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
878 i = buffered_messages.begin();
879 i != buffered_messages.end(); ++i) {
885 Send queued-for-sending map edit events.
888 // We will be accessing the environment
889 MutexAutoLock lock(m_env_mutex);
891 // Don't send too many at a time
894 // Single change sending is disabled if queue size is not small
895 bool disable_single_change_sending = false;
896 if(m_unsent_map_edit_queue.size() >= 4)
897 disable_single_change_sending = true;
899 int event_count = m_unsent_map_edit_queue.size();
901 // We'll log the amount of each
904 while(m_unsent_map_edit_queue.size() != 0)
906 MapEditEvent* event = m_unsent_map_edit_queue.front();
907 m_unsent_map_edit_queue.pop();
909 // Players far away from the change are stored here.
910 // Instead of sending the changes, MapBlocks are set not sent
912 std::vector<u16> far_players;
914 switch (event->type) {
917 prof.add("MEET_ADDNODE", 1);
918 sendAddNode(event->p, event->n, event->already_known_by_peer,
919 &far_players, disable_single_change_sending ? 5 : 30,
920 event->type == MEET_ADDNODE);
922 case MEET_REMOVENODE:
923 prof.add("MEET_REMOVENODE", 1);
924 sendRemoveNode(event->p, event->already_known_by_peer,
925 &far_players, disable_single_change_sending ? 5 : 30);
927 case MEET_BLOCK_NODE_METADATA_CHANGED:
928 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
929 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
930 setBlockNotSent(event->p);
933 infostream << "Server: MEET_OTHER" << std::endl;
934 prof.add("MEET_OTHER", 1);
935 for(std::set<v3s16>::iterator
936 i = event->modified_blocks.begin();
937 i != event->modified_blocks.end(); ++i) {
942 prof.add("unknown", 1);
943 warningstream << "Server: Unknown MapEditEvent "
944 << ((u32)event->type) << std::endl;
949 Set blocks not sent to far players
951 if(!far_players.empty()) {
952 // Convert list format to that wanted by SetBlocksNotSent
953 std::map<v3s16, MapBlock*> modified_blocks2;
954 for(std::set<v3s16>::iterator
955 i = event->modified_blocks.begin();
956 i != event->modified_blocks.end(); ++i) {
957 modified_blocks2[*i] =
958 m_env->getMap().getBlockNoCreateNoEx(*i);
961 // Set blocks not sent
962 for(std::vector<u16>::iterator
963 i = far_players.begin();
964 i != far_players.end(); ++i) {
965 if(RemoteClient *client = getClient(*i))
966 client->SetBlocksNotSent(modified_blocks2);
972 /*// Don't send too many at a time
974 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
978 if(event_count >= 5){
979 infostream<<"Server: MapEditEvents:"<<std::endl;
980 prof.print(infostream);
981 } else if(event_count != 0){
982 verbosestream<<"Server: MapEditEvents:"<<std::endl;
983 prof.print(verbosestream);
989 Trigger emergethread (it somehow gets to a non-triggered but
990 bysy state sometimes)
993 float &counter = m_emergethread_trigger_timer;
995 if (counter >= 2.0) {
998 m_emerge->startThreads();
1002 // Save map, players and auth stuff
1004 float &counter = m_savemap_timer;
1006 static const float save_interval =
1007 g_settings->getFloat("server_map_save_interval");
1008 if (counter >= save_interval) {
1010 MutexAutoLock lock(m_env_mutex);
1012 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1015 if (m_banmanager->isModified()) {
1016 m_banmanager->save();
1019 // Save changed parts of map
1020 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1023 m_env->saveLoadedPlayers();
1025 // Save environment metadata
1031 void Server::Receive()
1033 DSTACK(FUNCTION_NAME);
1034 SharedBuffer<u8> data;
1038 m_con.Receive(&pkt);
1039 peer_id = pkt.getPeerId();
1042 catch(con::InvalidIncomingDataException &e) {
1043 infostream<<"Server::Receive(): "
1044 "InvalidIncomingDataException: what()="
1045 <<e.what()<<std::endl;
1047 catch(SerializationError &e) {
1048 infostream<<"Server::Receive(): "
1049 "SerializationError: what()="
1050 <<e.what()<<std::endl;
1052 catch(ClientStateError &e) {
1053 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1054 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1055 L"Try reconnecting or updating your client");
1057 catch(con::PeerNotFoundException &e) {
1062 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1064 std::string playername = "";
1065 PlayerSAO *playersao = NULL;
1068 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1069 if (client != NULL) {
1070 playername = client->getName();
1071 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1073 } catch (std::exception &e) {
1079 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1081 // If failed, cancel
1082 if ((playersao == NULL) || (player == NULL)) {
1083 if (player && player->peer_id != 0) {
1084 actionstream << "Server: Failed to emerge player \"" << playername
1085 << "\" (player allocated to an another client)" << std::endl;
1086 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1087 L"name. If your client closed unexpectedly, try again in "
1090 errorstream << "Server: " << playername << ": Failed to emerge player"
1092 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1098 Send complete position information
1100 SendMovePlayer(peer_id);
1103 SendPlayerPrivileges(peer_id);
1105 // Send inventory formspec
1106 SendPlayerInventoryFormspec(peer_id);
1109 SendInventory(playersao);
1112 SendPlayerHPOrDie(playersao);
1115 SendPlayerBreath(playersao);
1117 // Show death screen if necessary
1118 if (playersao->isDead())
1119 SendDeathscreen(peer_id, false, v3f(0,0,0));
1121 // Note things in chat if not in simple singleplayer mode
1122 if(!m_simple_singleplayer_mode) {
1123 // Send information about server to player in chat
1124 SendChatMessage(peer_id, getStatusString());
1126 Address addr = getPeerAddress(player->peer_id);
1127 std::string ip_str = addr.serializeString();
1128 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1133 const std::vector<std::string> &names = m_clients.getPlayerNames();
1135 actionstream << player->getName() << " joins game. List of players: ";
1137 for (std::vector<std::string>::const_iterator i = names.begin();
1138 i != names.end(); ++i) {
1139 actionstream << *i << " ";
1142 actionstream << player->getName() <<std::endl;
1147 inline void Server::handleCommand(NetworkPacket* pkt)
1149 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1150 (this->*opHandle.handler)(pkt);
1153 void Server::ProcessData(NetworkPacket *pkt)
1155 DSTACK(FUNCTION_NAME);
1156 // Environment is locked first.
1157 MutexAutoLock envlock(m_env_mutex);
1159 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1160 u32 peer_id = pkt->getPeerId();
1163 Address address = getPeerAddress(peer_id);
1164 std::string addr_s = address.serializeString();
1166 if(m_banmanager->isIpBanned(addr_s)) {
1167 std::string ban_name = m_banmanager->getBanName(addr_s);
1168 infostream << "Server: A banned client tried to connect from "
1169 << addr_s << "; banned name was "
1170 << ban_name << std::endl;
1171 // This actually doesn't seem to transfer to the client
1172 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1173 + utf8_to_wide(ban_name));
1177 catch(con::PeerNotFoundException &e) {
1179 * no peer for this packet found
1180 * most common reason is peer timeout, e.g. peer didn't
1181 * respond for some time, your server was overloaded or
1184 infostream << "Server::ProcessData(): Canceling: peer "
1185 << peer_id << " not found" << std::endl;
1190 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1192 // Command must be handled into ToServerCommandHandler
1193 if (command >= TOSERVER_NUM_MSG_TYPES) {
1194 infostream << "Server: Ignoring unknown command "
1195 << command << std::endl;
1199 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1204 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1206 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1207 errorstream << "Server::ProcessData(): Cancelling: Peer"
1208 " serialization format invalid or not initialized."
1209 " Skipping incoming command=" << command << std::endl;
1213 /* Handle commands related to client startup */
1214 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1219 if (m_clients.getClientState(peer_id) < CS_Active) {
1220 if (command == TOSERVER_PLAYERPOS) return;
1222 errorstream << "Got packet command: " << command << " for peer id "
1223 << peer_id << " but client isn't active yet. Dropping packet "
1229 } catch (SendFailedException &e) {
1230 errorstream << "Server::ProcessData(): SendFailedException: "
1231 << "what=" << e.what()
1233 } catch (PacketError &e) {
1234 actionstream << "Server::ProcessData(): PacketError: "
1235 << "what=" << e.what()
1240 void Server::setTimeOfDay(u32 time)
1242 m_env->setTimeOfDay(time);
1243 m_time_of_day_send_timer = 0;
1246 void Server::onMapEditEvent(MapEditEvent *event)
1248 if(m_ignore_map_edit_events)
1250 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1252 MapEditEvent *e = event->clone();
1253 m_unsent_map_edit_queue.push(e);
1256 Inventory* Server::getInventory(const InventoryLocation &loc)
1259 case InventoryLocation::UNDEFINED:
1260 case InventoryLocation::CURRENT_PLAYER:
1262 case InventoryLocation::PLAYER:
1264 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1267 PlayerSAO *playersao = player->getPlayerSAO();
1270 return playersao->getInventory();
1273 case InventoryLocation::NODEMETA:
1275 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1278 return meta->getInventory();
1281 case InventoryLocation::DETACHED:
1283 if(m_detached_inventories.count(loc.name) == 0)
1285 return m_detached_inventories[loc.name];
1289 sanity_check(false); // abort
1294 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1297 case InventoryLocation::UNDEFINED:
1299 case InventoryLocation::PLAYER:
1304 RemotePlayer *player =
1305 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1310 PlayerSAO *playersao = player->getPlayerSAO();
1314 SendInventory(playersao);
1317 case InventoryLocation::NODEMETA:
1319 v3s16 blockpos = getNodeBlockPos(loc.p);
1321 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1323 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1325 setBlockNotSent(blockpos);
1328 case InventoryLocation::DETACHED:
1330 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1334 sanity_check(false); // abort
1339 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1341 std::vector<u16> clients = m_clients.getClientIDs();
1343 // Set the modified blocks unsent for all the clients
1344 for (std::vector<u16>::iterator i = clients.begin();
1345 i != clients.end(); ++i) {
1346 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1347 client->SetBlocksNotSent(block);
1352 void Server::peerAdded(con::Peer *peer)
1354 DSTACK(FUNCTION_NAME);
1355 verbosestream<<"Server::peerAdded(): peer->id="
1356 <<peer->id<<std::endl;
1359 c.type = con::PEER_ADDED;
1360 c.peer_id = peer->id;
1362 m_peer_change_queue.push(c);
1365 void Server::deletingPeer(con::Peer *peer, bool timeout)
1367 DSTACK(FUNCTION_NAME);
1368 verbosestream<<"Server::deletingPeer(): peer->id="
1369 <<peer->id<<", timeout="<<timeout<<std::endl;
1371 m_clients.event(peer->id, CSE_Disconnect);
1373 c.type = con::PEER_REMOVED;
1374 c.peer_id = peer->id;
1375 c.timeout = timeout;
1376 m_peer_change_queue.push(c);
1379 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1381 *retval = m_con.getPeerStat(peer_id,type);
1382 if (*retval == -1) return false;
1386 bool Server::getClientInfo(
1395 std::string* vers_string
1398 *state = m_clients.getClientState(peer_id);
1400 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1402 if (client == NULL) {
1407 *uptime = client->uptime();
1408 *ser_vers = client->serialization_version;
1409 *prot_vers = client->net_proto_version;
1411 *major = client->getMajor();
1412 *minor = client->getMinor();
1413 *patch = client->getPatch();
1414 *vers_string = client->getPatch();
1421 void Server::handlePeerChanges()
1423 while(m_peer_change_queue.size() > 0)
1425 con::PeerChange c = m_peer_change_queue.front();
1426 m_peer_change_queue.pop();
1428 verbosestream<<"Server: Handling peer change: "
1429 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1434 case con::PEER_ADDED:
1435 m_clients.CreateClient(c.peer_id);
1438 case con::PEER_REMOVED:
1439 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1443 FATAL_ERROR("Invalid peer change event received!");
1449 void Server::printToConsoleOnly(const std::string &text)
1452 m_admin_chat->outgoing_queue.push_back(
1453 new ChatEventChat("", utf8_to_wide(text)));
1455 std::cout << text << std::endl;
1459 void Server::Send(NetworkPacket* pkt)
1461 m_clients.send(pkt->getPeerId(),
1462 clientCommandFactoryTable[pkt->getCommand()].channel,
1464 clientCommandFactoryTable[pkt->getCommand()].reliable);
1467 void Server::SendMovement(u16 peer_id)
1469 DSTACK(FUNCTION_NAME);
1470 std::ostringstream os(std::ios_base::binary);
1472 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1474 pkt << g_settings->getFloat("movement_acceleration_default");
1475 pkt << g_settings->getFloat("movement_acceleration_air");
1476 pkt << g_settings->getFloat("movement_acceleration_fast");
1477 pkt << g_settings->getFloat("movement_speed_walk");
1478 pkt << g_settings->getFloat("movement_speed_crouch");
1479 pkt << g_settings->getFloat("movement_speed_fast");
1480 pkt << g_settings->getFloat("movement_speed_climb");
1481 pkt << g_settings->getFloat("movement_speed_jump");
1482 pkt << g_settings->getFloat("movement_liquid_fluidity");
1483 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1484 pkt << g_settings->getFloat("movement_liquid_sink");
1485 pkt << g_settings->getFloat("movement_gravity");
1490 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1492 if (!g_settings->getBool("enable_damage"))
1495 u16 peer_id = playersao->getPeerID();
1496 bool is_alive = playersao->getHP() > 0;
1499 SendPlayerHP(peer_id);
1504 void Server::SendHP(u16 peer_id, u8 hp)
1506 DSTACK(FUNCTION_NAME);
1508 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1513 void Server::SendBreath(u16 peer_id, u16 breath)
1515 DSTACK(FUNCTION_NAME);
1517 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1518 pkt << (u16) breath;
1522 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1523 const std::string &custom_reason, bool reconnect)
1525 assert(reason < SERVER_ACCESSDENIED_MAX);
1527 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1529 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1530 pkt << custom_reason;
1531 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1532 reason == SERVER_ACCESSDENIED_CRASH)
1533 pkt << custom_reason << (u8)reconnect;
1537 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1539 DSTACK(FUNCTION_NAME);
1541 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1546 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1547 v3f camera_point_target)
1549 DSTACK(FUNCTION_NAME);
1551 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1552 pkt << set_camera_point_target << camera_point_target;
1556 void Server::SendItemDef(u16 peer_id,
1557 IItemDefManager *itemdef, u16 protocol_version)
1559 DSTACK(FUNCTION_NAME);
1561 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1565 u32 length of the next item
1566 zlib-compressed serialized ItemDefManager
1568 std::ostringstream tmp_os(std::ios::binary);
1569 itemdef->serialize(tmp_os, protocol_version);
1570 std::ostringstream tmp_os2(std::ios::binary);
1571 compressZlib(tmp_os.str(), tmp_os2);
1572 pkt.putLongString(tmp_os2.str());
1575 verbosestream << "Server: Sending item definitions to id(" << peer_id
1576 << "): size=" << pkt.getSize() << std::endl;
1581 void Server::SendNodeDef(u16 peer_id,
1582 INodeDefManager *nodedef, u16 protocol_version)
1584 DSTACK(FUNCTION_NAME);
1586 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1590 u32 length of the next item
1591 zlib-compressed serialized NodeDefManager
1593 std::ostringstream tmp_os(std::ios::binary);
1594 nodedef->serialize(tmp_os, protocol_version);
1595 std::ostringstream tmp_os2(std::ios::binary);
1596 compressZlib(tmp_os.str(), tmp_os2);
1598 pkt.putLongString(tmp_os2.str());
1601 verbosestream << "Server: Sending node definitions to id(" << peer_id
1602 << "): size=" << pkt.getSize() << std::endl;
1608 Non-static send methods
1611 void Server::SendInventory(PlayerSAO* playerSAO)
1613 DSTACK(FUNCTION_NAME);
1615 UpdateCrafting(playerSAO->getPlayer());
1621 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1623 std::ostringstream os;
1624 playerSAO->getInventory()->serialize(os);
1626 std::string s = os.str();
1628 pkt.putRawString(s.c_str(), s.size());
1632 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1634 DSTACK(FUNCTION_NAME);
1636 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1639 if (peer_id != PEER_ID_INEXISTENT) {
1643 m_clients.sendToAll(0, &pkt, true);
1647 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1648 const std::string &formname)
1650 DSTACK(FUNCTION_NAME);
1652 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1653 if (formspec == "" ){
1654 //the client should close the formspec
1655 pkt.putLongString("");
1657 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1664 // Spawns a particle on peer with peer_id
1665 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1666 float expirationtime, float size, bool collisiondetection,
1667 bool collision_removal,
1668 bool vertical, const std::string &texture)
1670 DSTACK(FUNCTION_NAME);
1672 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1674 pkt << pos << velocity << acceleration << expirationtime
1675 << size << collisiondetection;
1676 pkt.putLongString(texture);
1678 pkt << collision_removal;
1680 if (peer_id != PEER_ID_INEXISTENT) {
1684 m_clients.sendToAll(0, &pkt, true);
1688 // Adds a ParticleSpawner on peer with peer_id
1689 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1690 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1691 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1692 u16 attached_id, bool vertical, const std::string &texture, u32 id)
1694 DSTACK(FUNCTION_NAME);
1696 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1698 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1699 << minacc << maxacc << minexptime << maxexptime << minsize
1700 << maxsize << collisiondetection;
1702 pkt.putLongString(texture);
1704 pkt << id << vertical;
1705 pkt << collision_removal;
1708 if (peer_id != PEER_ID_INEXISTENT) {
1712 m_clients.sendToAll(0, &pkt, true);
1716 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1718 DSTACK(FUNCTION_NAME);
1720 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1722 // Ugly error in this packet
1725 if (peer_id != PEER_ID_INEXISTENT) {
1729 m_clients.sendToAll(0, &pkt, true);
1734 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1736 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1738 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1739 << form->text << form->number << form->item << form->dir
1740 << form->align << form->offset << form->world_pos << form->size;
1745 void Server::SendHUDRemove(u16 peer_id, u32 id)
1747 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1752 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1754 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1755 pkt << id << (u8) stat;
1759 case HUD_STAT_SCALE:
1760 case HUD_STAT_ALIGN:
1761 case HUD_STAT_OFFSET:
1762 pkt << *(v2f *) value;
1766 pkt << *(std::string *) value;
1768 case HUD_STAT_WORLD_POS:
1769 pkt << *(v3f *) value;
1772 pkt << *(v2s32 *) value;
1774 case HUD_STAT_NUMBER:
1778 pkt << *(u32 *) value;
1785 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1787 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1789 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1791 pkt << flags << mask;
1796 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1798 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1799 pkt << param << value;
1803 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1804 const std::string &type, const std::vector<std::string> ¶ms)
1806 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1807 pkt << bgcolor << type << (u16) params.size();
1809 for(size_t i=0; i<params.size(); i++)
1815 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1818 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1821 pkt << do_override << (u16) (ratio * 65535);
1826 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1828 DSTACK(FUNCTION_NAME);
1830 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1831 pkt << time << time_speed;
1833 if (peer_id == PEER_ID_INEXISTENT) {
1834 m_clients.sendToAll(0, &pkt, true);
1841 void Server::SendPlayerHP(u16 peer_id)
1843 DSTACK(FUNCTION_NAME);
1844 PlayerSAO *playersao = getPlayerSAO(peer_id);
1845 // In some rare case if the player is disconnected
1846 // while Lua call l_punch, for example, this can be NULL
1850 SendHP(peer_id, playersao->getHP());
1851 m_script->player_event(playersao,"health_changed");
1853 // Send to other clients
1854 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1855 ActiveObjectMessage aom(playersao->getId(), true, str);
1856 playersao->m_messages_out.push(aom);
1859 void Server::SendPlayerBreath(PlayerSAO *sao)
1861 DSTACK(FUNCTION_NAME);
1864 m_script->player_event(sao, "breath_changed");
1865 SendBreath(sao->getPeerID(), sao->getBreath());
1868 void Server::SendMovePlayer(u16 peer_id)
1870 DSTACK(FUNCTION_NAME);
1871 RemotePlayer *player = m_env->getPlayer(peer_id);
1873 PlayerSAO *sao = player->getPlayerSAO();
1876 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1877 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1880 v3f pos = sao->getBasePosition();
1881 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1882 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1883 << " pitch=" << sao->getPitch()
1884 << " yaw=" << sao->getYaw()
1891 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1893 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1896 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1897 << animation_frames[3] << animation_speed;
1902 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1904 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1905 pkt << first << third;
1908 void Server::SendPlayerPrivileges(u16 peer_id)
1910 RemotePlayer *player = m_env->getPlayer(peer_id);
1912 if(player->peer_id == PEER_ID_INEXISTENT)
1915 std::set<std::string> privs;
1916 m_script->getAuth(player->getName(), NULL, &privs);
1918 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1919 pkt << (u16) privs.size();
1921 for(std::set<std::string>::const_iterator i = privs.begin();
1922 i != privs.end(); ++i) {
1929 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1931 RemotePlayer *player = m_env->getPlayer(peer_id);
1933 if(player->peer_id == PEER_ID_INEXISTENT)
1936 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1937 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1941 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1943 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1944 pkt.putRawString(datas.c_str(), datas.size());
1946 return pkt.getSize();
1949 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1951 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1952 datas.size(), peer_id);
1954 pkt.putRawString(datas.c_str(), datas.size());
1956 m_clients.send(pkt.getPeerId(),
1957 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1962 s32 Server::playSound(const SimpleSoundSpec &spec,
1963 const ServerSoundParams ¶ms)
1965 // Find out initial position of sound
1966 bool pos_exists = false;
1967 v3f pos = params.getPos(m_env, &pos_exists);
1968 // If position is not found while it should be, cancel sound
1969 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1972 // Filter destination clients
1973 std::vector<u16> dst_clients;
1974 if(params.to_player != "")
1976 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1978 infostream<<"Server::playSound: Player \""<<params.to_player
1979 <<"\" not found"<<std::endl;
1982 if(player->peer_id == PEER_ID_INEXISTENT){
1983 infostream<<"Server::playSound: Player \""<<params.to_player
1984 <<"\" not connected"<<std::endl;
1987 dst_clients.push_back(player->peer_id);
1990 std::vector<u16> clients = m_clients.getClientIDs();
1992 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1993 RemotePlayer *player = m_env->getPlayer(*i);
1997 PlayerSAO *sao = player->getPlayerSAO();
2002 if(sao->getBasePosition().getDistanceFrom(pos) >
2003 params.max_hear_distance)
2006 dst_clients.push_back(*i);
2010 if(dst_clients.empty())
2014 s32 id = m_next_sound_id++;
2015 // The sound will exist as a reference in m_playing_sounds
2016 m_playing_sounds[id] = ServerPlayingSound();
2017 ServerPlayingSound &psound = m_playing_sounds[id];
2018 psound.params = params;
2020 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2021 pkt << id << spec.name << (float) (spec.gain * params.gain)
2022 << (u8) params.type << pos << params.object << params.loop;
2024 for(std::vector<u16>::iterator i = dst_clients.begin();
2025 i != dst_clients.end(); ++i) {
2026 psound.clients.insert(*i);
2027 m_clients.send(*i, 0, &pkt, true);
2031 void Server::stopSound(s32 handle)
2033 // Get sound reference
2034 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2035 if (i == m_playing_sounds.end())
2037 ServerPlayingSound &psound = i->second;
2039 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2042 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2043 i != psound.clients.end(); ++i) {
2045 m_clients.send(*i, 0, &pkt, true);
2047 // Remove sound reference
2048 m_playing_sounds.erase(i);
2051 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2052 std::vector<u16> *far_players, float far_d_nodes)
2054 float maxd = far_d_nodes*BS;
2055 v3f p_f = intToFloat(p, BS);
2057 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2060 std::vector<u16> clients = m_clients.getClientIDs();
2061 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2064 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2065 PlayerSAO *sao = player->getPlayerSAO();
2069 // If player is far away, only set modified blocks not sent
2070 v3f player_pos = sao->getBasePosition();
2071 if (player_pos.getDistanceFrom(p_f) > maxd) {
2072 far_players->push_back(*i);
2079 m_clients.send(*i, 0, &pkt, true);
2083 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2084 std::vector<u16> *far_players, float far_d_nodes,
2085 bool remove_metadata)
2087 float maxd = far_d_nodes*BS;
2088 v3f p_f = intToFloat(p, BS);
2090 std::vector<u16> clients = m_clients.getClientIDs();
2091 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2094 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2095 PlayerSAO *sao = player->getPlayerSAO();
2099 // If player is far away, only set modified blocks not sent
2100 v3f player_pos = sao->getBasePosition();
2101 if(player_pos.getDistanceFrom(p_f) > maxd) {
2102 far_players->push_back(*i);
2108 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2110 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2112 pkt << p << n.param0 << n.param1 << n.param2
2113 << (u8) (remove_metadata ? 0 : 1);
2115 if (!remove_metadata) {
2116 if (client->net_proto_version <= 21) {
2117 // Old clients always clear metadata; fix it
2118 // by sending the full block again.
2119 client->SetBlockNotSent(getNodeBlockPos(p));
2126 if (pkt.getSize() > 0)
2127 m_clients.send(*i, 0, &pkt, true);
2131 void Server::setBlockNotSent(v3s16 p)
2133 std::vector<u16> clients = m_clients.getClientIDs();
2135 for(std::vector<u16>::iterator i = clients.begin();
2136 i != clients.end(); ++i) {
2137 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2138 client->SetBlockNotSent(p);
2143 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2145 DSTACK(FUNCTION_NAME);
2147 v3s16 p = block->getPos();
2150 Create a packet with the block in the right format
2153 std::ostringstream os(std::ios_base::binary);
2154 block->serialize(os, ver, false);
2155 block->serializeNetworkSpecific(os, net_proto_version);
2156 std::string s = os.str();
2158 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2161 pkt.putRawString(s.c_str(), s.size());
2165 void Server::SendBlocks(float dtime)
2167 DSTACK(FUNCTION_NAME);
2169 MutexAutoLock envlock(m_env_mutex);
2170 //TODO check if one big lock could be faster then multiple small ones
2172 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2174 std::vector<PrioritySortedBlockTransfer> queue;
2176 s32 total_sending = 0;
2179 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2181 std::vector<u16> clients = m_clients.getClientIDs();
2184 for(std::vector<u16>::iterator i = clients.begin();
2185 i != clients.end(); ++i) {
2186 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2191 total_sending += client->SendingCount();
2192 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2198 // Lowest priority number comes first.
2199 // Lowest is most important.
2200 std::sort(queue.begin(), queue.end());
2203 for(u32 i=0; i<queue.size(); i++)
2205 //TODO: Calculate limit dynamically
2206 if(total_sending >= g_settings->getS32
2207 ("max_simultaneous_block_sends_server_total"))
2210 PrioritySortedBlockTransfer q = queue[i];
2212 MapBlock *block = NULL;
2215 block = m_env->getMap().getBlockNoCreate(q.pos);
2217 catch(InvalidPositionException &e)
2222 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2227 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2229 client->SentBlock(q.pos);
2235 void Server::fillMediaCache()
2237 DSTACK(FUNCTION_NAME);
2239 infostream<<"Server: Calculating media file checksums"<<std::endl;
2241 // Collect all media file paths
2242 std::vector<std::string> paths;
2243 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2244 i != m_mods.end(); ++i) {
2245 const ModSpec &mod = *i;
2246 paths.push_back(mod.path + DIR_DELIM + "textures");
2247 paths.push_back(mod.path + DIR_DELIM + "sounds");
2248 paths.push_back(mod.path + DIR_DELIM + "media");
2249 paths.push_back(mod.path + DIR_DELIM + "models");
2251 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2253 // Collect media file information from paths into cache
2254 for(std::vector<std::string>::iterator i = paths.begin();
2255 i != paths.end(); ++i) {
2256 std::string mediapath = *i;
2257 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2258 for (u32 j = 0; j < dirlist.size(); j++) {
2259 if (dirlist[j].dir) // Ignode dirs
2261 std::string filename = dirlist[j].name;
2262 // If name contains illegal characters, ignore the file
2263 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2264 infostream<<"Server: ignoring illegal file name: \""
2265 << filename << "\"" << std::endl;
2268 // If name is not in a supported format, ignore it
2269 const char *supported_ext[] = {
2270 ".png", ".jpg", ".bmp", ".tga",
2271 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2273 ".x", ".b3d", ".md2", ".obj",
2276 if (removeStringEnd(filename, supported_ext) == ""){
2277 infostream << "Server: ignoring unsupported file extension: \""
2278 << filename << "\"" << std::endl;
2281 // Ok, attempt to load the file and add to cache
2282 std::string filepath = mediapath + DIR_DELIM + filename;
2284 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2286 errorstream << "Server::fillMediaCache(): Could not open \""
2287 << filename << "\" for reading" << std::endl;
2290 std::ostringstream tmp_os(std::ios_base::binary);
2294 fis.read(buf, 1024);
2295 std::streamsize len = fis.gcount();
2296 tmp_os.write(buf, len);
2305 errorstream<<"Server::fillMediaCache(): Failed to read \""
2306 << filename << "\"" << std::endl;
2309 if(tmp_os.str().length() == 0) {
2310 errorstream << "Server::fillMediaCache(): Empty file \""
2311 << filepath << "\"" << std::endl;
2316 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2318 unsigned char *digest = sha1.getDigest();
2319 std::string sha1_base64 = base64_encode(digest, 20);
2320 std::string sha1_hex = hex_encode((char*)digest, 20);
2324 m_media[filename] = MediaInfo(filepath, sha1_base64);
2325 verbosestream << "Server: " << sha1_hex << " is " << filename
2331 void Server::sendMediaAnnouncement(u16 peer_id)
2333 DSTACK(FUNCTION_NAME);
2335 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2339 std::ostringstream os(std::ios_base::binary);
2341 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2342 pkt << (u16) m_media.size();
2344 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2345 i != m_media.end(); ++i) {
2346 pkt << i->first << i->second.sha1_digest;
2349 pkt << g_settings->get("remote_media");
2353 struct SendableMedia
2359 SendableMedia(const std::string &name_="", const std::string &path_="",
2360 const std::string &data_=""):
2367 void Server::sendRequestedMedia(u16 peer_id,
2368 const std::vector<std::string> &tosend)
2370 DSTACK(FUNCTION_NAME);
2372 verbosestream<<"Server::sendRequestedMedia(): "
2373 <<"Sending files to client"<<std::endl;
2377 // Put 5kB in one bunch (this is not accurate)
2378 u32 bytes_per_bunch = 5000;
2380 std::vector< std::vector<SendableMedia> > file_bunches;
2381 file_bunches.push_back(std::vector<SendableMedia>());
2383 u32 file_size_bunch_total = 0;
2385 for(std::vector<std::string>::const_iterator i = tosend.begin();
2386 i != tosend.end(); ++i) {
2387 const std::string &name = *i;
2389 if (m_media.find(name) == m_media.end()) {
2390 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2391 <<"unknown file \""<<(name)<<"\""<<std::endl;
2395 //TODO get path + name
2396 std::string tpath = m_media[name].path;
2399 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2400 if(fis.good() == false){
2401 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2402 <<tpath<<"\" for reading"<<std::endl;
2405 std::ostringstream tmp_os(std::ios_base::binary);
2409 fis.read(buf, 1024);
2410 std::streamsize len = fis.gcount();
2411 tmp_os.write(buf, len);
2412 file_size_bunch_total += len;
2421 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2422 <<name<<"\""<<std::endl;
2425 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2426 <<tname<<"\""<<std::endl;*/
2428 file_bunches[file_bunches.size()-1].push_back(
2429 SendableMedia(name, tpath, tmp_os.str()));
2431 // Start next bunch if got enough data
2432 if(file_size_bunch_total >= bytes_per_bunch) {
2433 file_bunches.push_back(std::vector<SendableMedia>());
2434 file_size_bunch_total = 0;
2439 /* Create and send packets */
2441 u16 num_bunches = file_bunches.size();
2442 for(u16 i = 0; i < num_bunches; i++) {
2445 u16 total number of texture bunches
2446 u16 index of this bunch
2447 u32 number of files in this bunch
2456 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2457 pkt << num_bunches << i << (u32) file_bunches[i].size();
2459 for(std::vector<SendableMedia>::iterator
2460 j = file_bunches[i].begin();
2461 j != file_bunches[i].end(); ++j) {
2463 pkt.putLongString(j->data);
2466 verbosestream << "Server::sendRequestedMedia(): bunch "
2467 << i << "/" << num_bunches
2468 << " files=" << file_bunches[i].size()
2469 << " size=" << pkt.getSize() << std::endl;
2474 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2476 if(m_detached_inventories.count(name) == 0) {
2477 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2480 Inventory *inv = m_detached_inventories[name];
2481 std::ostringstream os(std::ios_base::binary);
2483 os << serializeString(name);
2487 std::string s = os.str();
2489 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2490 pkt.putRawString(s.c_str(), s.size());
2492 const std::string &check = m_detached_inventories_player[name];
2493 if (peer_id == PEER_ID_INEXISTENT) {
2495 return m_clients.sendToAll(0, &pkt, true);
2496 RemotePlayer *p = m_env->getPlayer(check.c_str());
2498 m_clients.send(p->peer_id, 0, &pkt, true);
2500 if (check == "" || getPlayerName(peer_id) == check)
2505 void Server::sendDetachedInventories(u16 peer_id)
2507 DSTACK(FUNCTION_NAME);
2509 for(std::map<std::string, Inventory*>::iterator
2510 i = m_detached_inventories.begin();
2511 i != m_detached_inventories.end(); ++i) {
2512 const std::string &name = i->first;
2513 //Inventory *inv = i->second;
2514 sendDetachedInventory(name, peer_id);
2522 void Server::DiePlayer(u16 peer_id)
2524 DSTACK(FUNCTION_NAME);
2525 PlayerSAO *playersao = getPlayerSAO(peer_id);
2526 // In some rare cases this can be NULL -- if the player is disconnected
2527 // when a Lua function modifies l_punch, for example
2531 infostream << "Server::DiePlayer(): Player "
2532 << playersao->getPlayer()->getName()
2533 << " dies" << std::endl;
2535 playersao->setHP(0);
2537 // Trigger scripted stuff
2538 m_script->on_dieplayer(playersao);
2540 SendPlayerHP(peer_id);
2541 SendDeathscreen(peer_id, false, v3f(0,0,0));
2544 void Server::RespawnPlayer(u16 peer_id)
2546 DSTACK(FUNCTION_NAME);
2548 PlayerSAO *playersao = getPlayerSAO(peer_id);
2551 infostream << "Server::RespawnPlayer(): Player "
2552 << playersao->getPlayer()->getName()
2553 << " respawns" << std::endl;
2555 playersao->setHP(PLAYER_MAX_HP);
2556 playersao->setBreath(PLAYER_MAX_BREATH);
2558 bool repositioned = m_script->on_respawnplayer(playersao);
2559 if (!repositioned) {
2560 v3f pos = findSpawnPos();
2561 // setPos will send the new position to client
2562 playersao->setPos(pos);
2565 SendPlayerHP(peer_id);
2569 void Server::DenySudoAccess(u16 peer_id)
2571 DSTACK(FUNCTION_NAME);
2573 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2578 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2579 const std::string &str_reason, bool reconnect)
2581 if (proto_ver >= 25) {
2582 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2584 std::wstring wreason = utf8_to_wide(
2585 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2586 accessDeniedStrings[(u8)reason]);
2587 SendAccessDenied_Legacy(peer_id, wreason);
2590 m_clients.event(peer_id, CSE_SetDenied);
2591 m_con.DisconnectPeer(peer_id);
2595 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2597 DSTACK(FUNCTION_NAME);
2599 SendAccessDenied(peer_id, reason, custom_reason);
2600 m_clients.event(peer_id, CSE_SetDenied);
2601 m_con.DisconnectPeer(peer_id);
2604 // 13/03/15: remove this function when protocol version 25 will become
2605 // the minimum version for MT users, maybe in 1 year
2606 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2608 DSTACK(FUNCTION_NAME);
2610 SendAccessDenied_Legacy(peer_id, reason);
2611 m_clients.event(peer_id, CSE_SetDenied);
2612 m_con.DisconnectPeer(peer_id);
2615 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2617 DSTACK(FUNCTION_NAME);
2620 RemoteClient* client = getClient(peer_id, CS_Invalid);
2622 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2624 // Right now, the auth mechs don't change between login and sudo mode.
2625 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2626 client->allowed_sudo_mechs = sudo_auth_mechs;
2628 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2629 << g_settings->getFloat("dedicated_server_step")
2633 m_clients.event(peer_id, CSE_AuthAccept);
2635 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2637 // We only support SRP right now
2638 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2640 resp_pkt << sudo_auth_mechs;
2642 m_clients.event(peer_id, CSE_SudoSuccess);
2646 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2648 DSTACK(FUNCTION_NAME);
2649 std::wstring message;
2652 Clear references to playing sounds
2654 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2655 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2656 ServerPlayingSound &psound = i->second;
2657 psound.clients.erase(peer_id);
2658 if (psound.clients.empty())
2659 m_playing_sounds.erase(i++);
2664 RemotePlayer *player = m_env->getPlayer(peer_id);
2666 /* Run scripts and remove from environment */
2667 if (player != NULL) {
2668 PlayerSAO *playersao = player->getPlayerSAO();
2671 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2673 playersao->disconnected();
2680 if(player != NULL && reason != CDR_DENY) {
2681 std::ostringstream os(std::ios_base::binary);
2682 std::vector<u16> clients = m_clients.getClientIDs();
2684 for(std::vector<u16>::iterator i = clients.begin();
2685 i != clients.end(); ++i) {
2687 RemotePlayer *player = m_env->getPlayer(*i);
2691 // Get name of player
2692 os << player->getName() << " ";
2695 std::string name = player->getName();
2696 actionstream << name << " "
2697 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2698 << " List of players: " << os.str() << std::endl;
2700 m_admin_chat->outgoing_queue.push_back(
2701 new ChatEventNick(CET_NICK_REMOVE, name));
2705 MutexAutoLock env_lock(m_env_mutex);
2706 m_clients.DeleteClient(peer_id);
2710 // Send leave chat message to all remaining clients
2711 if(message.length() != 0)
2712 SendChatMessage(PEER_ID_INEXISTENT,message);
2715 void Server::UpdateCrafting(RemotePlayer *player)
2717 DSTACK(FUNCTION_NAME);
2719 // Get a preview for crafting
2721 InventoryLocation loc;
2722 loc.setPlayer(player->getName());
2723 std::vector<ItemStack> output_replacements;
2724 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2725 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2726 (&player->inventory)->getList("craft"), loc);
2728 // Put the new preview in
2729 InventoryList *plist = player->inventory.getList("craftpreview");
2730 sanity_check(plist);
2731 sanity_check(plist->getSize() >= 1);
2732 plist->changeItem(0, preview);
2735 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2737 if (evt->type == CET_NICK_ADD) {
2738 // The terminal informed us of its nick choice
2739 m_admin_nick = ((ChatEventNick *)evt)->nick;
2740 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2741 errorstream << "You haven't set up an account." << std::endl
2742 << "Please log in using the client as '"
2743 << m_admin_nick << "' with a secure password." << std::endl
2744 << "Until then, you can't execute admin tasks via the console," << std::endl
2745 << "and everybody can claim the user account instead of you," << std::endl
2746 << "giving them full control over this server." << std::endl;
2749 assert(evt->type == CET_CHAT);
2750 handleAdminChat((ChatEventChat *)evt);
2754 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2755 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2757 // If something goes wrong, this player is to blame
2758 RollbackScopeActor rollback_scope(m_rollback,
2759 std::string("player:") + name);
2763 // Whether to send line to the player that sent the message, or to all players
2764 bool broadcast_line = true;
2767 bool ate = m_script->on_chat_message(name,
2768 wide_to_utf8(wmessage));
2769 // If script ate the message, don't proceed
2774 switch (player->canSendChatMessage()) {
2775 case RPLAYER_CHATRESULT_FLOODING: {
2776 std::wstringstream ws;
2777 ws << L"You cannot send more messages. You are limited to "
2778 << g_settings->getFloat("chat_message_limit_per_10sec")
2779 << L" messages per 10 seconds.";
2782 case RPLAYER_CHATRESULT_KICK:
2783 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2785 case RPLAYER_CHATRESULT_OK: break;
2786 default: FATAL_ERROR("Unhandled chat filtering result found.");
2790 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2791 return L"Your message exceed the maximum chat message limit set on the server. "
2792 L"It was refused. Send a shorter message";
2795 // Commands are implemented in Lua, so only catch invalid
2796 // commands that were not "eaten" and send an error back
2797 if (wmessage[0] == L'/') {
2798 std::wstring wcmd = wmessage.substr(1);
2799 broadcast_line = false;
2800 if (wcmd.length() == 0)
2801 line += L"-!- Empty command";
2803 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2805 if (check_shout_priv && !checkPriv(name, "shout")) {
2806 line += L"-!- You don't have permission to shout.";
2807 broadcast_line = false;
2817 Tell calling method to send the message to sender
2819 if (!broadcast_line) {
2823 Send the message to others
2825 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2827 std::vector<u16> clients = m_clients.getClientIDs();
2830 Send the message back to the inital sender
2831 if they are using protocol version >= 29
2834 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2835 if (player->protocol_version >= 29)
2836 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2838 for (u16 i = 0; i < clients.size(); i++) {
2839 u16 cid = clients[i];
2840 if (cid != peer_id_to_avoid_sending)
2841 SendChatMessage(cid, line);
2847 void Server::handleAdminChat(const ChatEventChat *evt)
2849 std::string name = evt->nick;
2850 std::wstring wname = utf8_to_wide(name);
2851 std::wstring wmessage = evt->evt_msg;
2853 std::wstring answer = handleChat(name, wname, wmessage);
2855 // If asked to send answer to sender
2856 if (!answer.empty()) {
2857 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2861 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2863 RemoteClient *client = getClientNoEx(peer_id,state_min);
2865 throw ClientNotFoundException("Client not found");
2869 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2871 return m_clients.getClientNoEx(peer_id, state_min);
2874 std::string Server::getPlayerName(u16 peer_id)
2876 RemotePlayer *player = m_env->getPlayer(peer_id);
2878 return "[id="+itos(peer_id)+"]";
2879 return player->getName();
2882 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2884 RemotePlayer *player = m_env->getPlayer(peer_id);
2887 return player->getPlayerSAO();
2890 std::wstring Server::getStatusString()
2892 std::wostringstream os(std::ios_base::binary);
2895 os<<L"version="<<narrow_to_wide(g_version_string);
2897 os<<L", uptime="<<m_uptime.get();
2899 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2900 // Information about clients
2903 std::vector<u16> clients = m_clients.getClientIDs();
2904 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2906 RemotePlayer *player = m_env->getPlayer(*i);
2907 // Get name of player
2908 std::wstring name = L"unknown";
2910 name = narrow_to_wide(player->getName());
2911 // Add name to information string
2919 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2920 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2921 if(g_settings->get("motd") != "")
2922 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2926 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2928 std::set<std::string> privs;
2929 m_script->getAuth(name, NULL, &privs);
2933 bool Server::checkPriv(const std::string &name, const std::string &priv)
2935 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2936 return (privs.count(priv) != 0);
2939 void Server::reportPrivsModified(const std::string &name)
2942 std::vector<u16> clients = m_clients.getClientIDs();
2943 for(std::vector<u16>::iterator i = clients.begin();
2944 i != clients.end(); ++i) {
2945 RemotePlayer *player = m_env->getPlayer(*i);
2946 reportPrivsModified(player->getName());
2949 RemotePlayer *player = m_env->getPlayer(name.c_str());
2952 SendPlayerPrivileges(player->peer_id);
2953 PlayerSAO *sao = player->getPlayerSAO();
2956 sao->updatePrivileges(
2957 getPlayerEffectivePrivs(name),
2962 void Server::reportInventoryFormspecModified(const std::string &name)
2964 RemotePlayer *player = m_env->getPlayer(name.c_str());
2967 SendPlayerInventoryFormspec(player->peer_id);
2970 void Server::setIpBanned(const std::string &ip, const std::string &name)
2972 m_banmanager->add(ip, name);
2975 void Server::unsetIpBanned(const std::string &ip_or_name)
2977 m_banmanager->remove(ip_or_name);
2980 std::string Server::getBanDescription(const std::string &ip_or_name)
2982 return m_banmanager->getBanDescription(ip_or_name);
2985 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2987 // m_env will be NULL if the server is initializing
2991 if (m_admin_nick == name && !m_admin_nick.empty()) {
2992 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2995 RemotePlayer *player = m_env->getPlayer(name);
3000 if (player->peer_id == PEER_ID_INEXISTENT)
3003 SendChatMessage(player->peer_id, msg);
3006 bool Server::showFormspec(const char *playername, const std::string &formspec,
3007 const std::string &formname)
3009 // m_env will be NULL if the server is initializing
3013 RemotePlayer *player = m_env->getPlayer(playername);
3017 SendShowFormspecMessage(player->peer_id, formspec, formname);
3021 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3026 u32 id = player->addHud(form);
3028 SendHUDAdd(player->peer_id, id, form);
3033 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3037 HudElement* todel = player->removeHud(id);
3044 SendHUDRemove(player->peer_id, id);
3048 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3053 SendHUDChange(player->peer_id, id, stat, data);
3057 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3062 SendHUDSetFlags(player->peer_id, flags, mask);
3063 player->hud_flags &= ~mask;
3064 player->hud_flags |= flags;
3066 PlayerSAO* playersao = player->getPlayerSAO();
3068 if (playersao == NULL)
3071 m_script->player_event(playersao, "hud_changed");
3075 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3080 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3083 player->setHotbarItemcount(hotbar_itemcount);
3084 std::ostringstream os(std::ios::binary);
3085 writeS32(os, hotbar_itemcount);
3086 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3090 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3095 player->setHotbarImage(name);
3096 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3099 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3103 return player->getHotbarImage();
3106 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3111 player->setHotbarSelectedImage(name);
3112 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3115 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3116 v2s32 animation_frames[4], f32 frame_speed)
3121 player->setLocalAnimations(animation_frames, frame_speed);
3122 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3126 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3131 player->eye_offset_first = first;
3132 player->eye_offset_third = third;
3133 SendEyeOffset(player->peer_id, first, third);
3137 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3138 const std::string &type, const std::vector<std::string> ¶ms)
3143 player->setSky(bgcolor, type, params);
3144 SendSetSky(player->peer_id, bgcolor, type, params);
3148 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3154 player->overrideDayNightRatio(do_override, ratio);
3155 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3159 void Server::notifyPlayers(const std::wstring &msg)
3161 SendChatMessage(PEER_ID_INEXISTENT,msg);
3164 void Server::spawnParticle(const std::string &playername, v3f pos,
3165 v3f velocity, v3f acceleration,
3166 float expirationtime, float size, bool
3167 collisiondetection, bool collision_removal,
3168 bool vertical, const std::string &texture)
3170 // m_env will be NULL if the server is initializing
3174 u16 peer_id = PEER_ID_INEXISTENT;
3175 if (playername != "") {
3176 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3179 peer_id = player->peer_id;
3182 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3183 expirationtime, size, collisiondetection,
3184 collision_removal, vertical, texture);
3187 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3188 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3189 float minexptime, float maxexptime, float minsize, float maxsize,
3190 bool collisiondetection, bool collision_removal,
3191 ServerActiveObject *attached, bool vertical, const std::string &texture,
3192 const std::string &playername)
3194 // m_env will be NULL if the server is initializing
3198 u16 peer_id = PEER_ID_INEXISTENT;
3199 if (playername != "") {
3200 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3203 peer_id = player->peer_id;
3206 u16 attached_id = attached ? attached->getId() : 0;
3209 if (attached_id == 0)
3210 id = m_env->addParticleSpawner(spawntime);
3212 id = m_env->addParticleSpawner(spawntime, attached_id);
3214 SendAddParticleSpawner(peer_id, amount, spawntime,
3215 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3216 minexptime, maxexptime, minsize, maxsize,
3217 collisiondetection, collision_removal, attached_id, vertical,
3223 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3225 // m_env will be NULL if the server is initializing
3227 throw ServerError("Can't delete particle spawners during initialisation!");
3229 u16 peer_id = PEER_ID_INEXISTENT;
3230 if (playername != "") {
3231 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3234 peer_id = player->peer_id;
3237 m_env->deleteParticleSpawner(id);
3238 SendDeleteParticleSpawner(peer_id, id);
3241 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3243 if(m_detached_inventories.count(name) > 0){
3244 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3245 delete m_detached_inventories[name];
3247 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3249 Inventory *inv = new Inventory(m_itemdef);
3251 m_detached_inventories[name] = inv;
3252 m_detached_inventories_player[name] = player;
3253 //TODO find a better way to do this
3254 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3258 // actions: time-reversed list
3259 // Return value: success/failure
3260 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3261 std::list<std::string> *log)
3263 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3264 ServerMap *map = (ServerMap*)(&m_env->getMap());
3266 // Fail if no actions to handle
3267 if(actions.empty()){
3268 log->push_back("Nothing to do.");
3275 for(std::list<RollbackAction>::const_iterator
3276 i = actions.begin();
3277 i != actions.end(); ++i)
3279 const RollbackAction &action = *i;
3281 bool success = action.applyRevert(map, this, this);
3284 std::ostringstream os;
3285 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3286 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3288 log->push_back(os.str());
3290 std::ostringstream os;
3291 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3292 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3294 log->push_back(os.str());
3298 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3299 <<" failed"<<std::endl;
3301 // Call it done if less than half failed
3302 return num_failed <= num_tried/2;
3305 // IGameDef interface
3307 IItemDefManager *Server::getItemDefManager()
3312 INodeDefManager *Server::getNodeDefManager()
3317 ICraftDefManager *Server::getCraftDefManager()
3322 u16 Server::allocateUnknownNodeId(const std::string &name)
3324 return m_nodedef->allocateDummy(name);
3327 MtEventManager *Server::getEventManager()
3332 IWritableItemDefManager *Server::getWritableItemDefManager()
3337 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3342 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3347 const ModSpec *Server::getModSpec(const std::string &modname) const
3349 std::vector<ModSpec>::const_iterator it;
3350 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3351 const ModSpec &mod = *it;
3352 if (mod.name == modname)
3358 void Server::getModNames(std::vector<std::string> &modlist)
3360 std::vector<ModSpec>::iterator it;
3361 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3362 modlist.push_back(it->name);
3365 std::string Server::getBuiltinLuaPath()
3367 return porting::path_share + DIR_DELIM + "builtin";
3370 v3f Server::findSpawnPos()
3372 ServerMap &map = m_env->getServerMap();
3374 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3375 return nodeposf * BS;
3378 bool is_good = false;
3380 // Try to find a good place a few times
3381 for(s32 i = 0; i < 4000 && !is_good; i++) {
3383 // We're going to try to throw the player to this position
3384 v2s16 nodepos2d = v2s16(
3385 -range + (myrand() % (range * 2)),
3386 -range + (myrand() % (range * 2)));
3388 // Get spawn level at point
3389 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3390 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3391 // the mapgen to signify an unsuitable spawn position
3392 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3395 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3398 for (s32 i = 0; i < 10; i++) {
3399 v3s16 blockpos = getNodeBlockPos(nodepos);
3400 map.emergeBlock(blockpos, true);
3401 content_t c = map.getNodeNoEx(nodepos).getContent();
3402 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3404 if (air_count >= 2) {
3405 nodeposf = intToFloat(nodepos, BS);
3406 // Don't spawn the player outside map boundaries
3407 if (objectpos_over_limit(nodeposf))
3420 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3422 bool newplayer = false;
3425 Try to get an existing player
3427 RemotePlayer *player = m_env->getPlayer(name);
3429 // If player is already connected, cancel
3430 if (player != NULL && player->peer_id != 0) {
3431 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3436 If player with the wanted peer_id already exists, cancel.
3438 if (m_env->getPlayer(peer_id) != NULL) {
3439 infostream<<"emergePlayer(): Player with wrong name but same"
3440 " peer_id already exists"<<std::endl;
3444 // Create a new player active object
3445 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3446 player = m_env->loadPlayer(name, playersao);
3448 // Create player if it doesn't exist
3451 player = new RemotePlayer(name, this->idef());
3452 // Set player position
3453 infostream<<"Server: Finding spawn place for player \""
3454 <<name<<"\""<<std::endl;
3455 playersao->setBasePosition(findSpawnPos());
3457 // Make sure the player is saved
3458 player->setModified(true);
3460 // Add player to environment
3461 m_env->addPlayer(player);
3463 // If the player exists, ensure that they respawn inside legal bounds
3464 // This fixes an assert crash when the player can't be added
3465 // to the environment
3466 if (objectpos_over_limit(playersao->getBasePosition())) {
3467 actionstream << "Respawn position for player \""
3468 << name << "\" outside limits, resetting" << std::endl;
3469 playersao->setBasePosition(findSpawnPos());
3473 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3475 player->protocol_version = proto_version;
3477 /* Clean up old HUD elements from previous sessions */
3480 /* Add object to environment */
3481 m_env->addActiveObject(playersao);
3485 m_script->on_newplayer(playersao);
3491 void dedicated_server_loop(Server &server, bool &kill)
3493 DSTACK(FUNCTION_NAME);
3495 verbosestream<<"dedicated_server_loop()"<<std::endl;
3497 IntervalLimiter m_profiler_interval;
3499 static const float steplen = g_settings->getFloat("dedicated_server_step");
3500 static const float profiler_print_interval =
3501 g_settings->getFloat("profiler_print_interval");
3504 // This is kind of a hack but can be done like this
3505 // because server.step() is very light
3507 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3508 sleep_ms((int)(steplen*1000.0));
3510 server.step(steplen);
3512 if(server.getShutdownRequested() || kill)
3514 infostream<<"Dedicated server quitting"<<std::endl;
3516 if(g_settings->getBool("server_announce"))
3517 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3525 if (profiler_print_interval != 0) {
3526 if(m_profiler_interval.step(steplen, profiler_print_interval))
3528 infostream<<"Profiler:"<<std::endl;
3529 g_profiler->print(infostream);
3530 g_profiler->clear();