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 std::queue<u16> removed_objects;
709 std::queue<u16> added_objects;
710 m_env->getRemovedActiveObjects(playersao, radius, player_radius,
711 client->m_known_objects, removed_objects);
712 m_env->getAddedActiveObjects(playersao, radius, player_radius,
713 client->m_known_objects, added_objects);
715 // Ignore if nothing happened
716 if (removed_objects.empty() && added_objects.empty()) {
720 std::string data_buffer;
724 // Handle removed objects
725 writeU16((u8*)buf, removed_objects.size());
726 data_buffer.append(buf, 2);
727 while (!removed_objects.empty()) {
729 u16 id = removed_objects.front();
730 ServerActiveObject* obj = m_env->getActiveObject(id);
732 // Add to data buffer for sending
733 writeU16((u8*)buf, id);
734 data_buffer.append(buf, 2);
736 // Remove from known objects
737 client->m_known_objects.erase(id);
739 if(obj && obj->m_known_by_count > 0)
740 obj->m_known_by_count--;
741 removed_objects.pop();
744 // Handle added objects
745 writeU16((u8*)buf, added_objects.size());
746 data_buffer.append(buf, 2);
747 while (!added_objects.empty()) {
749 u16 id = added_objects.front();
750 ServerActiveObject* obj = m_env->getActiveObject(id);
753 u8 type = ACTIVEOBJECT_TYPE_INVALID;
755 warningstream<<FUNCTION_NAME
756 <<": NULL object"<<std::endl;
758 type = obj->getSendType();
760 // Add to data buffer for sending
761 writeU16((u8*)buf, id);
762 data_buffer.append(buf, 2);
763 writeU8((u8*)buf, type);
764 data_buffer.append(buf, 1);
767 data_buffer.append(serializeLongString(
768 obj->getClientInitializationData(client->net_proto_version)));
770 data_buffer.append(serializeLongString(""));
772 // Add to known objects
773 client->m_known_objects.insert(id);
776 obj->m_known_by_count++;
781 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
782 verbosestream << "Server: Sent object remove/add: "
783 << removed_objects.size() << " removed, "
784 << added_objects.size() << " added, "
785 << "packet size is " << pktSize << std::endl;
794 MutexAutoLock envlock(m_env_mutex);
795 ScopeProfiler sp(g_profiler, "Server: sending object messages");
798 // Value = data sent by object
799 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
801 // Get active object messages from environment
803 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
807 std::vector<ActiveObjectMessage>* message_list = NULL;
808 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
809 n = buffered_messages.find(aom.id);
810 if (n == buffered_messages.end()) {
811 message_list = new std::vector<ActiveObjectMessage>;
812 buffered_messages[aom.id] = message_list;
815 message_list = n->second;
817 message_list->push_back(aom);
821 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
822 // Route data to every client
823 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
824 i != clients.end(); ++i) {
825 RemoteClient *client = i->second;
826 std::string reliable_data;
827 std::string unreliable_data;
828 // Go through all objects in message buffer
829 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
830 j = buffered_messages.begin();
831 j != buffered_messages.end(); ++j) {
832 // If object is not known by client, skip it
834 if (client->m_known_objects.find(id) == client->m_known_objects.end())
837 // Get message list of object
838 std::vector<ActiveObjectMessage>* list = j->second;
839 // Go through every message
840 for (std::vector<ActiveObjectMessage>::iterator
841 k = list->begin(); k != list->end(); ++k) {
842 // Compose the full new data with header
843 ActiveObjectMessage aom = *k;
844 std::string new_data;
847 writeU16((u8*)&buf[0], aom.id);
848 new_data.append(buf, 2);
850 new_data += serializeString(aom.datastring);
851 // Add data to buffer
853 reliable_data += new_data;
855 unreliable_data += new_data;
859 reliable_data and unreliable_data are now ready.
862 if(reliable_data.size() > 0) {
863 SendActiveObjectMessages(client->peer_id, reliable_data);
866 if(unreliable_data.size() > 0) {
867 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
872 // Clear buffered_messages
873 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
874 i = buffered_messages.begin();
875 i != buffered_messages.end(); ++i) {
881 Send queued-for-sending map edit events.
884 // We will be accessing the environment
885 MutexAutoLock lock(m_env_mutex);
887 // Don't send too many at a time
890 // Single change sending is disabled if queue size is not small
891 bool disable_single_change_sending = false;
892 if(m_unsent_map_edit_queue.size() >= 4)
893 disable_single_change_sending = true;
895 int event_count = m_unsent_map_edit_queue.size();
897 // We'll log the amount of each
900 while(m_unsent_map_edit_queue.size() != 0)
902 MapEditEvent* event = m_unsent_map_edit_queue.front();
903 m_unsent_map_edit_queue.pop();
905 // Players far away from the change are stored here.
906 // Instead of sending the changes, MapBlocks are set not sent
908 std::vector<u16> far_players;
910 switch (event->type) {
913 prof.add("MEET_ADDNODE", 1);
914 sendAddNode(event->p, event->n, event->already_known_by_peer,
915 &far_players, disable_single_change_sending ? 5 : 30,
916 event->type == MEET_ADDNODE);
918 case MEET_REMOVENODE:
919 prof.add("MEET_REMOVENODE", 1);
920 sendRemoveNode(event->p, event->already_known_by_peer,
921 &far_players, disable_single_change_sending ? 5 : 30);
923 case MEET_BLOCK_NODE_METADATA_CHANGED:
924 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
925 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
926 setBlockNotSent(event->p);
929 infostream << "Server: MEET_OTHER" << std::endl;
930 prof.add("MEET_OTHER", 1);
931 for(std::set<v3s16>::iterator
932 i = event->modified_blocks.begin();
933 i != event->modified_blocks.end(); ++i) {
938 prof.add("unknown", 1);
939 warningstream << "Server: Unknown MapEditEvent "
940 << ((u32)event->type) << std::endl;
945 Set blocks not sent to far players
947 if(!far_players.empty()) {
948 // Convert list format to that wanted by SetBlocksNotSent
949 std::map<v3s16, MapBlock*> modified_blocks2;
950 for(std::set<v3s16>::iterator
951 i = event->modified_blocks.begin();
952 i != event->modified_blocks.end(); ++i) {
953 modified_blocks2[*i] =
954 m_env->getMap().getBlockNoCreateNoEx(*i);
957 // Set blocks not sent
958 for(std::vector<u16>::iterator
959 i = far_players.begin();
960 i != far_players.end(); ++i) {
961 if(RemoteClient *client = getClient(*i))
962 client->SetBlocksNotSent(modified_blocks2);
968 /*// Don't send too many at a time
970 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
974 if(event_count >= 5){
975 infostream<<"Server: MapEditEvents:"<<std::endl;
976 prof.print(infostream);
977 } else if(event_count != 0){
978 verbosestream<<"Server: MapEditEvents:"<<std::endl;
979 prof.print(verbosestream);
985 Trigger emergethread (it somehow gets to a non-triggered but
986 bysy state sometimes)
989 float &counter = m_emergethread_trigger_timer;
991 if (counter >= 2.0) {
994 m_emerge->startThreads();
998 // Save map, players and auth stuff
1000 float &counter = m_savemap_timer;
1002 static const float save_interval =
1003 g_settings->getFloat("server_map_save_interval");
1004 if (counter >= save_interval) {
1006 MutexAutoLock lock(m_env_mutex);
1008 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1011 if (m_banmanager->isModified()) {
1012 m_banmanager->save();
1015 // Save changed parts of map
1016 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1019 m_env->saveLoadedPlayers();
1021 // Save environment metadata
1027 void Server::Receive()
1029 DSTACK(FUNCTION_NAME);
1030 SharedBuffer<u8> data;
1034 m_con.Receive(&pkt);
1035 peer_id = pkt.getPeerId();
1038 catch(con::InvalidIncomingDataException &e) {
1039 infostream<<"Server::Receive(): "
1040 "InvalidIncomingDataException: what()="
1041 <<e.what()<<std::endl;
1043 catch(SerializationError &e) {
1044 infostream<<"Server::Receive(): "
1045 "SerializationError: what()="
1046 <<e.what()<<std::endl;
1048 catch(ClientStateError &e) {
1049 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1050 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1051 L"Try reconnecting or updating your client");
1053 catch(con::PeerNotFoundException &e) {
1058 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1060 std::string playername = "";
1061 PlayerSAO *playersao = NULL;
1064 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1065 if (client != NULL) {
1066 playername = client->getName();
1067 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1069 } catch (std::exception &e) {
1075 RemotePlayer *player =
1076 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1078 // If failed, cancel
1079 if ((playersao == NULL) || (player == NULL)) {
1080 if (player && player->peer_id != 0) {
1081 actionstream << "Server: Failed to emerge player \"" << playername
1082 << "\" (player allocated to an another client)" << std::endl;
1083 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1084 L"name. If your client closed unexpectedly, try again in "
1087 errorstream << "Server: " << playername << ": Failed to emerge player"
1089 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1095 Send complete position information
1097 SendMovePlayer(peer_id);
1100 SendPlayerPrivileges(peer_id);
1102 // Send inventory formspec
1103 SendPlayerInventoryFormspec(peer_id);
1106 SendInventory(playersao);
1109 SendPlayerHPOrDie(playersao);
1112 SendPlayerBreath(peer_id);
1114 // Show death screen if necessary
1115 if (playersao->isDead())
1116 SendDeathscreen(peer_id, false, v3f(0,0,0));
1118 // Note things in chat if not in simple singleplayer mode
1119 if(!m_simple_singleplayer_mode) {
1120 // Send information about server to player in chat
1121 SendChatMessage(peer_id, getStatusString());
1123 Address addr = getPeerAddress(player->peer_id);
1124 std::string ip_str = addr.serializeString();
1125 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1130 const std::vector<std::string> &names = m_clients.getPlayerNames();
1132 actionstream << player->getName() << " joins game. List of players: ";
1134 for (std::vector<std::string>::const_iterator i = names.begin();
1135 i != names.end(); ++i) {
1136 actionstream << *i << " ";
1139 actionstream << player->getName() <<std::endl;
1144 inline void Server::handleCommand(NetworkPacket* pkt)
1146 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1147 (this->*opHandle.handler)(pkt);
1150 void Server::ProcessData(NetworkPacket *pkt)
1152 DSTACK(FUNCTION_NAME);
1153 // Environment is locked first.
1154 MutexAutoLock envlock(m_env_mutex);
1156 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1157 u32 peer_id = pkt->getPeerId();
1160 Address address = getPeerAddress(peer_id);
1161 std::string addr_s = address.serializeString();
1163 if(m_banmanager->isIpBanned(addr_s)) {
1164 std::string ban_name = m_banmanager->getBanName(addr_s);
1165 infostream << "Server: A banned client tried to connect from "
1166 << addr_s << "; banned name was "
1167 << ban_name << std::endl;
1168 // This actually doesn't seem to transfer to the client
1169 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1170 + utf8_to_wide(ban_name));
1174 catch(con::PeerNotFoundException &e) {
1176 * no peer for this packet found
1177 * most common reason is peer timeout, e.g. peer didn't
1178 * respond for some time, your server was overloaded or
1181 infostream << "Server::ProcessData(): Canceling: peer "
1182 << peer_id << " not found" << std::endl;
1187 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1189 // Command must be handled into ToServerCommandHandler
1190 if (command >= TOSERVER_NUM_MSG_TYPES) {
1191 infostream << "Server: Ignoring unknown command "
1192 << command << std::endl;
1196 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1201 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1203 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1204 errorstream << "Server::ProcessData(): Cancelling: Peer"
1205 " serialization format invalid or not initialized."
1206 " Skipping incoming command=" << command << std::endl;
1210 /* Handle commands related to client startup */
1211 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1216 if (m_clients.getClientState(peer_id) < CS_Active) {
1217 if (command == TOSERVER_PLAYERPOS) return;
1219 errorstream << "Got packet command: " << command << " for peer id "
1220 << peer_id << " but client isn't active yet. Dropping packet "
1226 } catch (SendFailedException &e) {
1227 errorstream << "Server::ProcessData(): SendFailedException: "
1228 << "what=" << e.what()
1230 } catch (PacketError &e) {
1231 actionstream << "Server::ProcessData(): PacketError: "
1232 << "what=" << e.what()
1237 void Server::setTimeOfDay(u32 time)
1239 m_env->setTimeOfDay(time);
1240 m_time_of_day_send_timer = 0;
1243 void Server::onMapEditEvent(MapEditEvent *event)
1245 if(m_ignore_map_edit_events)
1247 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1249 MapEditEvent *e = event->clone();
1250 m_unsent_map_edit_queue.push(e);
1253 Inventory* Server::getInventory(const InventoryLocation &loc)
1256 case InventoryLocation::UNDEFINED:
1257 case InventoryLocation::CURRENT_PLAYER:
1259 case InventoryLocation::PLAYER:
1261 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1264 PlayerSAO *playersao = player->getPlayerSAO();
1267 return playersao->getInventory();
1270 case InventoryLocation::NODEMETA:
1272 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1275 return meta->getInventory();
1278 case InventoryLocation::DETACHED:
1280 if(m_detached_inventories.count(loc.name) == 0)
1282 return m_detached_inventories[loc.name];
1286 sanity_check(false); // abort
1291 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1294 case InventoryLocation::UNDEFINED:
1296 case InventoryLocation::PLAYER:
1301 RemotePlayer *player =
1302 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1307 PlayerSAO *playersao = player->getPlayerSAO();
1311 SendInventory(playersao);
1314 case InventoryLocation::NODEMETA:
1316 v3s16 blockpos = getNodeBlockPos(loc.p);
1318 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1320 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1322 setBlockNotSent(blockpos);
1325 case InventoryLocation::DETACHED:
1327 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1331 sanity_check(false); // abort
1336 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1338 std::vector<u16> clients = m_clients.getClientIDs();
1340 // Set the modified blocks unsent for all the clients
1341 for (std::vector<u16>::iterator i = clients.begin();
1342 i != clients.end(); ++i) {
1343 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1344 client->SetBlocksNotSent(block);
1349 void Server::peerAdded(con::Peer *peer)
1351 DSTACK(FUNCTION_NAME);
1352 verbosestream<<"Server::peerAdded(): peer->id="
1353 <<peer->id<<std::endl;
1356 c.type = con::PEER_ADDED;
1357 c.peer_id = peer->id;
1359 m_peer_change_queue.push(c);
1362 void Server::deletingPeer(con::Peer *peer, bool timeout)
1364 DSTACK(FUNCTION_NAME);
1365 verbosestream<<"Server::deletingPeer(): peer->id="
1366 <<peer->id<<", timeout="<<timeout<<std::endl;
1368 m_clients.event(peer->id, CSE_Disconnect);
1370 c.type = con::PEER_REMOVED;
1371 c.peer_id = peer->id;
1372 c.timeout = timeout;
1373 m_peer_change_queue.push(c);
1376 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1378 *retval = m_con.getPeerStat(peer_id,type);
1379 if (*retval == -1) return false;
1383 bool Server::getClientInfo(
1392 std::string* vers_string
1395 *state = m_clients.getClientState(peer_id);
1397 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1399 if (client == NULL) {
1404 *uptime = client->uptime();
1405 *ser_vers = client->serialization_version;
1406 *prot_vers = client->net_proto_version;
1408 *major = client->getMajor();
1409 *minor = client->getMinor();
1410 *patch = client->getPatch();
1411 *vers_string = client->getPatch();
1418 void Server::handlePeerChanges()
1420 while(m_peer_change_queue.size() > 0)
1422 con::PeerChange c = m_peer_change_queue.front();
1423 m_peer_change_queue.pop();
1425 verbosestream<<"Server: Handling peer change: "
1426 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1431 case con::PEER_ADDED:
1432 m_clients.CreateClient(c.peer_id);
1435 case con::PEER_REMOVED:
1436 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1440 FATAL_ERROR("Invalid peer change event received!");
1446 void Server::printToConsoleOnly(const std::string &text)
1449 m_admin_chat->outgoing_queue.push_back(
1450 new ChatEventChat("", utf8_to_wide(text)));
1452 std::cout << text << std::endl;
1456 void Server::Send(NetworkPacket* pkt)
1458 m_clients.send(pkt->getPeerId(),
1459 clientCommandFactoryTable[pkt->getCommand()].channel,
1461 clientCommandFactoryTable[pkt->getCommand()].reliable);
1464 void Server::SendMovement(u16 peer_id)
1466 DSTACK(FUNCTION_NAME);
1467 std::ostringstream os(std::ios_base::binary);
1469 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1471 pkt << g_settings->getFloat("movement_acceleration_default");
1472 pkt << g_settings->getFloat("movement_acceleration_air");
1473 pkt << g_settings->getFloat("movement_acceleration_fast");
1474 pkt << g_settings->getFloat("movement_speed_walk");
1475 pkt << g_settings->getFloat("movement_speed_crouch");
1476 pkt << g_settings->getFloat("movement_speed_fast");
1477 pkt << g_settings->getFloat("movement_speed_climb");
1478 pkt << g_settings->getFloat("movement_speed_jump");
1479 pkt << g_settings->getFloat("movement_liquid_fluidity");
1480 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1481 pkt << g_settings->getFloat("movement_liquid_sink");
1482 pkt << g_settings->getFloat("movement_gravity");
1487 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1489 if (!g_settings->getBool("enable_damage"))
1492 u16 peer_id = playersao->getPeerID();
1493 bool is_alive = playersao->getHP() > 0;
1496 SendPlayerHP(peer_id);
1501 void Server::SendHP(u16 peer_id, u8 hp)
1503 DSTACK(FUNCTION_NAME);
1505 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1510 void Server::SendBreath(u16 peer_id, u16 breath)
1512 DSTACK(FUNCTION_NAME);
1514 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1515 pkt << (u16) breath;
1519 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1520 const std::string &custom_reason, bool reconnect)
1522 assert(reason < SERVER_ACCESSDENIED_MAX);
1524 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1526 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1527 pkt << custom_reason;
1528 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1529 reason == SERVER_ACCESSDENIED_CRASH)
1530 pkt << custom_reason << (u8)reconnect;
1534 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1536 DSTACK(FUNCTION_NAME);
1538 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1543 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1544 v3f camera_point_target)
1546 DSTACK(FUNCTION_NAME);
1548 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1549 pkt << set_camera_point_target << camera_point_target;
1553 void Server::SendItemDef(u16 peer_id,
1554 IItemDefManager *itemdef, u16 protocol_version)
1556 DSTACK(FUNCTION_NAME);
1558 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1562 u32 length of the next item
1563 zlib-compressed serialized ItemDefManager
1565 std::ostringstream tmp_os(std::ios::binary);
1566 itemdef->serialize(tmp_os, protocol_version);
1567 std::ostringstream tmp_os2(std::ios::binary);
1568 compressZlib(tmp_os.str(), tmp_os2);
1569 pkt.putLongString(tmp_os2.str());
1572 verbosestream << "Server: Sending item definitions to id(" << peer_id
1573 << "): size=" << pkt.getSize() << std::endl;
1578 void Server::SendNodeDef(u16 peer_id,
1579 INodeDefManager *nodedef, u16 protocol_version)
1581 DSTACK(FUNCTION_NAME);
1583 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1587 u32 length of the next item
1588 zlib-compressed serialized NodeDefManager
1590 std::ostringstream tmp_os(std::ios::binary);
1591 nodedef->serialize(tmp_os, protocol_version);
1592 std::ostringstream tmp_os2(std::ios::binary);
1593 compressZlib(tmp_os.str(), tmp_os2);
1595 pkt.putLongString(tmp_os2.str());
1598 verbosestream << "Server: Sending node definitions to id(" << peer_id
1599 << "): size=" << pkt.getSize() << std::endl;
1605 Non-static send methods
1608 void Server::SendInventory(PlayerSAO* playerSAO)
1610 DSTACK(FUNCTION_NAME);
1612 UpdateCrafting(playerSAO->getPlayer());
1618 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1620 std::ostringstream os;
1621 playerSAO->getInventory()->serialize(os);
1623 std::string s = os.str();
1625 pkt.putRawString(s.c_str(), s.size());
1629 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1631 DSTACK(FUNCTION_NAME);
1633 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1636 if (peer_id != PEER_ID_INEXISTENT) {
1640 m_clients.sendToAll(0, &pkt, true);
1644 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1645 const std::string &formname)
1647 DSTACK(FUNCTION_NAME);
1649 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1651 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1657 // Spawns a particle on peer with peer_id
1658 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1659 float expirationtime, float size, bool collisiondetection,
1660 bool collision_removal,
1661 bool vertical, const std::string &texture)
1663 DSTACK(FUNCTION_NAME);
1665 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1667 pkt << pos << velocity << acceleration << expirationtime
1668 << size << collisiondetection;
1669 pkt.putLongString(texture);
1671 pkt << collision_removal;
1673 if (peer_id != PEER_ID_INEXISTENT) {
1677 m_clients.sendToAll(0, &pkt, true);
1681 // Adds a ParticleSpawner on peer with peer_id
1682 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1683 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1684 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1685 u16 attached_id, bool vertical, const std::string &texture, u32 id)
1687 DSTACK(FUNCTION_NAME);
1689 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1691 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1692 << minacc << maxacc << minexptime << maxexptime << minsize
1693 << maxsize << collisiondetection;
1695 pkt.putLongString(texture);
1697 pkt << id << vertical;
1698 pkt << collision_removal;
1701 if (peer_id != PEER_ID_INEXISTENT) {
1705 m_clients.sendToAll(0, &pkt, true);
1709 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1711 DSTACK(FUNCTION_NAME);
1713 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1715 // Ugly error in this packet
1718 if (peer_id != PEER_ID_INEXISTENT) {
1722 m_clients.sendToAll(0, &pkt, true);
1727 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1729 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1731 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1732 << form->text << form->number << form->item << form->dir
1733 << form->align << form->offset << form->world_pos << form->size;
1738 void Server::SendHUDRemove(u16 peer_id, u32 id)
1740 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1745 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1747 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1748 pkt << id << (u8) stat;
1752 case HUD_STAT_SCALE:
1753 case HUD_STAT_ALIGN:
1754 case HUD_STAT_OFFSET:
1755 pkt << *(v2f *) value;
1759 pkt << *(std::string *) value;
1761 case HUD_STAT_WORLD_POS:
1762 pkt << *(v3f *) value;
1765 pkt << *(v2s32 *) value;
1767 case HUD_STAT_NUMBER:
1771 pkt << *(u32 *) value;
1778 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1780 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1782 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1784 pkt << flags << mask;
1789 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1791 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1792 pkt << param << value;
1796 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1797 const std::string &type, const std::vector<std::string> ¶ms)
1799 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1800 pkt << bgcolor << type << (u16) params.size();
1802 for(size_t i=0; i<params.size(); i++)
1808 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1811 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1814 pkt << do_override << (u16) (ratio * 65535);
1819 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1821 DSTACK(FUNCTION_NAME);
1823 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1824 pkt << time << time_speed;
1826 if (peer_id == PEER_ID_INEXISTENT) {
1827 m_clients.sendToAll(0, &pkt, true);
1834 void Server::SendPlayerHP(u16 peer_id)
1836 DSTACK(FUNCTION_NAME);
1837 PlayerSAO *playersao = getPlayerSAO(peer_id);
1838 // In some rare case if the player is disconnected
1839 // while Lua call l_punch, for example, this can be NULL
1843 SendHP(peer_id, playersao->getHP());
1844 m_script->player_event(playersao,"health_changed");
1846 // Send to other clients
1847 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1848 ActiveObjectMessage aom(playersao->getId(), true, str);
1849 playersao->m_messages_out.push(aom);
1852 void Server::SendPlayerBreath(u16 peer_id)
1854 DSTACK(FUNCTION_NAME);
1855 PlayerSAO *playersao = getPlayerSAO(peer_id);
1858 m_script->player_event(playersao, "breath_changed");
1859 SendBreath(peer_id, playersao->getBreath());
1862 void Server::SendMovePlayer(u16 peer_id)
1864 DSTACK(FUNCTION_NAME);
1865 RemotePlayer *player = m_env->getPlayer(peer_id);
1867 PlayerSAO *sao = player->getPlayerSAO();
1870 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1871 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1874 v3f pos = sao->getBasePosition();
1875 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1876 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1877 << " pitch=" << sao->getPitch()
1878 << " yaw=" << sao->getYaw()
1885 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1887 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1890 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1891 << animation_frames[3] << animation_speed;
1896 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1898 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1899 pkt << first << third;
1902 void Server::SendPlayerPrivileges(u16 peer_id)
1904 RemotePlayer *player = m_env->getPlayer(peer_id);
1906 if(player->peer_id == PEER_ID_INEXISTENT)
1909 std::set<std::string> privs;
1910 m_script->getAuth(player->getName(), NULL, &privs);
1912 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1913 pkt << (u16) privs.size();
1915 for(std::set<std::string>::const_iterator i = privs.begin();
1916 i != privs.end(); ++i) {
1923 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1925 RemotePlayer *player = m_env->getPlayer(peer_id);
1927 if(player->peer_id == PEER_ID_INEXISTENT)
1930 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1931 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1935 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1937 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1938 pkt.putRawString(datas.c_str(), datas.size());
1940 return pkt.getSize();
1943 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1945 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1946 datas.size(), peer_id);
1948 pkt.putRawString(datas.c_str(), datas.size());
1950 m_clients.send(pkt.getPeerId(),
1951 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1956 s32 Server::playSound(const SimpleSoundSpec &spec,
1957 const ServerSoundParams ¶ms)
1959 // Find out initial position of sound
1960 bool pos_exists = false;
1961 v3f pos = params.getPos(m_env, &pos_exists);
1962 // If position is not found while it should be, cancel sound
1963 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1966 // Filter destination clients
1967 std::vector<u16> dst_clients;
1968 if(params.to_player != "")
1970 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1972 infostream<<"Server::playSound: Player \""<<params.to_player
1973 <<"\" not found"<<std::endl;
1976 if(player->peer_id == PEER_ID_INEXISTENT){
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not connected"<<std::endl;
1981 dst_clients.push_back(player->peer_id);
1984 std::vector<u16> clients = m_clients.getClientIDs();
1986 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1987 RemotePlayer *player = m_env->getPlayer(*i);
1991 PlayerSAO *sao = player->getPlayerSAO();
1996 if(sao->getBasePosition().getDistanceFrom(pos) >
1997 params.max_hear_distance)
2000 dst_clients.push_back(*i);
2004 if(dst_clients.empty())
2008 s32 id = m_next_sound_id++;
2009 // The sound will exist as a reference in m_playing_sounds
2010 m_playing_sounds[id] = ServerPlayingSound();
2011 ServerPlayingSound &psound = m_playing_sounds[id];
2012 psound.params = params;
2014 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2015 pkt << id << spec.name << (float) (spec.gain * params.gain)
2016 << (u8) params.type << pos << params.object << params.loop;
2018 for(std::vector<u16>::iterator i = dst_clients.begin();
2019 i != dst_clients.end(); ++i) {
2020 psound.clients.insert(*i);
2021 m_clients.send(*i, 0, &pkt, true);
2025 void Server::stopSound(s32 handle)
2027 // Get sound reference
2028 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2029 if (i == m_playing_sounds.end())
2031 ServerPlayingSound &psound = i->second;
2033 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2036 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2037 i != psound.clients.end(); ++i) {
2039 m_clients.send(*i, 0, &pkt, true);
2041 // Remove sound reference
2042 m_playing_sounds.erase(i);
2045 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2046 std::vector<u16> *far_players, float far_d_nodes)
2048 float maxd = far_d_nodes*BS;
2049 v3f p_f = intToFloat(p, BS);
2051 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2054 std::vector<u16> clients = m_clients.getClientIDs();
2055 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2058 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2059 PlayerSAO *sao = player->getPlayerSAO();
2063 // If player is far away, only set modified blocks not sent
2064 v3f player_pos = sao->getBasePosition();
2065 if (player_pos.getDistanceFrom(p_f) > maxd) {
2066 far_players->push_back(*i);
2073 m_clients.send(*i, 0, &pkt, true);
2077 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2078 std::vector<u16> *far_players, float far_d_nodes,
2079 bool remove_metadata)
2081 float maxd = far_d_nodes*BS;
2082 v3f p_f = intToFloat(p, BS);
2084 std::vector<u16> clients = m_clients.getClientIDs();
2085 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2088 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2089 PlayerSAO *sao = player->getPlayerSAO();
2093 // If player is far away, only set modified blocks not sent
2094 v3f player_pos = sao->getBasePosition();
2095 if(player_pos.getDistanceFrom(p_f) > maxd) {
2096 far_players->push_back(*i);
2102 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2104 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2106 pkt << p << n.param0 << n.param1 << n.param2
2107 << (u8) (remove_metadata ? 0 : 1);
2109 if (!remove_metadata) {
2110 if (client->net_proto_version <= 21) {
2111 // Old clients always clear metadata; fix it
2112 // by sending the full block again.
2113 client->SetBlockNotSent(getNodeBlockPos(p));
2120 if (pkt.getSize() > 0)
2121 m_clients.send(*i, 0, &pkt, true);
2125 void Server::setBlockNotSent(v3s16 p)
2127 std::vector<u16> clients = m_clients.getClientIDs();
2129 for(std::vector<u16>::iterator i = clients.begin();
2130 i != clients.end(); ++i) {
2131 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2132 client->SetBlockNotSent(p);
2137 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2139 DSTACK(FUNCTION_NAME);
2141 v3s16 p = block->getPos();
2144 Create a packet with the block in the right format
2147 std::ostringstream os(std::ios_base::binary);
2148 block->serialize(os, ver, false);
2149 block->serializeNetworkSpecific(os, net_proto_version);
2150 std::string s = os.str();
2152 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2155 pkt.putRawString(s.c_str(), s.size());
2159 void Server::SendBlocks(float dtime)
2161 DSTACK(FUNCTION_NAME);
2163 MutexAutoLock envlock(m_env_mutex);
2164 //TODO check if one big lock could be faster then multiple small ones
2166 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2168 std::vector<PrioritySortedBlockTransfer> queue;
2170 s32 total_sending = 0;
2173 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2175 std::vector<u16> clients = m_clients.getClientIDs();
2178 for(std::vector<u16>::iterator i = clients.begin();
2179 i != clients.end(); ++i) {
2180 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2185 total_sending += client->SendingCount();
2186 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2192 // Lowest priority number comes first.
2193 // Lowest is most important.
2194 std::sort(queue.begin(), queue.end());
2197 for(u32 i=0; i<queue.size(); i++)
2199 //TODO: Calculate limit dynamically
2200 if(total_sending >= g_settings->getS32
2201 ("max_simultaneous_block_sends_server_total"))
2204 PrioritySortedBlockTransfer q = queue[i];
2206 MapBlock *block = NULL;
2209 block = m_env->getMap().getBlockNoCreate(q.pos);
2211 catch(InvalidPositionException &e)
2216 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2221 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2223 client->SentBlock(q.pos);
2229 void Server::fillMediaCache()
2231 DSTACK(FUNCTION_NAME);
2233 infostream<<"Server: Calculating media file checksums"<<std::endl;
2235 // Collect all media file paths
2236 std::vector<std::string> paths;
2237 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2238 i != m_mods.end(); ++i) {
2239 const ModSpec &mod = *i;
2240 paths.push_back(mod.path + DIR_DELIM + "textures");
2241 paths.push_back(mod.path + DIR_DELIM + "sounds");
2242 paths.push_back(mod.path + DIR_DELIM + "media");
2243 paths.push_back(mod.path + DIR_DELIM + "models");
2245 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2247 // Collect media file information from paths into cache
2248 for(std::vector<std::string>::iterator i = paths.begin();
2249 i != paths.end(); ++i) {
2250 std::string mediapath = *i;
2251 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2252 for (u32 j = 0; j < dirlist.size(); j++) {
2253 if (dirlist[j].dir) // Ignode dirs
2255 std::string filename = dirlist[j].name;
2256 // If name contains illegal characters, ignore the file
2257 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2258 infostream<<"Server: ignoring illegal file name: \""
2259 << filename << "\"" << std::endl;
2262 // If name is not in a supported format, ignore it
2263 const char *supported_ext[] = {
2264 ".png", ".jpg", ".bmp", ".tga",
2265 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2267 ".x", ".b3d", ".md2", ".obj",
2270 if (removeStringEnd(filename, supported_ext) == ""){
2271 infostream << "Server: ignoring unsupported file extension: \""
2272 << filename << "\"" << std::endl;
2275 // Ok, attempt to load the file and add to cache
2276 std::string filepath = mediapath + DIR_DELIM + filename;
2278 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2280 errorstream << "Server::fillMediaCache(): Could not open \""
2281 << filename << "\" for reading" << std::endl;
2284 std::ostringstream tmp_os(std::ios_base::binary);
2288 fis.read(buf, 1024);
2289 std::streamsize len = fis.gcount();
2290 tmp_os.write(buf, len);
2299 errorstream<<"Server::fillMediaCache(): Failed to read \""
2300 << filename << "\"" << std::endl;
2303 if(tmp_os.str().length() == 0) {
2304 errorstream << "Server::fillMediaCache(): Empty file \""
2305 << filepath << "\"" << std::endl;
2310 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2312 unsigned char *digest = sha1.getDigest();
2313 std::string sha1_base64 = base64_encode(digest, 20);
2314 std::string sha1_hex = hex_encode((char*)digest, 20);
2318 m_media[filename] = MediaInfo(filepath, sha1_base64);
2319 verbosestream << "Server: " << sha1_hex << " is " << filename
2325 void Server::sendMediaAnnouncement(u16 peer_id)
2327 DSTACK(FUNCTION_NAME);
2329 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2333 std::ostringstream os(std::ios_base::binary);
2335 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2336 pkt << (u16) m_media.size();
2338 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2339 i != m_media.end(); ++i) {
2340 pkt << i->first << i->second.sha1_digest;
2343 pkt << g_settings->get("remote_media");
2347 struct SendableMedia
2353 SendableMedia(const std::string &name_="", const std::string &path_="",
2354 const std::string &data_=""):
2361 void Server::sendRequestedMedia(u16 peer_id,
2362 const std::vector<std::string> &tosend)
2364 DSTACK(FUNCTION_NAME);
2366 verbosestream<<"Server::sendRequestedMedia(): "
2367 <<"Sending files to client"<<std::endl;
2371 // Put 5kB in one bunch (this is not accurate)
2372 u32 bytes_per_bunch = 5000;
2374 std::vector< std::vector<SendableMedia> > file_bunches;
2375 file_bunches.push_back(std::vector<SendableMedia>());
2377 u32 file_size_bunch_total = 0;
2379 for(std::vector<std::string>::const_iterator i = tosend.begin();
2380 i != tosend.end(); ++i) {
2381 const std::string &name = *i;
2383 if (m_media.find(name) == m_media.end()) {
2384 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2385 <<"unknown file \""<<(name)<<"\""<<std::endl;
2389 //TODO get path + name
2390 std::string tpath = m_media[name].path;
2393 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2394 if(fis.good() == false){
2395 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2396 <<tpath<<"\" for reading"<<std::endl;
2399 std::ostringstream tmp_os(std::ios_base::binary);
2403 fis.read(buf, 1024);
2404 std::streamsize len = fis.gcount();
2405 tmp_os.write(buf, len);
2406 file_size_bunch_total += len;
2415 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2416 <<name<<"\""<<std::endl;
2419 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2420 <<tname<<"\""<<std::endl;*/
2422 file_bunches[file_bunches.size()-1].push_back(
2423 SendableMedia(name, tpath, tmp_os.str()));
2425 // Start next bunch if got enough data
2426 if(file_size_bunch_total >= bytes_per_bunch) {
2427 file_bunches.push_back(std::vector<SendableMedia>());
2428 file_size_bunch_total = 0;
2433 /* Create and send packets */
2435 u16 num_bunches = file_bunches.size();
2436 for(u16 i = 0; i < num_bunches; i++) {
2439 u16 total number of texture bunches
2440 u16 index of this bunch
2441 u32 number of files in this bunch
2450 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2451 pkt << num_bunches << i << (u32) file_bunches[i].size();
2453 for(std::vector<SendableMedia>::iterator
2454 j = file_bunches[i].begin();
2455 j != file_bunches[i].end(); ++j) {
2457 pkt.putLongString(j->data);
2460 verbosestream << "Server::sendRequestedMedia(): bunch "
2461 << i << "/" << num_bunches
2462 << " files=" << file_bunches[i].size()
2463 << " size=" << pkt.getSize() << std::endl;
2468 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2470 if(m_detached_inventories.count(name) == 0) {
2471 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2474 Inventory *inv = m_detached_inventories[name];
2475 std::ostringstream os(std::ios_base::binary);
2477 os << serializeString(name);
2481 std::string s = os.str();
2483 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2484 pkt.putRawString(s.c_str(), s.size());
2486 if (peer_id != PEER_ID_INEXISTENT) {
2490 m_clients.sendToAll(0, &pkt, true);
2494 void Server::sendDetachedInventories(u16 peer_id)
2496 DSTACK(FUNCTION_NAME);
2498 for(std::map<std::string, Inventory*>::iterator
2499 i = m_detached_inventories.begin();
2500 i != m_detached_inventories.end(); ++i) {
2501 const std::string &name = i->first;
2502 //Inventory *inv = i->second;
2503 sendDetachedInventory(name, peer_id);
2511 void Server::DiePlayer(u16 peer_id)
2513 DSTACK(FUNCTION_NAME);
2514 PlayerSAO *playersao = getPlayerSAO(peer_id);
2515 // In some rare cases this can be NULL -- if the player is disconnected
2516 // when a Lua function modifies l_punch, for example
2520 infostream << "Server::DiePlayer(): Player "
2521 << playersao->getPlayer()->getName()
2522 << " dies" << std::endl;
2524 playersao->setHP(0);
2526 // Trigger scripted stuff
2527 m_script->on_dieplayer(playersao);
2529 SendPlayerHP(peer_id);
2530 SendDeathscreen(peer_id, false, v3f(0,0,0));
2533 void Server::RespawnPlayer(u16 peer_id)
2535 DSTACK(FUNCTION_NAME);
2537 PlayerSAO *playersao = getPlayerSAO(peer_id);
2540 infostream << "Server::RespawnPlayer(): Player "
2541 << playersao->getPlayer()->getName()
2542 << " respawns" << std::endl;
2544 playersao->setHP(PLAYER_MAX_HP);
2545 playersao->setBreath(PLAYER_MAX_BREATH);
2547 SendPlayerHP(peer_id);
2548 SendPlayerBreath(peer_id);
2550 bool repositioned = m_script->on_respawnplayer(playersao);
2552 v3f pos = findSpawnPos();
2553 // setPos will send the new position to client
2554 playersao->setPos(pos);
2559 void Server::DenySudoAccess(u16 peer_id)
2561 DSTACK(FUNCTION_NAME);
2563 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2568 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2569 const std::string &str_reason, bool reconnect)
2571 if (proto_ver >= 25) {
2572 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2574 std::wstring wreason = utf8_to_wide(
2575 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2576 accessDeniedStrings[(u8)reason]);
2577 SendAccessDenied_Legacy(peer_id, wreason);
2580 m_clients.event(peer_id, CSE_SetDenied);
2581 m_con.DisconnectPeer(peer_id);
2585 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2587 DSTACK(FUNCTION_NAME);
2589 SendAccessDenied(peer_id, reason, custom_reason);
2590 m_clients.event(peer_id, CSE_SetDenied);
2591 m_con.DisconnectPeer(peer_id);
2594 // 13/03/15: remove this function when protocol version 25 will become
2595 // the minimum version for MT users, maybe in 1 year
2596 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2598 DSTACK(FUNCTION_NAME);
2600 SendAccessDenied_Legacy(peer_id, reason);
2601 m_clients.event(peer_id, CSE_SetDenied);
2602 m_con.DisconnectPeer(peer_id);
2605 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2607 DSTACK(FUNCTION_NAME);
2610 RemoteClient* client = getClient(peer_id, CS_Invalid);
2612 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2614 // Right now, the auth mechs don't change between login and sudo mode.
2615 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2616 client->allowed_sudo_mechs = sudo_auth_mechs;
2618 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2619 << g_settings->getFloat("dedicated_server_step")
2623 m_clients.event(peer_id, CSE_AuthAccept);
2625 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2627 // We only support SRP right now
2628 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2630 resp_pkt << sudo_auth_mechs;
2632 m_clients.event(peer_id, CSE_SudoSuccess);
2636 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2638 DSTACK(FUNCTION_NAME);
2639 std::wstring message;
2642 Clear references to playing sounds
2644 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2645 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2646 ServerPlayingSound &psound = i->second;
2647 psound.clients.erase(peer_id);
2648 if (psound.clients.empty())
2649 m_playing_sounds.erase(i++);
2654 RemotePlayer *player = m_env->getPlayer(peer_id);
2656 /* Run scripts and remove from environment */
2657 if(player != NULL) {
2658 PlayerSAO *playersao = player->getPlayerSAO();
2661 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2663 playersao->disconnected();
2670 if(player != NULL && reason != CDR_DENY) {
2671 std::ostringstream os(std::ios_base::binary);
2672 std::vector<u16> clients = m_clients.getClientIDs();
2674 for(std::vector<u16>::iterator i = clients.begin();
2675 i != clients.end(); ++i) {
2677 RemotePlayer *player = m_env->getPlayer(*i);
2681 // Get name of player
2682 os << player->getName() << " ";
2685 std::string name = player->getName();
2686 actionstream << name << " "
2687 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2688 << " List of players: " << os.str() << std::endl;
2690 m_admin_chat->outgoing_queue.push_back(
2691 new ChatEventNick(CET_NICK_REMOVE, name));
2695 MutexAutoLock env_lock(m_env_mutex);
2696 m_clients.DeleteClient(peer_id);
2700 // Send leave chat message to all remaining clients
2701 if(message.length() != 0)
2702 SendChatMessage(PEER_ID_INEXISTENT,message);
2705 void Server::UpdateCrafting(RemotePlayer *player)
2707 DSTACK(FUNCTION_NAME);
2709 // Get a preview for crafting
2711 InventoryLocation loc;
2712 loc.setPlayer(player->getName());
2713 std::vector<ItemStack> output_replacements;
2714 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2715 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2716 (&player->inventory)->getList("craft"), loc);
2718 // Put the new preview in
2719 InventoryList *plist = player->inventory.getList("craftpreview");
2720 sanity_check(plist);
2721 sanity_check(plist->getSize() >= 1);
2722 plist->changeItem(0, preview);
2725 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2727 if (evt->type == CET_NICK_ADD) {
2728 // The terminal informed us of its nick choice
2729 m_admin_nick = ((ChatEventNick *)evt)->nick;
2730 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2731 errorstream << "You haven't set up an account." << std::endl
2732 << "Please log in using the client as '"
2733 << m_admin_nick << "' with a secure password." << std::endl
2734 << "Until then, you can't execute admin tasks via the console," << std::endl
2735 << "and everybody can claim the user account instead of you," << std::endl
2736 << "giving them full control over this server." << std::endl;
2739 assert(evt->type == CET_CHAT);
2740 handleAdminChat((ChatEventChat *)evt);
2744 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2745 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2747 // If something goes wrong, this player is to blame
2748 RollbackScopeActor rollback_scope(m_rollback,
2749 std::string("player:") + name);
2753 // Whether to send line to the player that sent the message, or to all players
2754 bool broadcast_line = true;
2757 bool ate = m_script->on_chat_message(name,
2758 wide_to_utf8(wmessage));
2759 // If script ate the message, don't proceed
2764 switch (player->canSendChatMessage()) {
2765 case RPLAYER_CHATRESULT_FLOODING: {
2766 std::wstringstream ws;
2767 ws << L"You cannot send more messages. You are limited to "
2768 << g_settings->getFloat("chat_message_limit_per_10sec")
2769 << L" messages per 10 seconds.";
2772 case RPLAYER_CHATRESULT_KICK:
2773 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2775 case RPLAYER_CHATRESULT_OK: break;
2776 default: FATAL_ERROR("Unhandled chat filtering result found.");
2780 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2781 return L"Your message exceed the maximum chat message limit set on the server. "
2782 L"It was refused. Send a shorter message";
2785 // Commands are implemented in Lua, so only catch invalid
2786 // commands that were not "eaten" and send an error back
2787 if (wmessage[0] == L'/') {
2788 std::wstring wcmd = wmessage.substr(1);
2789 broadcast_line = false;
2790 if (wcmd.length() == 0)
2791 line += L"-!- Empty command";
2793 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2795 if (check_shout_priv && !checkPriv(name, "shout")) {
2796 line += L"-!- You don't have permission to shout.";
2797 broadcast_line = false;
2807 Tell calling method to send the message to sender
2809 if (!broadcast_line) {
2813 Send the message to others
2815 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2817 std::vector<u16> clients = m_clients.getClientIDs();
2819 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2820 for (u16 i = 0; i < clients.size(); i++) {
2821 u16 cid = clients[i];
2822 if (cid != peer_id_to_avoid_sending)
2823 SendChatMessage(cid, line);
2829 void Server::handleAdminChat(const ChatEventChat *evt)
2831 std::string name = evt->nick;
2832 std::wstring wname = utf8_to_wide(name);
2833 std::wstring wmessage = evt->evt_msg;
2835 std::wstring answer = handleChat(name, wname, wmessage);
2837 // If asked to send answer to sender
2838 if (!answer.empty()) {
2839 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2843 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2845 RemoteClient *client = getClientNoEx(peer_id,state_min);
2847 throw ClientNotFoundException("Client not found");
2851 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2853 return m_clients.getClientNoEx(peer_id, state_min);
2856 std::string Server::getPlayerName(u16 peer_id)
2858 RemotePlayer *player = m_env->getPlayer(peer_id);
2860 return "[id="+itos(peer_id)+"]";
2861 return player->getName();
2864 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2866 RemotePlayer *player = m_env->getPlayer(peer_id);
2869 return player->getPlayerSAO();
2872 std::wstring Server::getStatusString()
2874 std::wostringstream os(std::ios_base::binary);
2877 os<<L"version="<<narrow_to_wide(g_version_string);
2879 os<<L", uptime="<<m_uptime.get();
2881 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2882 // Information about clients
2885 std::vector<u16> clients = m_clients.getClientIDs();
2886 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2888 RemotePlayer *player = m_env->getPlayer(*i);
2889 // Get name of player
2890 std::wstring name = L"unknown";
2892 name = narrow_to_wide(player->getName());
2893 // Add name to information string
2901 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2902 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2903 if(g_settings->get("motd") != "")
2904 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2908 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2910 std::set<std::string> privs;
2911 m_script->getAuth(name, NULL, &privs);
2915 bool Server::checkPriv(const std::string &name, const std::string &priv)
2917 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2918 return (privs.count(priv) != 0);
2921 void Server::reportPrivsModified(const std::string &name)
2924 std::vector<u16> clients = m_clients.getClientIDs();
2925 for(std::vector<u16>::iterator i = clients.begin();
2926 i != clients.end(); ++i) {
2927 RemotePlayer *player = m_env->getPlayer(*i);
2928 reportPrivsModified(player->getName());
2931 RemotePlayer *player = m_env->getPlayer(name.c_str());
2934 SendPlayerPrivileges(player->peer_id);
2935 PlayerSAO *sao = player->getPlayerSAO();
2938 sao->updatePrivileges(
2939 getPlayerEffectivePrivs(name),
2944 void Server::reportInventoryFormspecModified(const std::string &name)
2946 RemotePlayer *player = m_env->getPlayer(name.c_str());
2949 SendPlayerInventoryFormspec(player->peer_id);
2952 void Server::setIpBanned(const std::string &ip, const std::string &name)
2954 m_banmanager->add(ip, name);
2957 void Server::unsetIpBanned(const std::string &ip_or_name)
2959 m_banmanager->remove(ip_or_name);
2962 std::string Server::getBanDescription(const std::string &ip_or_name)
2964 return m_banmanager->getBanDescription(ip_or_name);
2967 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2969 // m_env will be NULL if the server is initializing
2973 if (m_admin_nick == name && !m_admin_nick.empty()) {
2974 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2977 RemotePlayer *player = m_env->getPlayer(name);
2982 if (player->peer_id == PEER_ID_INEXISTENT)
2985 SendChatMessage(player->peer_id, msg);
2988 bool Server::showFormspec(const char *playername, const std::string &formspec,
2989 const std::string &formname)
2991 // m_env will be NULL if the server is initializing
2995 RemotePlayer *player = m_env->getPlayer(playername);
2999 SendShowFormspecMessage(player->peer_id, formspec, formname);
3003 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3008 u32 id = player->addHud(form);
3010 SendHUDAdd(player->peer_id, id, form);
3015 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3019 HudElement* todel = player->removeHud(id);
3026 SendHUDRemove(player->peer_id, id);
3030 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3035 SendHUDChange(player->peer_id, id, stat, data);
3039 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3044 SendHUDSetFlags(player->peer_id, flags, mask);
3045 player->hud_flags &= ~mask;
3046 player->hud_flags |= flags;
3048 PlayerSAO* playersao = player->getPlayerSAO();
3050 if (playersao == NULL)
3053 m_script->player_event(playersao, "hud_changed");
3057 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3062 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3065 player->setHotbarItemcount(hotbar_itemcount);
3066 std::ostringstream os(std::ios::binary);
3067 writeS32(os, hotbar_itemcount);
3068 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3072 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3077 player->setHotbarImage(name);
3078 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3081 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3085 return player->getHotbarImage();
3088 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3093 player->setHotbarSelectedImage(name);
3094 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3097 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3098 v2s32 animation_frames[4], f32 frame_speed)
3103 player->setLocalAnimations(animation_frames, frame_speed);
3104 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3108 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3113 player->eye_offset_first = first;
3114 player->eye_offset_third = third;
3115 SendEyeOffset(player->peer_id, first, third);
3119 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3120 const std::string &type, const std::vector<std::string> ¶ms)
3125 player->setSky(bgcolor, type, params);
3126 SendSetSky(player->peer_id, bgcolor, type, params);
3130 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3136 player->overrideDayNightRatio(do_override, ratio);
3137 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3141 void Server::notifyPlayers(const std::wstring &msg)
3143 SendChatMessage(PEER_ID_INEXISTENT,msg);
3146 void Server::spawnParticle(const std::string &playername, v3f pos,
3147 v3f velocity, v3f acceleration,
3148 float expirationtime, float size, bool
3149 collisiondetection, bool collision_removal,
3150 bool vertical, const std::string &texture)
3152 // m_env will be NULL if the server is initializing
3156 u16 peer_id = PEER_ID_INEXISTENT;
3157 if (playername != "") {
3158 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3161 peer_id = player->peer_id;
3164 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3165 expirationtime, size, collisiondetection,
3166 collision_removal, vertical, texture);
3169 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3170 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3171 float minexptime, float maxexptime, float minsize, float maxsize,
3172 bool collisiondetection, bool collision_removal,
3173 ServerActiveObject *attached, bool vertical, const std::string &texture,
3174 const std::string &playername)
3176 // m_env will be NULL if the server is initializing
3180 u16 peer_id = PEER_ID_INEXISTENT;
3181 if (playername != "") {
3182 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3185 peer_id = player->peer_id;
3188 u16 attached_id = attached ? attached->getId() : 0;
3191 if (attached_id == 0)
3192 id = m_env->addParticleSpawner(spawntime);
3194 id = m_env->addParticleSpawner(spawntime, attached_id);
3196 SendAddParticleSpawner(peer_id, amount, spawntime,
3197 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3198 minexptime, maxexptime, minsize, maxsize,
3199 collisiondetection, collision_removal, attached_id, vertical,
3205 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3207 // m_env will be NULL if the server is initializing
3209 throw ServerError("Can't delete particle spawners during initialisation!");
3211 u16 peer_id = PEER_ID_INEXISTENT;
3212 if (playername != "") {
3213 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3216 peer_id = player->peer_id;
3219 m_env->deleteParticleSpawner(id);
3220 SendDeleteParticleSpawner(peer_id, id);
3223 Inventory* Server::createDetachedInventory(const std::string &name)
3225 if(m_detached_inventories.count(name) > 0){
3226 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3227 delete m_detached_inventories[name];
3229 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3231 Inventory *inv = new Inventory(m_itemdef);
3233 m_detached_inventories[name] = inv;
3234 //TODO find a better way to do this
3235 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3239 // actions: time-reversed list
3240 // Return value: success/failure
3241 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3242 std::list<std::string> *log)
3244 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3245 ServerMap *map = (ServerMap*)(&m_env->getMap());
3247 // Fail if no actions to handle
3248 if(actions.empty()){
3249 log->push_back("Nothing to do.");
3256 for(std::list<RollbackAction>::const_iterator
3257 i = actions.begin();
3258 i != actions.end(); ++i)
3260 const RollbackAction &action = *i;
3262 bool success = action.applyRevert(map, this, this);
3265 std::ostringstream os;
3266 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3267 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3269 log->push_back(os.str());
3271 std::ostringstream os;
3272 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3273 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3275 log->push_back(os.str());
3279 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3280 <<" failed"<<std::endl;
3282 // Call it done if less than half failed
3283 return num_failed <= num_tried/2;
3286 // IGameDef interface
3288 IItemDefManager *Server::getItemDefManager()
3293 INodeDefManager *Server::getNodeDefManager()
3298 ICraftDefManager *Server::getCraftDefManager()
3302 ITextureSource *Server::getTextureSource()
3306 IShaderSource *Server::getShaderSource()
3310 scene::ISceneManager *Server::getSceneManager()
3315 u16 Server::allocateUnknownNodeId(const std::string &name)
3317 return m_nodedef->allocateDummy(name);
3320 ISoundManager *Server::getSoundManager()
3322 return &dummySoundManager;
3325 MtEventManager *Server::getEventManager()
3330 IWritableItemDefManager *Server::getWritableItemDefManager()
3335 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3340 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3345 const ModSpec *Server::getModSpec(const std::string &modname) const
3347 std::vector<ModSpec>::const_iterator it;
3348 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3349 const ModSpec &mod = *it;
3350 if (mod.name == modname)
3356 void Server::getModNames(std::vector<std::string> &modlist)
3358 std::vector<ModSpec>::iterator it;
3359 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3360 modlist.push_back(it->name);
3363 std::string Server::getBuiltinLuaPath()
3365 return porting::path_share + DIR_DELIM + "builtin";
3368 v3f Server::findSpawnPos()
3370 ServerMap &map = m_env->getServerMap();
3372 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3373 return nodeposf * BS;
3376 bool is_good = false;
3378 // Try to find a good place a few times
3379 for(s32 i = 0; i < 4000 && !is_good; i++) {
3381 // We're going to try to throw the player to this position
3382 v2s16 nodepos2d = v2s16(
3383 -range + (myrand() % (range * 2)),
3384 -range + (myrand() % (range * 2)));
3386 // Get spawn level at point
3387 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3388 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3389 // the mapgen to signify an unsuitable spawn position
3390 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3393 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3396 for (s32 i = 0; i < 10; i++) {
3397 v3s16 blockpos = getNodeBlockPos(nodepos);
3398 map.emergeBlock(blockpos, true);
3399 content_t c = map.getNodeNoEx(nodepos).getContent();
3400 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3402 if (air_count >= 2) {
3403 nodeposf = intToFloat(nodepos, BS);
3404 // Don't spawn the player outside map boundaries
3405 if (objectpos_over_limit(nodeposf))
3418 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3420 bool newplayer = false;
3423 Try to get an existing player
3425 RemotePlayer *player = m_env->getPlayer(name);
3427 // If player is already connected, cancel
3428 if (player != NULL && player->peer_id != 0) {
3429 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3434 If player with the wanted peer_id already exists, cancel.
3436 if (m_env->getPlayer(peer_id) != NULL) {
3437 infostream<<"emergePlayer(): Player with wrong name but same"
3438 " peer_id already exists"<<std::endl;
3442 // Create a new player active object
3443 PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
3444 player = m_env->loadPlayer(name, playersao);
3446 // Create player if it doesn't exist
3449 player = new RemotePlayer(name, this->idef());
3450 // Set player position
3451 infostream<<"Server: Finding spawn place for player \""
3452 <<name<<"\""<<std::endl;
3453 playersao->setBasePosition(findSpawnPos());
3455 // Make sure the player is saved
3456 player->setModified(true);
3458 // Add player to environment
3459 m_env->addPlayer(player);
3461 // If the player exists, ensure that they respawn inside legal bounds
3462 // This fixes an assert crash when the player can't be added
3463 // to the environment
3464 if (objectpos_over_limit(playersao->getBasePosition())) {
3465 actionstream << "Respawn position for player \""
3466 << name << "\" outside limits, resetting" << std::endl;
3467 playersao->setBasePosition(findSpawnPos());
3471 playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
3473 player->protocol_version = proto_version;
3475 /* Clean up old HUD elements from previous sessions */
3478 /* Add object to environment */
3479 m_env->addActiveObject(playersao);
3483 m_script->on_newplayer(playersao);
3489 void dedicated_server_loop(Server &server, bool &kill)
3491 DSTACK(FUNCTION_NAME);
3493 verbosestream<<"dedicated_server_loop()"<<std::endl;
3495 IntervalLimiter m_profiler_interval;
3497 static const float steplen = g_settings->getFloat("dedicated_server_step");
3498 static const float profiler_print_interval =
3499 g_settings->getFloat("profiler_print_interval");
3502 // This is kind of a hack but can be done like this
3503 // because server.step() is very light
3505 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3506 sleep_ms((int)(steplen*1000.0));
3508 server.step(steplen);
3510 if(server.getShutdownRequested() || kill)
3512 infostream<<"Dedicated server quitting"<<std::endl;
3514 if(g_settings->getBool("server_announce"))
3515 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3523 if (profiler_print_interval != 0) {
3524 if(m_profiler_interval.step(steplen, profiler_print_interval))
3526 infostream<<"Profiler:"<<std::endl;
3527 g_profiler->print(infostream);
3528 g_profiler->clear();