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 "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("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(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();
2829 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2830 for (u16 i = 0; i < clients.size(); i++) {
2831 u16 cid = clients[i];
2832 if (cid != peer_id_to_avoid_sending)
2833 SendChatMessage(cid, line);
2839 void Server::handleAdminChat(const ChatEventChat *evt)
2841 std::string name = evt->nick;
2842 std::wstring wname = utf8_to_wide(name);
2843 std::wstring wmessage = evt->evt_msg;
2845 std::wstring answer = handleChat(name, wname, wmessage);
2847 // If asked to send answer to sender
2848 if (!answer.empty()) {
2849 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2853 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2855 RemoteClient *client = getClientNoEx(peer_id,state_min);
2857 throw ClientNotFoundException("Client not found");
2861 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2863 return m_clients.getClientNoEx(peer_id, state_min);
2866 std::string Server::getPlayerName(u16 peer_id)
2868 RemotePlayer *player = m_env->getPlayer(peer_id);
2870 return "[id="+itos(peer_id)+"]";
2871 return player->getName();
2874 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2876 RemotePlayer *player = m_env->getPlayer(peer_id);
2879 return player->getPlayerSAO();
2882 std::wstring Server::getStatusString()
2884 std::wostringstream os(std::ios_base::binary);
2887 os<<L"version="<<narrow_to_wide(g_version_string);
2889 os<<L", uptime="<<m_uptime.get();
2891 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2892 // Information about clients
2895 std::vector<u16> clients = m_clients.getClientIDs();
2896 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2898 RemotePlayer *player = m_env->getPlayer(*i);
2899 // Get name of player
2900 std::wstring name = L"unknown";
2902 name = narrow_to_wide(player->getName());
2903 // Add name to information string
2911 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2912 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2913 if(g_settings->get("motd") != "")
2914 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2918 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2920 std::set<std::string> privs;
2921 m_script->getAuth(name, NULL, &privs);
2925 bool Server::checkPriv(const std::string &name, const std::string &priv)
2927 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2928 return (privs.count(priv) != 0);
2931 void Server::reportPrivsModified(const std::string &name)
2934 std::vector<u16> clients = m_clients.getClientIDs();
2935 for(std::vector<u16>::iterator i = clients.begin();
2936 i != clients.end(); ++i) {
2937 RemotePlayer *player = m_env->getPlayer(*i);
2938 reportPrivsModified(player->getName());
2941 RemotePlayer *player = m_env->getPlayer(name.c_str());
2944 SendPlayerPrivileges(player->peer_id);
2945 PlayerSAO *sao = player->getPlayerSAO();
2948 sao->updatePrivileges(
2949 getPlayerEffectivePrivs(name),
2954 void Server::reportInventoryFormspecModified(const std::string &name)
2956 RemotePlayer *player = m_env->getPlayer(name.c_str());
2959 SendPlayerInventoryFormspec(player->peer_id);
2962 void Server::setIpBanned(const std::string &ip, const std::string &name)
2964 m_banmanager->add(ip, name);
2967 void Server::unsetIpBanned(const std::string &ip_or_name)
2969 m_banmanager->remove(ip_or_name);
2972 std::string Server::getBanDescription(const std::string &ip_or_name)
2974 return m_banmanager->getBanDescription(ip_or_name);
2977 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2979 // m_env will be NULL if the server is initializing
2983 if (m_admin_nick == name && !m_admin_nick.empty()) {
2984 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2987 RemotePlayer *player = m_env->getPlayer(name);
2992 if (player->peer_id == PEER_ID_INEXISTENT)
2995 SendChatMessage(player->peer_id, msg);
2998 bool Server::showFormspec(const char *playername, const std::string &formspec,
2999 const std::string &formname)
3001 // m_env will be NULL if the server is initializing
3005 RemotePlayer *player = m_env->getPlayer(playername);
3009 SendShowFormspecMessage(player->peer_id, formspec, formname);
3013 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3018 u32 id = player->addHud(form);
3020 SendHUDAdd(player->peer_id, id, form);
3025 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3029 HudElement* todel = player->removeHud(id);
3036 SendHUDRemove(player->peer_id, id);
3040 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3045 SendHUDChange(player->peer_id, id, stat, data);
3049 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3054 SendHUDSetFlags(player->peer_id, flags, mask);
3055 player->hud_flags &= ~mask;
3056 player->hud_flags |= flags;
3058 PlayerSAO* playersao = player->getPlayerSAO();
3060 if (playersao == NULL)
3063 m_script->player_event(playersao, "hud_changed");
3067 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3072 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3075 player->setHotbarItemcount(hotbar_itemcount);
3076 std::ostringstream os(std::ios::binary);
3077 writeS32(os, hotbar_itemcount);
3078 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3082 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3087 player->setHotbarImage(name);
3088 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3091 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3095 return player->getHotbarImage();
3098 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3103 player->setHotbarSelectedImage(name);
3104 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3107 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3108 v2s32 animation_frames[4], f32 frame_speed)
3113 player->setLocalAnimations(animation_frames, frame_speed);
3114 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3118 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3123 player->eye_offset_first = first;
3124 player->eye_offset_third = third;
3125 SendEyeOffset(player->peer_id, first, third);
3129 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3130 const std::string &type, const std::vector<std::string> ¶ms)
3135 player->setSky(bgcolor, type, params);
3136 SendSetSky(player->peer_id, bgcolor, type, params);
3140 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3146 player->overrideDayNightRatio(do_override, ratio);
3147 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3151 void Server::notifyPlayers(const std::wstring &msg)
3153 SendChatMessage(PEER_ID_INEXISTENT,msg);
3156 void Server::spawnParticle(const std::string &playername, v3f pos,
3157 v3f velocity, v3f acceleration,
3158 float expirationtime, float size, bool
3159 collisiondetection, bool collision_removal,
3160 bool vertical, const std::string &texture)
3162 // m_env will be NULL if the server is initializing
3166 u16 peer_id = PEER_ID_INEXISTENT;
3167 if (playername != "") {
3168 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3171 peer_id = player->peer_id;
3174 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3175 expirationtime, size, collisiondetection,
3176 collision_removal, vertical, texture);
3179 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3180 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3181 float minexptime, float maxexptime, float minsize, float maxsize,
3182 bool collisiondetection, bool collision_removal,
3183 ServerActiveObject *attached, bool vertical, const std::string &texture,
3184 const std::string &playername)
3186 // m_env will be NULL if the server is initializing
3190 u16 peer_id = PEER_ID_INEXISTENT;
3191 if (playername != "") {
3192 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3195 peer_id = player->peer_id;
3198 u16 attached_id = attached ? attached->getId() : 0;
3201 if (attached_id == 0)
3202 id = m_env->addParticleSpawner(spawntime);
3204 id = m_env->addParticleSpawner(spawntime, attached_id);
3206 SendAddParticleSpawner(peer_id, amount, spawntime,
3207 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3208 minexptime, maxexptime, minsize, maxsize,
3209 collisiondetection, collision_removal, attached_id, vertical,
3215 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3217 // m_env will be NULL if the server is initializing
3219 throw ServerError("Can't delete particle spawners during initialisation!");
3221 u16 peer_id = PEER_ID_INEXISTENT;
3222 if (playername != "") {
3223 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3226 peer_id = player->peer_id;
3229 m_env->deleteParticleSpawner(id);
3230 SendDeleteParticleSpawner(peer_id, id);
3233 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3235 if(m_detached_inventories.count(name) > 0){
3236 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3237 delete m_detached_inventories[name];
3239 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3241 Inventory *inv = new Inventory(m_itemdef);
3243 m_detached_inventories[name] = inv;
3244 m_detached_inventories_player[name] = player;
3245 //TODO find a better way to do this
3246 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3250 // actions: time-reversed list
3251 // Return value: success/failure
3252 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3253 std::list<std::string> *log)
3255 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3256 ServerMap *map = (ServerMap*)(&m_env->getMap());
3258 // Fail if no actions to handle
3259 if(actions.empty()){
3260 log->push_back("Nothing to do.");
3267 for(std::list<RollbackAction>::const_iterator
3268 i = actions.begin();
3269 i != actions.end(); ++i)
3271 const RollbackAction &action = *i;
3273 bool success = action.applyRevert(map, this, this);
3276 std::ostringstream os;
3277 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3278 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3280 log->push_back(os.str());
3282 std::ostringstream os;
3283 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3284 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3286 log->push_back(os.str());
3290 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3291 <<" failed"<<std::endl;
3293 // Call it done if less than half failed
3294 return num_failed <= num_tried/2;
3297 // IGameDef interface
3299 IItemDefManager *Server::getItemDefManager()
3304 INodeDefManager *Server::getNodeDefManager()
3309 ICraftDefManager *Server::getCraftDefManager()
3313 ITextureSource *Server::getTextureSource()
3317 IShaderSource *Server::getShaderSource()
3321 scene::ISceneManager *Server::getSceneManager()
3326 u16 Server::allocateUnknownNodeId(const std::string &name)
3328 return m_nodedef->allocateDummy(name);
3331 ISoundManager *Server::getSoundManager()
3333 return &dummySoundManager;
3336 MtEventManager *Server::getEventManager()
3341 IWritableItemDefManager *Server::getWritableItemDefManager()
3346 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3351 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3356 const ModSpec *Server::getModSpec(const std::string &modname) const
3358 std::vector<ModSpec>::const_iterator it;
3359 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3360 const ModSpec &mod = *it;
3361 if (mod.name == modname)
3367 void Server::getModNames(std::vector<std::string> &modlist)
3369 std::vector<ModSpec>::iterator it;
3370 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3371 modlist.push_back(it->name);
3374 std::string Server::getBuiltinLuaPath()
3376 return porting::path_share + DIR_DELIM + "builtin";
3379 v3f Server::findSpawnPos()
3381 ServerMap &map = m_env->getServerMap();
3383 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3384 return nodeposf * BS;
3387 bool is_good = false;
3389 // Try to find a good place a few times
3390 for(s32 i = 0; i < 4000 && !is_good; i++) {
3392 // We're going to try to throw the player to this position
3393 v2s16 nodepos2d = v2s16(
3394 -range + (myrand() % (range * 2)),
3395 -range + (myrand() % (range * 2)));
3397 // Get spawn level at point
3398 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3399 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3400 // the mapgen to signify an unsuitable spawn position
3401 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3404 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3407 for (s32 i = 0; i < 10; i++) {
3408 v3s16 blockpos = getNodeBlockPos(nodepos);
3409 map.emergeBlock(blockpos, true);
3410 content_t c = map.getNodeNoEx(nodepos).getContent();
3411 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3413 if (air_count >= 2) {
3414 nodeposf = intToFloat(nodepos, BS);
3415 // Don't spawn the player outside map boundaries
3416 if (objectpos_over_limit(nodeposf))
3429 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3431 bool newplayer = false;
3434 Try to get an existing player
3436 RemotePlayer *player = m_env->getPlayer(name);
3438 // If player is already connected, cancel
3439 if (player != NULL && player->peer_id != 0) {
3440 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3445 If player with the wanted peer_id already exists, cancel.
3447 if (m_env->getPlayer(peer_id) != NULL) {
3448 infostream<<"emergePlayer(): Player with wrong name but same"
3449 " peer_id already exists"<<std::endl;
3453 // Create a new player active object
3454 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3455 player = m_env->loadPlayer(name, playersao);
3457 // Create player if it doesn't exist
3460 player = new RemotePlayer(name, this->idef());
3461 // Set player position
3462 infostream<<"Server: Finding spawn place for player \""
3463 <<name<<"\""<<std::endl;
3464 playersao->setBasePosition(findSpawnPos());
3466 // Make sure the player is saved
3467 player->setModified(true);
3469 // Add player to environment
3470 m_env->addPlayer(player);
3472 // If the player exists, ensure that they respawn inside legal bounds
3473 // This fixes an assert crash when the player can't be added
3474 // to the environment
3475 if (objectpos_over_limit(playersao->getBasePosition())) {
3476 actionstream << "Respawn position for player \""
3477 << name << "\" outside limits, resetting" << std::endl;
3478 playersao->setBasePosition(findSpawnPos());
3482 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3484 player->protocol_version = proto_version;
3486 /* Clean up old HUD elements from previous sessions */
3489 /* Add object to environment */
3490 m_env->addActiveObject(playersao);
3494 m_script->on_newplayer(playersao);
3500 void dedicated_server_loop(Server &server, bool &kill)
3502 DSTACK(FUNCTION_NAME);
3504 verbosestream<<"dedicated_server_loop()"<<std::endl;
3506 IntervalLimiter m_profiler_interval;
3508 static const float steplen = g_settings->getFloat("dedicated_server_step");
3509 static const float profiler_print_interval =
3510 g_settings->getFloat("profiler_print_interval");
3513 // This is kind of a hack but can be done like this
3514 // because server.step() is very light
3516 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3517 sleep_ms((int)(steplen*1000.0));
3519 server.step(steplen);
3521 if(server.getShutdownRequested() || kill)
3523 infostream<<"Dedicated server quitting"<<std::endl;
3525 if(g_settings->getBool("server_announce"))
3526 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3534 if (profiler_print_interval != 0) {
3535 if(m_profiler_interval.step(steplen, profiler_print_interval))
3537 infostream<<"Profiler:"<<std::endl;
3538 g_profiler->print(infostream);
3539 g_profiler->clear();