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,
153 m_path_world(path_world),
154 m_gamespec(gamespec),
155 m_simple_singleplayer_mode(simple_singleplayer_mode),
156 m_async_fatal_error(""),
165 m_enable_rollback_recording(false),
168 m_itemdef(createItemDefManager()),
169 m_nodedef(createNodeDefManager()),
170 m_craftdef(createCraftDefManager()),
171 m_event(new EventManager()),
173 m_time_of_day_send_timer(0),
176 m_shutdown_requested(false),
177 m_shutdown_ask_reconnect(false),
178 m_ignore_map_edit_events(false),
179 m_ignore_map_edit_events_peer_id(0),
183 m_liquid_transform_timer = 0.0;
184 m_liquid_transform_every = 1.0;
185 m_print_info_timer = 0.0;
186 m_masterserver_timer = 0.0;
187 m_objectdata_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 // Load mapgen params from Settings
268 m_emerge->loadMapgenParams();
270 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
271 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
273 // Initialize scripting
274 infostream<<"Server: Initializing Lua"<<std::endl;
276 m_script = new GameScripting(this);
278 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
280 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
283 infostream << "Server: Loading mods: ";
284 for(std::vector<ModSpec>::iterator i = m_mods.begin();
285 i != m_mods.end(); ++i) {
286 const ModSpec &mod = *i;
287 infostream << mod.name << " ";
289 infostream << std::endl;
290 // Load and run "mod" scripts
291 for (std::vector<ModSpec>::iterator it = m_mods.begin();
292 it != m_mods.end(); ++it) {
293 const ModSpec &mod = *it;
294 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
295 throw ModError("Error loading mod \"" + mod.name +
296 "\": Mod name does not follow naming conventions: "
297 "Only chararacters [a-z0-9_] are allowed.");
299 std::string script_path = mod.path + DIR_DELIM + "init.lua";
300 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
301 << script_path << "\"]" << std::endl;
302 m_script->loadMod(script_path, mod.name);
305 // Read Textures and calculate sha1 sums
308 // Apply item aliases in the node definition manager
309 m_nodedef->updateAliases(m_itemdef);
311 // Apply texture overrides from texturepack/override.txt
312 std::string texture_path = g_settings->get("texture_path");
313 if (texture_path != "" && fs::IsDir(texture_path))
314 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
316 m_nodedef->setNodeRegistrationStatus(true);
318 // Perform pending node name resolutions
319 m_nodedef->runNodeResolveCallbacks();
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 // Initialize mapgens
330 m_emerge->initMapgens();
332 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
333 if (m_enable_rollback_recording) {
334 // Create rollback manager
335 m_rollback = new RollbackManager(m_path_world, this);
338 // Give environment reference to scripting api
339 m_script->initializeEnvironment(m_env);
341 // Register us to receive map edit events
342 servermap->addEventReceiver(this);
344 // If file exists, load environment metadata
345 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
347 infostream<<"Server: Loading environment metadata"<<std::endl;
351 // Add some test ActiveBlockModifiers to environment
352 add_legacy_abms(m_env, m_nodedef);
354 m_liquid_transform_every = g_settings->getFloat("liquid_update");
359 infostream<<"Server destructing"<<std::endl;
361 // Send shutdown message
362 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
365 MutexAutoLock envlock(m_env_mutex);
367 // Execute script shutdown hooks
368 m_script->on_shutdown();
370 infostream << "Server: Saving players" << std::endl;
371 m_env->saveLoadedPlayers();
373 infostream << "Server: Kicking players" << std::endl;
374 std::string kick_msg;
375 bool reconnect = false;
376 if (getShutdownRequested()) {
377 reconnect = m_shutdown_ask_reconnect;
378 kick_msg = m_shutdown_msg;
380 if (kick_msg == "") {
381 kick_msg = g_settings->get("kick_msg_shutdown");
383 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
384 kick_msg, reconnect);
386 infostream << "Server: Saving environment metadata" << std::endl;
394 // stop all emerge threads before deleting players that may have
395 // requested blocks to be emerged
396 m_emerge->stopThreads();
398 // Delete things in the reverse order of creation
401 // N.B. the EmergeManager should be deleted after the Environment since Map
402 // depends on EmergeManager to write its current params to the map meta
411 // Deinitialize scripting
412 infostream<<"Server: Deinitializing scripting"<<std::endl;
415 // Delete detached inventories
416 for (std::map<std::string, Inventory*>::iterator
417 i = m_detached_inventories.begin();
418 i != m_detached_inventories.end(); ++i) {
423 void Server::start(Address bind_addr)
425 DSTACK(FUNCTION_NAME);
427 m_bind_addr = bind_addr;
429 infostream<<"Starting server on "
430 << bind_addr.serializeString() <<"..."<<std::endl;
432 // Stop thread if already running
435 // Initialize connection
436 m_con.SetTimeoutMs(30);
437 m_con.Serve(bind_addr);
442 // ASCII art for the win!
444 <<" .__ __ __ "<<std::endl
445 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
446 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
447 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
448 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
449 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
450 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
451 actionstream<<"Server for gameid=\""<<m_gamespec.id
452 <<"\" listening on "<<bind_addr.serializeString()<<":"
453 <<bind_addr.getPort() << "."<<std::endl;
458 DSTACK(FUNCTION_NAME);
460 infostream<<"Server: Stopping and waiting threads"<<std::endl;
462 // Stop threads (set run=false first so both start stopping)
464 //m_emergethread.setRun(false);
466 //m_emergethread.stop();
468 infostream<<"Server: Threads stopped"<<std::endl;
471 void Server::step(float dtime)
473 DSTACK(FUNCTION_NAME);
478 MutexAutoLock lock(m_step_dtime_mutex);
479 m_step_dtime += dtime;
481 // Throw if fatal error occurred in thread
482 std::string async_err = m_async_fatal_error.get();
483 if (!async_err.empty()) {
484 if (!m_simple_singleplayer_mode) {
485 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
486 g_settings->get("kick_msg_crash"),
487 g_settings->getBool("ask_reconnect_on_crash"));
489 throw ServerError(async_err);
493 void Server::AsyncRunStep(bool initial_step)
495 DSTACK(FUNCTION_NAME);
497 g_profiler->add("Server::AsyncRunStep (num)", 1);
501 MutexAutoLock lock1(m_step_dtime_mutex);
502 dtime = m_step_dtime;
506 // Send blocks to clients
510 if((dtime < 0.001) && (initial_step == false))
513 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
515 //infostream<<"Server steps "<<dtime<<std::endl;
516 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
519 MutexAutoLock lock1(m_step_dtime_mutex);
520 m_step_dtime -= dtime;
527 m_uptime.set(m_uptime.get() + dtime);
533 Update time of day and overall game time
535 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
538 Send to clients at constant intervals
541 m_time_of_day_send_timer -= dtime;
542 if(m_time_of_day_send_timer < 0.0) {
543 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
544 u16 time = m_env->getTimeOfDay();
545 float time_speed = g_settings->getFloat("time_speed");
546 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
550 MutexAutoLock lock(m_env_mutex);
551 // Figure out and report maximum lag to environment
552 float max_lag = m_env->getMaxLagEstimate();
553 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
555 if(dtime > 0.1 && dtime > max_lag * 2.0)
556 infostream<<"Server: Maximum lag peaked to "<<dtime
560 m_env->reportMaxLagEstimate(max_lag);
562 ScopeProfiler sp(g_profiler, "SEnv step");
563 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
567 static const float map_timer_and_unload_dtime = 2.92;
568 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
570 MutexAutoLock lock(m_env_mutex);
571 // Run Map's timers and unload unused data
572 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
573 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
574 g_settings->getFloat("server_unload_unused_data_timeout"),
582 /* Transform liquids */
583 m_liquid_transform_timer += dtime;
584 if(m_liquid_transform_timer >= m_liquid_transform_every)
586 m_liquid_transform_timer -= m_liquid_transform_every;
588 MutexAutoLock lock(m_env_mutex);
590 ScopeProfiler sp(g_profiler, "Server: liquid transform");
592 std::map<v3s16, MapBlock*> modified_blocks;
593 m_env->getMap().transformLiquids(modified_blocks);
598 core::map<v3s16, MapBlock*> lighting_modified_blocks;
599 ServerMap &map = ((ServerMap&)m_env->getMap());
600 map.updateLighting(modified_blocks, lighting_modified_blocks);
602 // Add blocks modified by lighting to modified_blocks
603 for(core::map<v3s16, MapBlock*>::Iterator
604 i = lighting_modified_blocks.getIterator();
605 i.atEnd() == false; i++)
607 MapBlock *block = i.getNode()->getValue();
608 modified_blocks.insert(block->getPos(), block);
612 Set the modified blocks unsent for all the clients
614 if(!modified_blocks.empty())
616 SetBlocksNotSent(modified_blocks);
619 m_clients.step(dtime);
621 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
623 // send masterserver announce
625 float &counter = m_masterserver_timer;
626 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
627 g_settings->getBool("server_announce"))
629 ServerList::sendAnnounce(counter ? "update" : "start",
630 m_bind_addr.getPort(),
631 m_clients.getPlayerNames(),
633 m_env->getGameTime(),
636 m_emerge->params.mg_name,
645 Check added and deleted active objects
648 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
649 MutexAutoLock envlock(m_env_mutex);
652 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
653 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
655 // Radius inside which objects are active
656 s16 radius = g_settings->getS16("active_object_send_range_blocks");
657 s16 player_radius = g_settings->getS16("player_transfer_distance");
659 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
660 !g_settings->getBool("unlimited_player_transfer_distance"))
661 player_radius = radius;
663 radius *= MAP_BLOCKSIZE;
664 player_radius *= MAP_BLOCKSIZE;
666 for (std::map<u16, RemoteClient*>::iterator
668 i != clients.end(); ++i) {
669 RemoteClient *client = i->second;
671 // If definitions and textures have not been sent, don't
672 // send objects either
673 if (client->getState() < CS_DefinitionsSent)
676 Player *player = m_env->getPlayer(client->peer_id);
678 // This can happen if the client timeouts somehow
679 /*warningstream<<FUNCTION_NAME<<": Client "
681 <<" has no associated player"<<std::endl;*/
685 std::queue<u16> removed_objects;
686 std::queue<u16> added_objects;
687 m_env->getRemovedActiveObjects(player, radius, player_radius,
688 client->m_known_objects, removed_objects);
689 m_env->getAddedActiveObjects(player, radius, player_radius,
690 client->m_known_objects, added_objects);
692 // Ignore if nothing happened
693 if (removed_objects.empty() && added_objects.empty()) {
697 std::string data_buffer;
701 // Handle removed objects
702 writeU16((u8*)buf, removed_objects.size());
703 data_buffer.append(buf, 2);
704 while (!removed_objects.empty()) {
706 u16 id = removed_objects.front();
707 ServerActiveObject* obj = m_env->getActiveObject(id);
709 // Add to data buffer for sending
710 writeU16((u8*)buf, id);
711 data_buffer.append(buf, 2);
713 // Remove from known objects
714 client->m_known_objects.erase(id);
716 if(obj && obj->m_known_by_count > 0)
717 obj->m_known_by_count--;
718 removed_objects.pop();
721 // Handle added objects
722 writeU16((u8*)buf, added_objects.size());
723 data_buffer.append(buf, 2);
724 while (!added_objects.empty()) {
726 u16 id = added_objects.front();
727 ServerActiveObject* obj = m_env->getActiveObject(id);
730 u8 type = ACTIVEOBJECT_TYPE_INVALID;
732 warningstream<<FUNCTION_NAME
733 <<": NULL object"<<std::endl;
735 type = obj->getSendType();
737 // Add to data buffer for sending
738 writeU16((u8*)buf, id);
739 data_buffer.append(buf, 2);
740 writeU8((u8*)buf, type);
741 data_buffer.append(buf, 1);
744 data_buffer.append(serializeLongString(
745 obj->getClientInitializationData(client->net_proto_version)));
747 data_buffer.append(serializeLongString(""));
749 // Add to known objects
750 client->m_known_objects.insert(id);
753 obj->m_known_by_count++;
758 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
759 verbosestream << "Server: Sent object remove/add: "
760 << removed_objects.size() << " removed, "
761 << added_objects.size() << " added, "
762 << "packet size is " << pktSize << std::endl;
771 MutexAutoLock envlock(m_env_mutex);
772 ScopeProfiler sp(g_profiler, "Server: sending object messages");
775 // Value = data sent by object
776 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
778 // Get active object messages from environment
780 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
784 std::vector<ActiveObjectMessage>* message_list = NULL;
785 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
786 n = buffered_messages.find(aom.id);
787 if (n == buffered_messages.end()) {
788 message_list = new std::vector<ActiveObjectMessage>;
789 buffered_messages[aom.id] = message_list;
792 message_list = n->second;
794 message_list->push_back(aom);
798 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
799 // Route data to every client
800 for (std::map<u16, RemoteClient*>::iterator
802 i != clients.end(); ++i) {
803 RemoteClient *client = i->second;
804 std::string reliable_data;
805 std::string unreliable_data;
806 // Go through all objects in message buffer
807 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
808 j = buffered_messages.begin();
809 j != buffered_messages.end(); ++j) {
810 // If object is not known by client, skip it
812 if (client->m_known_objects.find(id) == client->m_known_objects.end())
815 // Get message list of object
816 std::vector<ActiveObjectMessage>* list = j->second;
817 // Go through every message
818 for (std::vector<ActiveObjectMessage>::iterator
819 k = list->begin(); k != list->end(); ++k) {
820 // Compose the full new data with header
821 ActiveObjectMessage aom = *k;
822 std::string new_data;
825 writeU16((u8*)&buf[0], aom.id);
826 new_data.append(buf, 2);
828 new_data += serializeString(aom.datastring);
829 // Add data to buffer
831 reliable_data += new_data;
833 unreliable_data += new_data;
837 reliable_data and unreliable_data are now ready.
840 if(reliable_data.size() > 0) {
841 SendActiveObjectMessages(client->peer_id, reliable_data);
844 if(unreliable_data.size() > 0) {
845 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
850 // Clear buffered_messages
851 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
852 i = buffered_messages.begin();
853 i != buffered_messages.end(); ++i) {
859 Send queued-for-sending map edit events.
862 // We will be accessing the environment
863 MutexAutoLock lock(m_env_mutex);
865 // Don't send too many at a time
868 // Single change sending is disabled if queue size is not small
869 bool disable_single_change_sending = false;
870 if(m_unsent_map_edit_queue.size() >= 4)
871 disable_single_change_sending = true;
873 int event_count = m_unsent_map_edit_queue.size();
875 // We'll log the amount of each
878 while(m_unsent_map_edit_queue.size() != 0)
880 MapEditEvent* event = m_unsent_map_edit_queue.front();
881 m_unsent_map_edit_queue.pop();
883 // Players far away from the change are stored here.
884 // Instead of sending the changes, MapBlocks are set not sent
886 std::vector<u16> far_players;
888 switch (event->type) {
891 prof.add("MEET_ADDNODE", 1);
892 sendAddNode(event->p, event->n, event->already_known_by_peer,
893 &far_players, disable_single_change_sending ? 5 : 30,
894 event->type == MEET_ADDNODE);
896 case MEET_REMOVENODE:
897 prof.add("MEET_REMOVENODE", 1);
898 sendRemoveNode(event->p, event->already_known_by_peer,
899 &far_players, disable_single_change_sending ? 5 : 30);
901 case MEET_BLOCK_NODE_METADATA_CHANGED:
902 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
903 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
904 setBlockNotSent(event->p);
907 infostream << "Server: MEET_OTHER" << std::endl;
908 prof.add("MEET_OTHER", 1);
909 for(std::set<v3s16>::iterator
910 i = event->modified_blocks.begin();
911 i != event->modified_blocks.end(); ++i) {
916 prof.add("unknown", 1);
917 warningstream << "Server: Unknown MapEditEvent "
918 << ((u32)event->type) << std::endl;
923 Set blocks not sent to far players
925 if(!far_players.empty()) {
926 // Convert list format to that wanted by SetBlocksNotSent
927 std::map<v3s16, MapBlock*> modified_blocks2;
928 for(std::set<v3s16>::iterator
929 i = event->modified_blocks.begin();
930 i != event->modified_blocks.end(); ++i) {
931 modified_blocks2[*i] =
932 m_env->getMap().getBlockNoCreateNoEx(*i);
935 // Set blocks not sent
936 for(std::vector<u16>::iterator
937 i = far_players.begin();
938 i != far_players.end(); ++i) {
939 if(RemoteClient *client = getClient(*i))
940 client->SetBlocksNotSent(modified_blocks2);
946 /*// Don't send too many at a time
948 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
952 if(event_count >= 5){
953 infostream<<"Server: MapEditEvents:"<<std::endl;
954 prof.print(infostream);
955 } else if(event_count != 0){
956 verbosestream<<"Server: MapEditEvents:"<<std::endl;
957 prof.print(verbosestream);
963 Trigger emergethread (it somehow gets to a non-triggered but
964 bysy state sometimes)
967 float &counter = m_emergethread_trigger_timer;
973 m_emerge->startThreads();
977 // Save map, players and auth stuff
979 float &counter = m_savemap_timer;
981 if(counter >= g_settings->getFloat("server_map_save_interval"))
984 MutexAutoLock lock(m_env_mutex);
986 ScopeProfiler sp(g_profiler, "Server: saving stuff");
989 if (m_banmanager->isModified()) {
990 m_banmanager->save();
993 // Save changed parts of map
994 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
997 m_env->saveLoadedPlayers();
999 // Save environment metadata
1005 void Server::Receive()
1007 DSTACK(FUNCTION_NAME);
1008 SharedBuffer<u8> data;
1012 m_con.Receive(&pkt);
1013 peer_id = pkt.getPeerId();
1016 catch(con::InvalidIncomingDataException &e) {
1017 infostream<<"Server::Receive(): "
1018 "InvalidIncomingDataException: what()="
1019 <<e.what()<<std::endl;
1021 catch(SerializationError &e) {
1022 infostream<<"Server::Receive(): "
1023 "SerializationError: what()="
1024 <<e.what()<<std::endl;
1026 catch(ClientStateError &e) {
1027 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1028 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1029 L"Try reconnecting or updating your client");
1031 catch(con::PeerNotFoundException &e) {
1036 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1038 std::string playername = "";
1039 PlayerSAO *playersao = NULL;
1042 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1043 if (client != NULL) {
1044 playername = client->getName();
1045 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1047 } catch (std::exception &e) {
1053 RemotePlayer *player =
1054 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1056 // If failed, cancel
1057 if ((playersao == NULL) || (player == NULL)) {
1058 if (player && player->peer_id != 0) {
1059 actionstream << "Server: Failed to emerge player \"" << playername
1060 << "\" (player allocated to an another client)" << std::endl;
1061 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1062 L"name. If your client closed unexpectedly, try again in "
1065 errorstream << "Server: " << playername << ": Failed to emerge player"
1067 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1073 Send complete position information
1075 SendMovePlayer(peer_id);
1078 SendPlayerPrivileges(peer_id);
1080 // Send inventory formspec
1081 SendPlayerInventoryFormspec(peer_id);
1084 SendInventory(playersao);
1087 SendPlayerHPOrDie(playersao);
1090 SendPlayerBreath(peer_id);
1092 // Show death screen if necessary
1093 if(player->isDead())
1094 SendDeathscreen(peer_id, false, v3f(0,0,0));
1096 // Note things in chat if not in simple singleplayer mode
1097 if(!m_simple_singleplayer_mode) {
1098 // Send information about server to player in chat
1099 SendChatMessage(peer_id, getStatusString());
1101 // Send information about joining in chat
1103 std::wstring name = L"unknown";
1104 Player *player = m_env->getPlayer(peer_id);
1106 name = narrow_to_wide(player->getName());
1108 std::wstring message;
1111 message += L" joined the game.";
1112 SendChatMessage(PEER_ID_INEXISTENT,message);
1115 Address addr = getPeerAddress(player->peer_id);
1116 std::string ip_str = addr.serializeString();
1117 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1122 std::vector<std::string> names = m_clients.getPlayerNames();
1124 actionstream<<player->getName() <<" joins game. List of players: ";
1126 for (std::vector<std::string>::iterator i = names.begin();
1127 i != names.end(); ++i) {
1128 actionstream << *i << " ";
1131 actionstream << player->getName() <<std::endl;
1136 inline void Server::handleCommand(NetworkPacket* pkt)
1138 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1139 (this->*opHandle.handler)(pkt);
1142 void Server::ProcessData(NetworkPacket *pkt)
1144 DSTACK(FUNCTION_NAME);
1145 // Environment is locked first.
1146 MutexAutoLock envlock(m_env_mutex);
1148 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1149 u32 peer_id = pkt->getPeerId();
1152 Address address = getPeerAddress(peer_id);
1153 std::string addr_s = address.serializeString();
1155 if(m_banmanager->isIpBanned(addr_s)) {
1156 std::string ban_name = m_banmanager->getBanName(addr_s);
1157 infostream << "Server: A banned client tried to connect from "
1158 << addr_s << "; banned name was "
1159 << ban_name << std::endl;
1160 // This actually doesn't seem to transfer to the client
1161 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1162 + utf8_to_wide(ban_name));
1166 catch(con::PeerNotFoundException &e) {
1168 * no peer for this packet found
1169 * most common reason is peer timeout, e.g. peer didn't
1170 * respond for some time, your server was overloaded or
1173 infostream << "Server::ProcessData(): Canceling: peer "
1174 << peer_id << " not found" << std::endl;
1179 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1181 // Command must be handled into ToServerCommandHandler
1182 if (command >= TOSERVER_NUM_MSG_TYPES) {
1183 infostream << "Server: Ignoring unknown command "
1184 << command << std::endl;
1188 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1193 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1195 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1196 errorstream << "Server::ProcessData(): Cancelling: Peer"
1197 " serialization format invalid or not initialized."
1198 " Skipping incoming command=" << command << std::endl;
1202 /* Handle commands related to client startup */
1203 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1208 if (m_clients.getClientState(peer_id) < CS_Active) {
1209 if (command == TOSERVER_PLAYERPOS) return;
1211 errorstream << "Got packet command: " << command << " for peer id "
1212 << peer_id << " but client isn't active yet. Dropping packet "
1218 } catch (SendFailedException &e) {
1219 errorstream << "Server::ProcessData(): SendFailedException: "
1220 << "what=" << e.what()
1222 } catch (PacketError &e) {
1223 actionstream << "Server::ProcessData(): PacketError: "
1224 << "what=" << e.what()
1229 void Server::setTimeOfDay(u32 time)
1231 m_env->setTimeOfDay(time);
1232 m_time_of_day_send_timer = 0;
1235 u32 Server::getTimeOfDay()
1237 return m_env->getTimeOfDay();
1240 void Server::onMapEditEvent(MapEditEvent *event)
1242 if(m_ignore_map_edit_events)
1244 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1246 MapEditEvent *e = event->clone();
1247 m_unsent_map_edit_queue.push(e);
1250 Inventory* Server::getInventory(const InventoryLocation &loc)
1253 case InventoryLocation::UNDEFINED:
1254 case InventoryLocation::CURRENT_PLAYER:
1256 case InventoryLocation::PLAYER:
1258 Player *player = m_env->getPlayer(loc.name.c_str());
1261 PlayerSAO *playersao = player->getPlayerSAO();
1264 return playersao->getInventory();
1267 case InventoryLocation::NODEMETA:
1269 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1272 return meta->getInventory();
1275 case InventoryLocation::DETACHED:
1277 if(m_detached_inventories.count(loc.name) == 0)
1279 return m_detached_inventories[loc.name];
1283 sanity_check(false); // abort
1288 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1291 case InventoryLocation::UNDEFINED:
1293 case InventoryLocation::PLAYER:
1298 Player *player = m_env->getPlayer(loc.name.c_str());
1301 PlayerSAO *playersao = player->getPlayerSAO();
1305 SendInventory(playersao);
1308 case InventoryLocation::NODEMETA:
1310 v3s16 blockpos = getNodeBlockPos(loc.p);
1312 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1314 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1316 setBlockNotSent(blockpos);
1319 case InventoryLocation::DETACHED:
1321 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1325 sanity_check(false); // abort
1330 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1332 std::vector<u16> clients = m_clients.getClientIDs();
1334 // Set the modified blocks unsent for all the clients
1335 for (std::vector<u16>::iterator i = clients.begin();
1336 i != clients.end(); ++i) {
1337 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1338 client->SetBlocksNotSent(block);
1343 void Server::peerAdded(con::Peer *peer)
1345 DSTACK(FUNCTION_NAME);
1346 verbosestream<<"Server::peerAdded(): peer->id="
1347 <<peer->id<<std::endl;
1350 c.type = con::PEER_ADDED;
1351 c.peer_id = peer->id;
1353 m_peer_change_queue.push(c);
1356 void Server::deletingPeer(con::Peer *peer, bool timeout)
1358 DSTACK(FUNCTION_NAME);
1359 verbosestream<<"Server::deletingPeer(): peer->id="
1360 <<peer->id<<", timeout="<<timeout<<std::endl;
1362 m_clients.event(peer->id, CSE_Disconnect);
1364 c.type = con::PEER_REMOVED;
1365 c.peer_id = peer->id;
1366 c.timeout = timeout;
1367 m_peer_change_queue.push(c);
1370 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1372 *retval = m_con.getPeerStat(peer_id,type);
1373 if (*retval == -1) return false;
1377 bool Server::getClientInfo(
1386 std::string* vers_string
1389 *state = m_clients.getClientState(peer_id);
1391 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1393 if (client == NULL) {
1398 *uptime = client->uptime();
1399 *ser_vers = client->serialization_version;
1400 *prot_vers = client->net_proto_version;
1402 *major = client->getMajor();
1403 *minor = client->getMinor();
1404 *patch = client->getPatch();
1405 *vers_string = client->getPatch();
1412 void Server::handlePeerChanges()
1414 while(m_peer_change_queue.size() > 0)
1416 con::PeerChange c = m_peer_change_queue.front();
1417 m_peer_change_queue.pop();
1419 verbosestream<<"Server: Handling peer change: "
1420 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1425 case con::PEER_ADDED:
1426 m_clients.CreateClient(c.peer_id);
1429 case con::PEER_REMOVED:
1430 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1434 FATAL_ERROR("Invalid peer change event received!");
1440 void Server::Send(NetworkPacket* pkt)
1442 m_clients.send(pkt->getPeerId(),
1443 clientCommandFactoryTable[pkt->getCommand()].channel,
1445 clientCommandFactoryTable[pkt->getCommand()].reliable);
1448 void Server::SendMovement(u16 peer_id)
1450 DSTACK(FUNCTION_NAME);
1451 std::ostringstream os(std::ios_base::binary);
1453 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1455 pkt << g_settings->getFloat("movement_acceleration_default");
1456 pkt << g_settings->getFloat("movement_acceleration_air");
1457 pkt << g_settings->getFloat("movement_acceleration_fast");
1458 pkt << g_settings->getFloat("movement_speed_walk");
1459 pkt << g_settings->getFloat("movement_speed_crouch");
1460 pkt << g_settings->getFloat("movement_speed_fast");
1461 pkt << g_settings->getFloat("movement_speed_climb");
1462 pkt << g_settings->getFloat("movement_speed_jump");
1463 pkt << g_settings->getFloat("movement_liquid_fluidity");
1464 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1465 pkt << g_settings->getFloat("movement_liquid_sink");
1466 pkt << g_settings->getFloat("movement_gravity");
1471 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1473 if (!g_settings->getBool("enable_damage"))
1476 u16 peer_id = playersao->getPeerID();
1477 bool is_alive = playersao->getHP() > 0;
1480 SendPlayerHP(peer_id);
1485 void Server::SendHP(u16 peer_id, u8 hp)
1487 DSTACK(FUNCTION_NAME);
1489 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1494 void Server::SendBreath(u16 peer_id, u16 breath)
1496 DSTACK(FUNCTION_NAME);
1498 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1499 pkt << (u16) breath;
1503 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1504 const std::string &custom_reason, bool reconnect)
1506 assert(reason < SERVER_ACCESSDENIED_MAX);
1508 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1510 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1511 pkt << custom_reason;
1512 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1513 reason == SERVER_ACCESSDENIED_CRASH)
1514 pkt << custom_reason << (u8)reconnect;
1518 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1520 DSTACK(FUNCTION_NAME);
1522 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1527 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1528 v3f camera_point_target)
1530 DSTACK(FUNCTION_NAME);
1532 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1533 pkt << set_camera_point_target << camera_point_target;
1537 void Server::SendItemDef(u16 peer_id,
1538 IItemDefManager *itemdef, u16 protocol_version)
1540 DSTACK(FUNCTION_NAME);
1542 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1546 u32 length of the next item
1547 zlib-compressed serialized ItemDefManager
1549 std::ostringstream tmp_os(std::ios::binary);
1550 itemdef->serialize(tmp_os, protocol_version);
1551 std::ostringstream tmp_os2(std::ios::binary);
1552 compressZlib(tmp_os.str(), tmp_os2);
1553 pkt.putLongString(tmp_os2.str());
1556 verbosestream << "Server: Sending item definitions to id(" << peer_id
1557 << "): size=" << pkt.getSize() << std::endl;
1562 void Server::SendNodeDef(u16 peer_id,
1563 INodeDefManager *nodedef, u16 protocol_version)
1565 DSTACK(FUNCTION_NAME);
1567 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1571 u32 length of the next item
1572 zlib-compressed serialized NodeDefManager
1574 std::ostringstream tmp_os(std::ios::binary);
1575 nodedef->serialize(tmp_os, protocol_version);
1576 std::ostringstream tmp_os2(std::ios::binary);
1577 compressZlib(tmp_os.str(), tmp_os2);
1579 pkt.putLongString(tmp_os2.str());
1582 verbosestream << "Server: Sending node definitions to id(" << peer_id
1583 << "): size=" << pkt.getSize() << std::endl;
1589 Non-static send methods
1592 void Server::SendInventory(PlayerSAO* playerSAO)
1594 DSTACK(FUNCTION_NAME);
1596 UpdateCrafting(playerSAO->getPlayer());
1602 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1604 std::ostringstream os;
1605 playerSAO->getInventory()->serialize(os);
1607 std::string s = os.str();
1609 pkt.putRawString(s.c_str(), s.size());
1613 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1615 DSTACK(FUNCTION_NAME);
1617 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1620 if (peer_id != PEER_ID_INEXISTENT) {
1624 m_clients.sendToAll(0, &pkt, true);
1628 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1629 const std::string &formname)
1631 DSTACK(FUNCTION_NAME);
1633 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1635 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1641 // Spawns a particle on peer with peer_id
1642 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1643 float expirationtime, float size, bool collisiondetection,
1644 bool vertical, std::string texture)
1646 DSTACK(FUNCTION_NAME);
1648 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1650 pkt << pos << velocity << acceleration << expirationtime
1651 << size << collisiondetection;
1652 pkt.putLongString(texture);
1655 if (peer_id != PEER_ID_INEXISTENT) {
1659 m_clients.sendToAll(0, &pkt, true);
1663 // Adds a ParticleSpawner on peer with peer_id
1664 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1665 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1666 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1668 DSTACK(FUNCTION_NAME);
1670 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1672 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1673 << minacc << maxacc << minexptime << maxexptime << minsize
1674 << maxsize << collisiondetection;
1676 pkt.putLongString(texture);
1678 pkt << id << vertical;
1680 if (peer_id != PEER_ID_INEXISTENT) {
1684 m_clients.sendToAll(0, &pkt, true);
1688 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1690 DSTACK(FUNCTION_NAME);
1692 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1694 // Ugly error in this packet
1697 if (peer_id != PEER_ID_INEXISTENT) {
1701 m_clients.sendToAll(0, &pkt, true);
1706 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1708 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1710 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1711 << form->text << form->number << form->item << form->dir
1712 << form->align << form->offset << form->world_pos << form->size;
1717 void Server::SendHUDRemove(u16 peer_id, u32 id)
1719 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1724 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1726 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1727 pkt << id << (u8) stat;
1731 case HUD_STAT_SCALE:
1732 case HUD_STAT_ALIGN:
1733 case HUD_STAT_OFFSET:
1734 pkt << *(v2f *) value;
1738 pkt << *(std::string *) value;
1740 case HUD_STAT_WORLD_POS:
1741 pkt << *(v3f *) value;
1744 pkt << *(v2s32 *) value;
1746 case HUD_STAT_NUMBER:
1750 pkt << *(u32 *) value;
1757 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1759 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1761 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1763 pkt << flags << mask;
1768 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1770 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1771 pkt << param << value;
1775 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1776 const std::string &type, const std::vector<std::string> ¶ms)
1778 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1779 pkt << bgcolor << type << (u16) params.size();
1781 for(size_t i=0; i<params.size(); i++)
1787 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1790 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1793 pkt << do_override << (u16) (ratio * 65535);
1798 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1800 DSTACK(FUNCTION_NAME);
1802 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1803 pkt << time << time_speed;
1805 if (peer_id == PEER_ID_INEXISTENT) {
1806 m_clients.sendToAll(0, &pkt, true);
1813 void Server::SendPlayerHP(u16 peer_id)
1815 DSTACK(FUNCTION_NAME);
1816 PlayerSAO *playersao = getPlayerSAO(peer_id);
1817 // In some rare case, if the player is disconnected
1818 // while Lua call l_punch, for example, this can be NULL
1822 SendHP(peer_id, playersao->getHP());
1823 m_script->player_event(playersao,"health_changed");
1825 // Send to other clients
1826 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1827 ActiveObjectMessage aom(playersao->getId(), true, str);
1828 playersao->m_messages_out.push(aom);
1831 void Server::SendPlayerBreath(u16 peer_id)
1833 DSTACK(FUNCTION_NAME);
1834 PlayerSAO *playersao = getPlayerSAO(peer_id);
1837 m_script->player_event(playersao, "breath_changed");
1838 SendBreath(peer_id, playersao->getBreath());
1841 void Server::SendMovePlayer(u16 peer_id)
1843 DSTACK(FUNCTION_NAME);
1844 Player *player = m_env->getPlayer(peer_id);
1847 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1848 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1851 v3f pos = player->getPosition();
1852 f32 pitch = player->getPitch();
1853 f32 yaw = player->getYaw();
1854 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1855 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1856 << " pitch=" << pitch
1864 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1866 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1869 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1870 << animation_frames[3] << animation_speed;
1875 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1877 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1878 pkt << first << third;
1881 void Server::SendPlayerPrivileges(u16 peer_id)
1883 Player *player = m_env->getPlayer(peer_id);
1885 if(player->peer_id == PEER_ID_INEXISTENT)
1888 std::set<std::string> privs;
1889 m_script->getAuth(player->getName(), NULL, &privs);
1891 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1892 pkt << (u16) privs.size();
1894 for(std::set<std::string>::const_iterator i = privs.begin();
1895 i != privs.end(); ++i) {
1902 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1904 Player *player = m_env->getPlayer(peer_id);
1906 if(player->peer_id == PEER_ID_INEXISTENT)
1909 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1910 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1914 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1916 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1917 pkt.putRawString(datas.c_str(), datas.size());
1919 return pkt.getSize();
1922 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1924 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1925 datas.size(), peer_id);
1927 pkt.putRawString(datas.c_str(), datas.size());
1929 m_clients.send(pkt.getPeerId(),
1930 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1935 s32 Server::playSound(const SimpleSoundSpec &spec,
1936 const ServerSoundParams ¶ms)
1938 // Find out initial position of sound
1939 bool pos_exists = false;
1940 v3f pos = params.getPos(m_env, &pos_exists);
1941 // If position is not found while it should be, cancel sound
1942 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1945 // Filter destination clients
1946 std::vector<u16> dst_clients;
1947 if(params.to_player != "")
1949 Player *player = m_env->getPlayer(params.to_player.c_str());
1951 infostream<<"Server::playSound: Player \""<<params.to_player
1952 <<"\" not found"<<std::endl;
1955 if(player->peer_id == PEER_ID_INEXISTENT){
1956 infostream<<"Server::playSound: Player \""<<params.to_player
1957 <<"\" not connected"<<std::endl;
1960 dst_clients.push_back(player->peer_id);
1963 std::vector<u16> clients = m_clients.getClientIDs();
1965 for(std::vector<u16>::iterator
1966 i = clients.begin(); i != clients.end(); ++i) {
1967 Player *player = m_env->getPlayer(*i);
1972 if(player->getPosition().getDistanceFrom(pos) >
1973 params.max_hear_distance)
1976 dst_clients.push_back(*i);
1980 if(dst_clients.empty())
1984 s32 id = m_next_sound_id++;
1985 // The sound will exist as a reference in m_playing_sounds
1986 m_playing_sounds[id] = ServerPlayingSound();
1987 ServerPlayingSound &psound = m_playing_sounds[id];
1988 psound.params = params;
1990 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1991 pkt << id << spec.name << (float) (spec.gain * params.gain)
1992 << (u8) params.type << pos << params.object << params.loop;
1994 for(std::vector<u16>::iterator i = dst_clients.begin();
1995 i != dst_clients.end(); ++i) {
1996 psound.clients.insert(*i);
1997 m_clients.send(*i, 0, &pkt, true);
2001 void Server::stopSound(s32 handle)
2003 // Get sound reference
2004 std::map<s32, ServerPlayingSound>::iterator i =
2005 m_playing_sounds.find(handle);
2006 if(i == m_playing_sounds.end())
2008 ServerPlayingSound &psound = i->second;
2010 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2013 for(std::set<u16>::iterator i = psound.clients.begin();
2014 i != psound.clients.end(); ++i) {
2016 m_clients.send(*i, 0, &pkt, true);
2018 // Remove sound reference
2019 m_playing_sounds.erase(i);
2022 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2023 std::vector<u16> *far_players, float far_d_nodes)
2025 float maxd = far_d_nodes*BS;
2026 v3f p_f = intToFloat(p, BS);
2028 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2031 std::vector<u16> clients = m_clients.getClientIDs();
2032 for(std::vector<u16>::iterator i = clients.begin();
2033 i != clients.end(); ++i) {
2036 if(Player *player = m_env->getPlayer(*i)) {
2037 // If player is far away, only set modified blocks not sent
2038 v3f player_pos = player->getPosition();
2039 if(player_pos.getDistanceFrom(p_f) > maxd) {
2040 far_players->push_back(*i);
2047 m_clients.send(*i, 0, &pkt, true);
2051 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2052 std::vector<u16> *far_players, float far_d_nodes,
2053 bool remove_metadata)
2055 float maxd = far_d_nodes*BS;
2056 v3f p_f = intToFloat(p, BS);
2058 std::vector<u16> clients = m_clients.getClientIDs();
2059 for(std::vector<u16>::iterator i = clients.begin();
2060 i != clients.end(); ++i) {
2064 if(Player *player = m_env->getPlayer(*i)) {
2065 // If player is far away, only set modified blocks not sent
2066 v3f player_pos = player->getPosition();
2067 if(player_pos.getDistanceFrom(p_f) > maxd) {
2068 far_players->push_back(*i);
2074 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2076 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2078 pkt << p << n.param0 << n.param1 << n.param2
2079 << (u8) (remove_metadata ? 0 : 1);
2081 if (!remove_metadata) {
2082 if (client->net_proto_version <= 21) {
2083 // Old clients always clear metadata; fix it
2084 // by sending the full block again.
2085 client->SetBlockNotSent(getNodeBlockPos(p));
2092 if (pkt.getSize() > 0)
2093 m_clients.send(*i, 0, &pkt, true);
2097 void Server::setBlockNotSent(v3s16 p)
2099 std::vector<u16> clients = m_clients.getClientIDs();
2101 for(std::vector<u16>::iterator i = clients.begin();
2102 i != clients.end(); ++i) {
2103 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2104 client->SetBlockNotSent(p);
2109 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2111 DSTACK(FUNCTION_NAME);
2113 v3s16 p = block->getPos();
2116 Create a packet with the block in the right format
2119 std::ostringstream os(std::ios_base::binary);
2120 block->serialize(os, ver, false);
2121 block->serializeNetworkSpecific(os, net_proto_version);
2122 std::string s = os.str();
2124 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2127 pkt.putRawString(s.c_str(), s.size());
2131 void Server::SendBlocks(float dtime)
2133 DSTACK(FUNCTION_NAME);
2135 MutexAutoLock envlock(m_env_mutex);
2136 //TODO check if one big lock could be faster then multiple small ones
2138 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2140 std::vector<PrioritySortedBlockTransfer> queue;
2142 s32 total_sending = 0;
2145 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2147 std::vector<u16> clients = m_clients.getClientIDs();
2150 for(std::vector<u16>::iterator i = clients.begin();
2151 i != clients.end(); ++i) {
2152 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2157 total_sending += client->SendingCount();
2158 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2164 // Lowest priority number comes first.
2165 // Lowest is most important.
2166 std::sort(queue.begin(), queue.end());
2169 for(u32 i=0; i<queue.size(); i++)
2171 //TODO: Calculate limit dynamically
2172 if(total_sending >= g_settings->getS32
2173 ("max_simultaneous_block_sends_server_total"))
2176 PrioritySortedBlockTransfer q = queue[i];
2178 MapBlock *block = NULL;
2181 block = m_env->getMap().getBlockNoCreate(q.pos);
2183 catch(InvalidPositionException &e)
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2193 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2195 client->SentBlock(q.pos);
2201 void Server::fillMediaCache()
2203 DSTACK(FUNCTION_NAME);
2205 infostream<<"Server: Calculating media file checksums"<<std::endl;
2207 // Collect all media file paths
2208 std::vector<std::string> paths;
2209 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2210 i != m_mods.end(); ++i) {
2211 const ModSpec &mod = *i;
2212 paths.push_back(mod.path + DIR_DELIM + "textures");
2213 paths.push_back(mod.path + DIR_DELIM + "sounds");
2214 paths.push_back(mod.path + DIR_DELIM + "media");
2215 paths.push_back(mod.path + DIR_DELIM + "models");
2217 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2219 // Collect media file information from paths into cache
2220 for(std::vector<std::string>::iterator i = paths.begin();
2221 i != paths.end(); ++i) {
2222 std::string mediapath = *i;
2223 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2224 for (u32 j = 0; j < dirlist.size(); j++) {
2225 if (dirlist[j].dir) // Ignode dirs
2227 std::string filename = dirlist[j].name;
2228 // If name contains illegal characters, ignore the file
2229 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2230 infostream<<"Server: ignoring illegal file name: \""
2231 << filename << "\"" << std::endl;
2234 // If name is not in a supported format, ignore it
2235 const char *supported_ext[] = {
2236 ".png", ".jpg", ".bmp", ".tga",
2237 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2239 ".x", ".b3d", ".md2", ".obj",
2242 if (removeStringEnd(filename, supported_ext) == ""){
2243 infostream << "Server: ignoring unsupported file extension: \""
2244 << filename << "\"" << std::endl;
2247 // Ok, attempt to load the file and add to cache
2248 std::string filepath = mediapath + DIR_DELIM + filename;
2250 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2252 errorstream << "Server::fillMediaCache(): Could not open \""
2253 << filename << "\" for reading" << std::endl;
2256 std::ostringstream tmp_os(std::ios_base::binary);
2260 fis.read(buf, 1024);
2261 std::streamsize len = fis.gcount();
2262 tmp_os.write(buf, len);
2271 errorstream<<"Server::fillMediaCache(): Failed to read \""
2272 << filename << "\"" << std::endl;
2275 if(tmp_os.str().length() == 0) {
2276 errorstream << "Server::fillMediaCache(): Empty file \""
2277 << filepath << "\"" << std::endl;
2282 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2284 unsigned char *digest = sha1.getDigest();
2285 std::string sha1_base64 = base64_encode(digest, 20);
2286 std::string sha1_hex = hex_encode((char*)digest, 20);
2290 m_media[filename] = MediaInfo(filepath, sha1_base64);
2291 verbosestream << "Server: " << sha1_hex << " is " << filename
2297 void Server::sendMediaAnnouncement(u16 peer_id)
2299 DSTACK(FUNCTION_NAME);
2301 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2305 std::ostringstream os(std::ios_base::binary);
2307 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2308 pkt << (u16) m_media.size();
2310 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2311 i != m_media.end(); ++i) {
2312 pkt << i->first << i->second.sha1_digest;
2315 pkt << g_settings->get("remote_media");
2319 struct SendableMedia
2325 SendableMedia(const std::string &name_="", const std::string &path_="",
2326 const std::string &data_=""):
2333 void Server::sendRequestedMedia(u16 peer_id,
2334 const std::vector<std::string> &tosend)
2336 DSTACK(FUNCTION_NAME);
2338 verbosestream<<"Server::sendRequestedMedia(): "
2339 <<"Sending files to client"<<std::endl;
2343 // Put 5kB in one bunch (this is not accurate)
2344 u32 bytes_per_bunch = 5000;
2346 std::vector< std::vector<SendableMedia> > file_bunches;
2347 file_bunches.push_back(std::vector<SendableMedia>());
2349 u32 file_size_bunch_total = 0;
2351 for(std::vector<std::string>::const_iterator i = tosend.begin();
2352 i != tosend.end(); ++i) {
2353 const std::string &name = *i;
2355 if(m_media.find(name) == m_media.end()) {
2356 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2357 <<"unknown file \""<<(name)<<"\""<<std::endl;
2361 //TODO get path + name
2362 std::string tpath = m_media[name].path;
2365 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2366 if(fis.good() == false){
2367 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2368 <<tpath<<"\" for reading"<<std::endl;
2371 std::ostringstream tmp_os(std::ios_base::binary);
2375 fis.read(buf, 1024);
2376 std::streamsize len = fis.gcount();
2377 tmp_os.write(buf, len);
2378 file_size_bunch_total += len;
2387 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2388 <<name<<"\""<<std::endl;
2391 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2392 <<tname<<"\""<<std::endl;*/
2394 file_bunches[file_bunches.size()-1].push_back(
2395 SendableMedia(name, tpath, tmp_os.str()));
2397 // Start next bunch if got enough data
2398 if(file_size_bunch_total >= bytes_per_bunch) {
2399 file_bunches.push_back(std::vector<SendableMedia>());
2400 file_size_bunch_total = 0;
2405 /* Create and send packets */
2407 u16 num_bunches = file_bunches.size();
2408 for(u16 i = 0; i < num_bunches; i++) {
2411 u16 total number of texture bunches
2412 u16 index of this bunch
2413 u32 number of files in this bunch
2422 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2423 pkt << num_bunches << i << (u32) file_bunches[i].size();
2425 for(std::vector<SendableMedia>::iterator
2426 j = file_bunches[i].begin();
2427 j != file_bunches[i].end(); ++j) {
2429 pkt.putLongString(j->data);
2432 verbosestream << "Server::sendRequestedMedia(): bunch "
2433 << i << "/" << num_bunches
2434 << " files=" << file_bunches[i].size()
2435 << " size=" << pkt.getSize() << std::endl;
2440 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2442 if(m_detached_inventories.count(name) == 0) {
2443 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2446 Inventory *inv = m_detached_inventories[name];
2447 std::ostringstream os(std::ios_base::binary);
2449 os << serializeString(name);
2453 std::string s = os.str();
2455 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2456 pkt.putRawString(s.c_str(), s.size());
2458 if (peer_id != PEER_ID_INEXISTENT) {
2462 m_clients.sendToAll(0, &pkt, true);
2466 void Server::sendDetachedInventories(u16 peer_id)
2468 DSTACK(FUNCTION_NAME);
2470 for(std::map<std::string, Inventory*>::iterator
2471 i = m_detached_inventories.begin();
2472 i != m_detached_inventories.end(); ++i) {
2473 const std::string &name = i->first;
2474 //Inventory *inv = i->second;
2475 sendDetachedInventory(name, peer_id);
2483 void Server::DiePlayer(u16 peer_id)
2485 DSTACK(FUNCTION_NAME);
2487 PlayerSAO *playersao = getPlayerSAO(peer_id);
2490 infostream << "Server::DiePlayer(): Player "
2491 << playersao->getPlayer()->getName()
2492 << " dies" << std::endl;
2494 playersao->setHP(0);
2496 // Trigger scripted stuff
2497 m_script->on_dieplayer(playersao);
2499 SendPlayerHP(peer_id);
2500 SendDeathscreen(peer_id, false, v3f(0,0,0));
2503 void Server::RespawnPlayer(u16 peer_id)
2505 DSTACK(FUNCTION_NAME);
2507 PlayerSAO *playersao = getPlayerSAO(peer_id);
2510 infostream << "Server::RespawnPlayer(): Player "
2511 << playersao->getPlayer()->getName()
2512 << " respawns" << std::endl;
2514 playersao->setHP(PLAYER_MAX_HP);
2515 playersao->setBreath(PLAYER_MAX_BREATH);
2517 SendPlayerHP(peer_id);
2518 SendPlayerBreath(peer_id);
2520 bool repositioned = m_script->on_respawnplayer(playersao);
2522 v3f pos = findSpawnPos();
2523 // setPos will send the new position to client
2524 playersao->setPos(pos);
2529 void Server::DenySudoAccess(u16 peer_id)
2531 DSTACK(FUNCTION_NAME);
2533 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2538 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2539 const std::string &str_reason, bool reconnect)
2541 if (proto_ver >= 25) {
2542 SendAccessDenied(peer_id, reason, str_reason);
2544 std::wstring wreason = utf8_to_wide(
2545 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2546 accessDeniedStrings[(u8)reason]);
2547 SendAccessDenied_Legacy(peer_id, wreason);
2550 m_clients.event(peer_id, CSE_SetDenied);
2551 m_con.DisconnectPeer(peer_id);
2555 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2557 DSTACK(FUNCTION_NAME);
2559 SendAccessDenied(peer_id, reason, custom_reason);
2560 m_clients.event(peer_id, CSE_SetDenied);
2561 m_con.DisconnectPeer(peer_id);
2564 // 13/03/15: remove this function when protocol version 25 will become
2565 // the minimum version for MT users, maybe in 1 year
2566 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2568 DSTACK(FUNCTION_NAME);
2570 SendAccessDenied_Legacy(peer_id, reason);
2571 m_clients.event(peer_id, CSE_SetDenied);
2572 m_con.DisconnectPeer(peer_id);
2575 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2577 DSTACK(FUNCTION_NAME);
2580 RemoteClient* client = getClient(peer_id, CS_Invalid);
2582 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2584 // Right now, the auth mechs don't change between login and sudo mode.
2585 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2586 client->allowed_sudo_mechs = sudo_auth_mechs;
2588 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2589 << g_settings->getFloat("dedicated_server_step")
2593 m_clients.event(peer_id, CSE_AuthAccept);
2595 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2597 // We only support SRP right now
2598 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2600 resp_pkt << sudo_auth_mechs;
2602 m_clients.event(peer_id, CSE_SudoSuccess);
2606 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2608 DSTACK(FUNCTION_NAME);
2609 std::wstring message;
2612 Clear references to playing sounds
2614 for(std::map<s32, ServerPlayingSound>::iterator
2615 i = m_playing_sounds.begin();
2616 i != m_playing_sounds.end();)
2618 ServerPlayingSound &psound = i->second;
2619 psound.clients.erase(peer_id);
2620 if(psound.clients.empty())
2621 m_playing_sounds.erase(i++);
2626 Player *player = m_env->getPlayer(peer_id);
2628 // Collect information about leaving in chat
2630 if(player != NULL && reason != CDR_DENY)
2632 std::wstring name = narrow_to_wide(player->getName());
2635 message += L" left the game.";
2636 if(reason == CDR_TIMEOUT)
2637 message += L" (timed out)";
2641 /* Run scripts and remove from environment */
2645 PlayerSAO *playersao = player->getPlayerSAO();
2648 m_script->on_leaveplayer(playersao);
2650 playersao->disconnected();
2658 if(player != NULL && reason != CDR_DENY) {
2659 std::ostringstream os(std::ios_base::binary);
2660 std::vector<u16> clients = m_clients.getClientIDs();
2662 for(std::vector<u16>::iterator i = clients.begin();
2663 i != clients.end(); ++i) {
2665 Player *player = m_env->getPlayer(*i);
2669 // Get name of player
2670 os << player->getName() << " ";
2673 actionstream << player->getName() << " "
2674 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2675 << " List of players: " << os.str() << std::endl;
2679 MutexAutoLock env_lock(m_env_mutex);
2680 m_clients.DeleteClient(peer_id);
2684 // Send leave chat message to all remaining clients
2685 if(message.length() != 0)
2686 SendChatMessage(PEER_ID_INEXISTENT,message);
2689 void Server::UpdateCrafting(Player* player)
2691 DSTACK(FUNCTION_NAME);
2693 // Get a preview for crafting
2695 InventoryLocation loc;
2696 loc.setPlayer(player->getName());
2697 std::vector<ItemStack> output_replacements;
2698 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2699 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2701 // Put the new preview in
2702 InventoryList *plist = player->inventory.getList("craftpreview");
2703 sanity_check(plist);
2704 sanity_check(plist->getSize() >= 1);
2705 plist->changeItem(0, preview);
2708 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2710 RemoteClient *client = getClientNoEx(peer_id,state_min);
2712 throw ClientNotFoundException("Client not found");
2716 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2718 return m_clients.getClientNoEx(peer_id, state_min);
2721 std::string Server::getPlayerName(u16 peer_id)
2723 Player *player = m_env->getPlayer(peer_id);
2725 return "[id="+itos(peer_id)+"]";
2726 return player->getName();
2729 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2731 Player *player = m_env->getPlayer(peer_id);
2734 return player->getPlayerSAO();
2737 std::wstring Server::getStatusString()
2739 std::wostringstream os(std::ios_base::binary);
2742 os<<L"version="<<narrow_to_wide(g_version_string);
2744 os<<L", uptime="<<m_uptime.get();
2746 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2747 // Information about clients
2750 std::vector<u16> clients = m_clients.getClientIDs();
2751 for(std::vector<u16>::iterator i = clients.begin();
2752 i != clients.end(); ++i) {
2754 Player *player = m_env->getPlayer(*i);
2755 // Get name of player
2756 std::wstring name = L"unknown";
2758 name = narrow_to_wide(player->getName());
2759 // Add name to information string
2767 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2768 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2769 if(g_settings->get("motd") != "")
2770 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2774 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2776 std::set<std::string> privs;
2777 m_script->getAuth(name, NULL, &privs);
2781 bool Server::checkPriv(const std::string &name, const std::string &priv)
2783 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2784 return (privs.count(priv) != 0);
2787 void Server::reportPrivsModified(const std::string &name)
2790 std::vector<u16> clients = m_clients.getClientIDs();
2791 for(std::vector<u16>::iterator i = clients.begin();
2792 i != clients.end(); ++i) {
2793 Player *player = m_env->getPlayer(*i);
2794 reportPrivsModified(player->getName());
2797 Player *player = m_env->getPlayer(name.c_str());
2800 SendPlayerPrivileges(player->peer_id);
2801 PlayerSAO *sao = player->getPlayerSAO();
2804 sao->updatePrivileges(
2805 getPlayerEffectivePrivs(name),
2810 void Server::reportInventoryFormspecModified(const std::string &name)
2812 Player *player = m_env->getPlayer(name.c_str());
2815 SendPlayerInventoryFormspec(player->peer_id);
2818 void Server::setIpBanned(const std::string &ip, const std::string &name)
2820 m_banmanager->add(ip, name);
2823 void Server::unsetIpBanned(const std::string &ip_or_name)
2825 m_banmanager->remove(ip_or_name);
2828 std::string Server::getBanDescription(const std::string &ip_or_name)
2830 return m_banmanager->getBanDescription(ip_or_name);
2833 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2835 // m_env will be NULL if the server is initializing
2839 Player *player = m_env->getPlayer(name);
2843 if (player->peer_id == PEER_ID_INEXISTENT)
2846 SendChatMessage(player->peer_id, msg);
2849 bool Server::showFormspec(const char *playername, const std::string &formspec,
2850 const std::string &formname)
2852 // m_env will be NULL if the server is initializing
2856 Player *player = m_env->getPlayer(playername);
2860 SendShowFormspecMessage(player->peer_id, formspec, formname);
2864 u32 Server::hudAdd(Player *player, HudElement *form)
2869 u32 id = player->addHud(form);
2871 SendHUDAdd(player->peer_id, id, form);
2876 bool Server::hudRemove(Player *player, u32 id) {
2880 HudElement* todel = player->removeHud(id);
2887 SendHUDRemove(player->peer_id, id);
2891 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2896 SendHUDChange(player->peer_id, id, stat, data);
2900 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2905 SendHUDSetFlags(player->peer_id, flags, mask);
2906 player->hud_flags = flags;
2908 PlayerSAO* playersao = player->getPlayerSAO();
2910 if (playersao == NULL)
2913 m_script->player_event(playersao, "hud_changed");
2917 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2921 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2924 player->setHotbarItemcount(hotbar_itemcount);
2925 std::ostringstream os(std::ios::binary);
2926 writeS32(os, hotbar_itemcount);
2927 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2931 s32 Server::hudGetHotbarItemcount(Player *player)
2935 return player->getHotbarItemcount();
2938 void Server::hudSetHotbarImage(Player *player, std::string name)
2943 player->setHotbarImage(name);
2944 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2947 std::string Server::hudGetHotbarImage(Player *player)
2951 return player->getHotbarImage();
2954 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2959 player->setHotbarSelectedImage(name);
2960 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2963 std::string Server::hudGetHotbarSelectedImage(Player *player)
2968 return player->getHotbarSelectedImage();
2971 bool Server::setLocalPlayerAnimations(Player *player,
2972 v2s32 animation_frames[4], f32 frame_speed)
2977 player->setLocalAnimations(animation_frames, frame_speed);
2978 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2982 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2987 player->eye_offset_first = first;
2988 player->eye_offset_third = third;
2989 SendEyeOffset(player->peer_id, first, third);
2993 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2994 const std::string &type, const std::vector<std::string> ¶ms)
2999 player->setSky(bgcolor, type, params);
3000 SendSetSky(player->peer_id, bgcolor, type, params);
3004 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3010 player->overrideDayNightRatio(do_override, ratio);
3011 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3015 void Server::notifyPlayers(const std::wstring &msg)
3017 SendChatMessage(PEER_ID_INEXISTENT,msg);
3020 void Server::spawnParticle(const std::string &playername, v3f pos,
3021 v3f velocity, v3f acceleration,
3022 float expirationtime, float size, bool
3023 collisiondetection, bool vertical, const std::string &texture)
3025 // m_env will be NULL if the server is initializing
3029 u16 peer_id = PEER_ID_INEXISTENT;
3030 if (playername != "") {
3031 Player* player = m_env->getPlayer(playername.c_str());
3034 peer_id = player->peer_id;
3037 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3038 expirationtime, size, collisiondetection, vertical, texture);
3041 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3042 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3043 float minexptime, float maxexptime, float minsize, float maxsize,
3044 bool collisiondetection, bool vertical, const std::string &texture,
3045 const std::string &playername)
3047 // m_env will be NULL if the server is initializing
3051 u16 peer_id = PEER_ID_INEXISTENT;
3052 if (playername != "") {
3053 Player* player = m_env->getPlayer(playername.c_str());
3056 peer_id = player->peer_id;
3060 for(;;) // look for unused particlespawner id
3063 if (std::find(m_particlespawner_ids.begin(),
3064 m_particlespawner_ids.end(), id)
3065 == m_particlespawner_ids.end())
3067 m_particlespawner_ids.push_back(id);
3072 SendAddParticleSpawner(peer_id, amount, spawntime,
3073 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3074 minexptime, maxexptime, minsize, maxsize,
3075 collisiondetection, vertical, texture, id);
3080 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3082 // m_env will be NULL if the server is initializing
3084 throw ServerError("Can't delete particle spawners during initialisation!");
3086 u16 peer_id = PEER_ID_INEXISTENT;
3087 if (playername != "") {
3088 Player* player = m_env->getPlayer(playername.c_str());
3091 peer_id = player->peer_id;
3094 m_particlespawner_ids.erase(
3095 std::remove(m_particlespawner_ids.begin(),
3096 m_particlespawner_ids.end(), id),
3097 m_particlespawner_ids.end());
3098 SendDeleteParticleSpawner(peer_id, id);
3101 Inventory* Server::createDetachedInventory(const std::string &name)
3103 if(m_detached_inventories.count(name) > 0){
3104 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3105 delete m_detached_inventories[name];
3107 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3109 Inventory *inv = new Inventory(m_itemdef);
3111 m_detached_inventories[name] = inv;
3112 //TODO find a better way to do this
3113 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3117 // actions: time-reversed list
3118 // Return value: success/failure
3119 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3120 std::list<std::string> *log)
3122 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3123 ServerMap *map = (ServerMap*)(&m_env->getMap());
3125 // Fail if no actions to handle
3126 if(actions.empty()){
3127 log->push_back("Nothing to do.");
3134 for(std::list<RollbackAction>::const_iterator
3135 i = actions.begin();
3136 i != actions.end(); ++i)
3138 const RollbackAction &action = *i;
3140 bool success = action.applyRevert(map, this, this);
3143 std::ostringstream os;
3144 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3145 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3147 log->push_back(os.str());
3149 std::ostringstream os;
3150 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3151 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3153 log->push_back(os.str());
3157 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3158 <<" failed"<<std::endl;
3160 // Call it done if less than half failed
3161 return num_failed <= num_tried/2;
3164 // IGameDef interface
3166 IItemDefManager *Server::getItemDefManager()
3171 INodeDefManager *Server::getNodeDefManager()
3176 ICraftDefManager *Server::getCraftDefManager()
3180 ITextureSource *Server::getTextureSource()
3184 IShaderSource *Server::getShaderSource()
3188 scene::ISceneManager *Server::getSceneManager()
3193 u16 Server::allocateUnknownNodeId(const std::string &name)
3195 return m_nodedef->allocateDummy(name);
3198 ISoundManager *Server::getSoundManager()
3200 return &dummySoundManager;
3203 MtEventManager *Server::getEventManager()
3208 IWritableItemDefManager *Server::getWritableItemDefManager()
3213 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3218 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3223 const ModSpec *Server::getModSpec(const std::string &modname) const
3225 std::vector<ModSpec>::const_iterator it;
3226 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3227 const ModSpec &mod = *it;
3228 if (mod.name == modname)
3234 void Server::getModNames(std::vector<std::string> &modlist)
3236 std::vector<ModSpec>::iterator it;
3237 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3238 modlist.push_back(it->name);
3241 std::string Server::getBuiltinLuaPath()
3243 return porting::path_share + DIR_DELIM + "builtin";
3246 v3f Server::findSpawnPos()
3248 ServerMap &map = m_env->getServerMap();
3250 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3251 return nodeposf * BS;
3254 s16 water_level = map.getWaterLevel();
3255 s16 vertical_spawn_range = g_settings->getS16("vertical_spawn_range");
3256 bool is_good = false;
3258 // Try to find a good place a few times
3259 for(s32 i = 0; i < 1000 && !is_good; i++) {
3261 // We're going to try to throw the player to this position
3262 v2s16 nodepos2d = v2s16(
3263 -range + (myrand() % (range * 2)),
3264 -range + (myrand() % (range * 2)));
3266 // Get ground height at point
3267 s16 groundheight = map.findGroundLevel(nodepos2d);
3268 // Don't go underwater or to high places
3269 if (groundheight <= water_level ||
3270 groundheight > water_level + vertical_spawn_range)
3273 v3s16 nodepos(nodepos2d.X, groundheight, nodepos2d.Y);
3276 for (s32 i = 0; i < 10; i++) {
3277 v3s16 blockpos = getNodeBlockPos(nodepos);
3278 map.emergeBlock(blockpos, true);
3279 content_t c = map.getNodeNoEx(nodepos).getContent();
3280 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3282 if (air_count >= 2) {
3283 nodeposf = intToFloat(nodepos, BS);
3284 // Don't spawn the player outside map boundaries
3285 if (objectpos_over_limit(nodeposf))
3298 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3300 bool newplayer = false;
3303 Try to get an existing player
3305 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3307 // If player is already connected, cancel
3308 if(player != NULL && player->peer_id != 0)
3310 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3315 If player with the wanted peer_id already exists, cancel.
3317 if(m_env->getPlayer(peer_id) != NULL)
3319 infostream<<"emergePlayer(): Player with wrong name but same"
3320 " peer_id already exists"<<std::endl;
3324 // Load player if it isn't already loaded
3326 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3329 // Create player if it doesn't exist
3332 player = new RemotePlayer(this, name);
3333 // Set player position
3334 infostream<<"Server: Finding spawn place for player \""
3335 <<name<<"\""<<std::endl;
3336 v3f pos = findSpawnPos();
3337 player->setPosition(pos);
3339 // Make sure the player is saved
3340 player->setModified(true);
3342 // Add player to environment
3343 m_env->addPlayer(player);
3345 // If the player exists, ensure that they respawn inside legal bounds
3346 // This fixes an assert crash when the player can't be added
3347 // to the environment
3348 if (objectpos_over_limit(player->getPosition())) {
3349 actionstream << "Respawn position for player \""
3350 << name << "\" outside limits, resetting" << std::endl;
3351 v3f pos = findSpawnPos();
3352 player->setPosition(pos);
3356 // Create a new player active object
3357 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3358 getPlayerEffectivePrivs(player->getName()),
3361 player->protocol_version = proto_version;
3363 /* Clean up old HUD elements from previous sessions */
3366 /* Add object to environment */
3367 m_env->addActiveObject(playersao);
3371 m_script->on_newplayer(playersao);
3377 void dedicated_server_loop(Server &server, bool &kill)
3379 DSTACK(FUNCTION_NAME);
3381 verbosestream<<"dedicated_server_loop()"<<std::endl;
3383 IntervalLimiter m_profiler_interval;
3387 float steplen = g_settings->getFloat("dedicated_server_step");
3388 // This is kind of a hack but can be done like this
3389 // because server.step() is very light
3391 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3392 sleep_ms((int)(steplen*1000.0));
3394 server.step(steplen);
3396 if(server.getShutdownRequested() || kill)
3398 infostream<<"Dedicated server quitting"<<std::endl;
3400 if(g_settings->getBool("server_announce"))
3401 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3409 float profiler_print_interval =
3410 g_settings->getFloat("profiler_print_interval");
3411 if(profiler_print_interval != 0)
3413 if(m_profiler_interval.step(steplen, profiler_print_interval))
3415 infostream<<"Profiler:"<<std::endl;
3416 g_profiler->print(infostream);
3417 g_profiler->clear();