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_print_info_timer = 0.0;
188 m_masterserver_timer = 0.0;
189 m_objectdata_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if(!modconf.isConsistent()) {
229 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
230 it != unsatisfied_mods.end(); ++it) {
232 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
233 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
234 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
235 errorstream << " \"" << *dep_it << "\"";
236 errorstream << std::endl;
240 Settings worldmt_settings;
241 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
242 worldmt_settings.readConfigFile(worldmt.c_str());
243 std::vector<std::string> names = worldmt_settings.getNames();
244 std::set<std::string> load_mod_names;
245 for(std::vector<std::string>::iterator it = names.begin();
246 it != names.end(); ++it) {
247 std::string name = *it;
248 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
249 load_mod_names.insert(name.substr(9));
251 // complain about mods declared to be loaded, but not found
252 for(std::vector<ModSpec>::iterator it = m_mods.begin();
253 it != m_mods.end(); ++it)
254 load_mod_names.erase((*it).name);
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
257 load_mod_names.erase((*it).name);
258 if(!load_mod_names.empty()) {
259 errorstream << "The following mods could not be found:";
260 for(std::set<std::string>::iterator it = load_mod_names.begin();
261 it != load_mod_names.end(); ++it)
262 errorstream << " \"" << (*it) << "\"";
263 errorstream << std::endl;
267 MutexAutoLock envlock(m_env_mutex);
269 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
270 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
272 // Initialize scripting
273 infostream<<"Server: Initializing Lua"<<std::endl;
275 m_script = new GameScripting(this);
277 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
279 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
282 infostream << "Server: Loading mods: ";
283 for(std::vector<ModSpec>::iterator i = m_mods.begin();
284 i != m_mods.end(); ++i) {
285 const ModSpec &mod = *i;
286 infostream << mod.name << " ";
288 infostream << std::endl;
289 // Load and run "mod" scripts
290 for (std::vector<ModSpec>::iterator it = m_mods.begin();
291 it != m_mods.end(); ++it) {
292 const ModSpec &mod = *it;
293 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
294 throw ModError("Error loading mod \"" + mod.name +
295 "\": Mod name does not follow naming conventions: "
296 "Only chararacters [a-z0-9_] are allowed.");
298 std::string script_path = mod.path + DIR_DELIM + "init.lua";
299 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
300 << script_path << "\"]" << std::endl;
301 m_script->loadMod(script_path, mod.name);
304 // Read Textures and calculate sha1 sums
307 // Apply item aliases in the node definition manager
308 m_nodedef->updateAliases(m_itemdef);
310 // Apply texture overrides from texturepack/override.txt
311 std::string texture_path = g_settings->get("texture_path");
312 if (texture_path != "" && fs::IsDir(texture_path))
313 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
315 m_nodedef->setNodeRegistrationStatus(true);
317 // Perform pending node name resolutions
318 m_nodedef->runNodeResolveCallbacks();
320 // unmap node names for connected nodeboxes
321 m_nodedef->mapNodeboxConnections();
323 // init the recipe hashes to speed up crafting
324 m_craftdef->initHashes(this);
326 // Initialize Environment
327 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
329 m_clients.setEnv(m_env);
331 if (!servermap->settings_mgr.makeMapgenParams())
332 FATAL_ERROR("Couldn't create any mapgen type");
334 // Initialize mapgens
335 m_emerge->initMapgens(servermap->getMapgenParams());
337 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
338 if (m_enable_rollback_recording) {
339 // Create rollback manager
340 m_rollback = new RollbackManager(m_path_world, this);
343 // Give environment reference to scripting api
344 m_script->initializeEnvironment(m_env);
346 // Register us to receive map edit events
347 servermap->addEventReceiver(this);
349 // If file exists, load environment metadata
350 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
351 infostream << "Server: Loading environment metadata" << std::endl;
354 m_env->loadDefaultMeta();
357 // Add some test ActiveBlockModifiers to environment
358 add_legacy_abms(m_env, m_nodedef);
360 m_liquid_transform_every = g_settings->getFloat("liquid_update");
365 infostream<<"Server destructing"<<std::endl;
367 // Send shutdown message
368 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
371 MutexAutoLock envlock(m_env_mutex);
373 // Execute script shutdown hooks
374 m_script->on_shutdown();
376 infostream << "Server: Saving players" << std::endl;
377 m_env->saveLoadedPlayers();
379 infostream << "Server: Kicking players" << std::endl;
380 std::string kick_msg;
381 bool reconnect = false;
382 if (getShutdownRequested()) {
383 reconnect = m_shutdown_ask_reconnect;
384 kick_msg = m_shutdown_msg;
386 if (kick_msg == "") {
387 kick_msg = g_settings->get("kick_msg_shutdown");
389 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
390 kick_msg, reconnect);
392 infostream << "Server: Saving environment metadata" << std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
414 // Deinitialize scripting
415 infostream<<"Server: Deinitializing scripting"<<std::endl;
418 // Delete detached inventories
419 for (std::map<std::string, Inventory*>::iterator
420 i = m_detached_inventories.begin();
421 i != m_detached_inventories.end(); ++i) {
426 void Server::start(Address bind_addr)
428 DSTACK(FUNCTION_NAME);
430 m_bind_addr = bind_addr;
432 infostream<<"Starting server on "
433 << bind_addr.serializeString() <<"..."<<std::endl;
435 // Stop thread if already running
438 // Initialize connection
439 m_con.SetTimeoutMs(30);
440 m_con.Serve(bind_addr);
445 // ASCII art for the win!
447 <<" .__ __ __ "<<std::endl
448 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
449 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
450 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
451 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
452 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
453 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
454 actionstream<<"Server for gameid=\""<<m_gamespec.id
455 <<"\" listening on "<<bind_addr.serializeString()<<":"
456 <<bind_addr.getPort() << "."<<std::endl;
461 DSTACK(FUNCTION_NAME);
463 infostream<<"Server: Stopping and waiting threads"<<std::endl;
465 // Stop threads (set run=false first so both start stopping)
467 //m_emergethread.setRun(false);
469 //m_emergethread.stop();
471 infostream<<"Server: Threads stopped"<<std::endl;
474 void Server::step(float dtime)
476 DSTACK(FUNCTION_NAME);
481 MutexAutoLock lock(m_step_dtime_mutex);
482 m_step_dtime += dtime;
484 // Throw if fatal error occurred in thread
485 std::string async_err = m_async_fatal_error.get();
486 if (!async_err.empty()) {
487 if (!m_simple_singleplayer_mode) {
488 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
489 g_settings->get("kick_msg_crash"),
490 g_settings->getBool("ask_reconnect_on_crash"));
492 throw ServerError(async_err);
496 void Server::AsyncRunStep(bool initial_step)
498 DSTACK(FUNCTION_NAME);
500 g_profiler->add("Server::AsyncRunStep (num)", 1);
504 MutexAutoLock lock1(m_step_dtime_mutex);
505 dtime = m_step_dtime;
509 // Send blocks to clients
513 if((dtime < 0.001) && (initial_step == false))
516 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
518 //infostream<<"Server steps "<<dtime<<std::endl;
519 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
522 MutexAutoLock lock1(m_step_dtime_mutex);
523 m_step_dtime -= dtime;
530 m_uptime.set(m_uptime.get() + dtime);
536 Update time of day and overall game time
538 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
541 Send to clients at constant intervals
544 m_time_of_day_send_timer -= dtime;
545 if(m_time_of_day_send_timer < 0.0) {
546 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
547 u16 time = m_env->getTimeOfDay();
548 float time_speed = g_settings->getFloat("time_speed");
549 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
553 MutexAutoLock lock(m_env_mutex);
554 // Figure out and report maximum lag to environment
555 float max_lag = m_env->getMaxLagEstimate();
556 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
558 if(dtime > 0.1 && dtime > max_lag * 2.0)
559 infostream<<"Server: Maximum lag peaked to "<<dtime
563 m_env->reportMaxLagEstimate(max_lag);
565 ScopeProfiler sp(g_profiler, "SEnv step");
566 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
570 static const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 MutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"),
582 Listen to the admin chat, if available
585 if (!m_admin_chat->command_queue.empty()) {
586 MutexAutoLock lock(m_env_mutex);
587 while (!m_admin_chat->command_queue.empty()) {
588 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
589 handleChatInterfaceEvent(evt);
593 m_admin_chat->outgoing_queue.push_back(
594 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
601 /* Transform liquids */
602 m_liquid_transform_timer += dtime;
603 if(m_liquid_transform_timer >= m_liquid_transform_every)
605 m_liquid_transform_timer -= m_liquid_transform_every;
607 MutexAutoLock lock(m_env_mutex);
609 ScopeProfiler sp(g_profiler, "Server: liquid transform");
611 std::map<v3s16, MapBlock*> modified_blocks;
612 m_env->getMap().transformLiquids(modified_blocks);
617 core::map<v3s16, MapBlock*> lighting_modified_blocks;
618 ServerMap &map = ((ServerMap&)m_env->getMap());
619 map.updateLighting(modified_blocks, lighting_modified_blocks);
621 // Add blocks modified by lighting to modified_blocks
622 for(core::map<v3s16, MapBlock*>::Iterator
623 i = lighting_modified_blocks.getIterator();
624 i.atEnd() == false; i++)
626 MapBlock *block = i.getNode()->getValue();
627 modified_blocks.insert(block->getPos(), block);
631 Set the modified blocks unsent for all the clients
633 if(!modified_blocks.empty())
635 SetBlocksNotSent(modified_blocks);
638 m_clients.step(dtime);
640 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
642 // send masterserver announce
644 float &counter = m_masterserver_timer;
645 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
646 g_settings->getBool("server_announce"))
648 ServerList::sendAnnounce(counter ? "update" : "start",
649 m_bind_addr.getPort(),
650 m_clients.getPlayerNames(),
652 m_env->getGameTime(),
655 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
664 Check added and deleted active objects
667 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
668 MutexAutoLock envlock(m_env_mutex);
671 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
672 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
674 // Radius inside which objects are active
675 static const s16 radius =
676 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
678 // Radius inside which players are active
679 static const bool is_transfer_limited =
680 g_settings->exists("unlimited_player_transfer_distance") &&
681 !g_settings->getBool("unlimited_player_transfer_distance");
682 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
683 s16 player_radius = player_transfer_dist;
684 if (player_radius == 0 && is_transfer_limited)
685 player_radius = radius;
687 for (std::map<u16, RemoteClient*>::iterator
689 i != clients.end(); ++i) {
690 RemoteClient *client = i->second;
692 // If definitions and textures have not been sent, don't
693 // send objects either
694 if (client->getState() < CS_DefinitionsSent)
697 Player *player = m_env->getPlayer(client->peer_id);
699 // This can happen if the client timeouts somehow
700 /*warningstream<<FUNCTION_NAME<<": Client "
702 <<" has no associated player"<<std::endl;*/
706 std::queue<u16> removed_objects;
707 std::queue<u16> added_objects;
708 m_env->getRemovedActiveObjects(player, radius, player_radius,
709 client->m_known_objects, removed_objects);
710 m_env->getAddedActiveObjects(player, radius, player_radius,
711 client->m_known_objects, added_objects);
713 // Ignore if nothing happened
714 if (removed_objects.empty() && added_objects.empty()) {
718 std::string data_buffer;
722 // Handle removed objects
723 writeU16((u8*)buf, removed_objects.size());
724 data_buffer.append(buf, 2);
725 while (!removed_objects.empty()) {
727 u16 id = removed_objects.front();
728 ServerActiveObject* obj = m_env->getActiveObject(id);
730 // Add to data buffer for sending
731 writeU16((u8*)buf, id);
732 data_buffer.append(buf, 2);
734 // Remove from known objects
735 client->m_known_objects.erase(id);
737 if(obj && obj->m_known_by_count > 0)
738 obj->m_known_by_count--;
739 removed_objects.pop();
742 // Handle added objects
743 writeU16((u8*)buf, added_objects.size());
744 data_buffer.append(buf, 2);
745 while (!added_objects.empty()) {
747 u16 id = added_objects.front();
748 ServerActiveObject* obj = m_env->getActiveObject(id);
751 u8 type = ACTIVEOBJECT_TYPE_INVALID;
753 warningstream<<FUNCTION_NAME
754 <<": NULL object"<<std::endl;
756 type = obj->getSendType();
758 // Add to data buffer for sending
759 writeU16((u8*)buf, id);
760 data_buffer.append(buf, 2);
761 writeU8((u8*)buf, type);
762 data_buffer.append(buf, 1);
765 data_buffer.append(serializeLongString(
766 obj->getClientInitializationData(client->net_proto_version)));
768 data_buffer.append(serializeLongString(""));
770 // Add to known objects
771 client->m_known_objects.insert(id);
774 obj->m_known_by_count++;
779 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
780 verbosestream << "Server: Sent object remove/add: "
781 << removed_objects.size() << " removed, "
782 << added_objects.size() << " added, "
783 << "packet size is " << pktSize << std::endl;
792 MutexAutoLock envlock(m_env_mutex);
793 ScopeProfiler sp(g_profiler, "Server: sending object messages");
796 // Value = data sent by object
797 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
799 // Get active object messages from environment
801 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
805 std::vector<ActiveObjectMessage>* message_list = NULL;
806 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
807 n = buffered_messages.find(aom.id);
808 if (n == buffered_messages.end()) {
809 message_list = new std::vector<ActiveObjectMessage>;
810 buffered_messages[aom.id] = message_list;
813 message_list = n->second;
815 message_list->push_back(aom);
819 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
820 // Route data to every client
821 for (std::map<u16, RemoteClient*>::iterator
823 i != clients.end(); ++i) {
824 RemoteClient *client = i->second;
825 std::string reliable_data;
826 std::string unreliable_data;
827 // Go through all objects in message buffer
828 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
829 j = buffered_messages.begin();
830 j != buffered_messages.end(); ++j) {
831 // If object is not known by client, skip it
833 if (client->m_known_objects.find(id) == client->m_known_objects.end())
836 // Get message list of object
837 std::vector<ActiveObjectMessage>* list = j->second;
838 // Go through every message
839 for (std::vector<ActiveObjectMessage>::iterator
840 k = list->begin(); k != list->end(); ++k) {
841 // Compose the full new data with header
842 ActiveObjectMessage aom = *k;
843 std::string new_data;
846 writeU16((u8*)&buf[0], aom.id);
847 new_data.append(buf, 2);
849 new_data += serializeString(aom.datastring);
850 // Add data to buffer
852 reliable_data += new_data;
854 unreliable_data += new_data;
858 reliable_data and unreliable_data are now ready.
861 if(reliable_data.size() > 0) {
862 SendActiveObjectMessages(client->peer_id, reliable_data);
865 if(unreliable_data.size() > 0) {
866 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
871 // Clear buffered_messages
872 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
873 i = buffered_messages.begin();
874 i != buffered_messages.end(); ++i) {
880 Send queued-for-sending map edit events.
883 // We will be accessing the environment
884 MutexAutoLock lock(m_env_mutex);
886 // Don't send too many at a time
889 // Single change sending is disabled if queue size is not small
890 bool disable_single_change_sending = false;
891 if(m_unsent_map_edit_queue.size() >= 4)
892 disable_single_change_sending = true;
894 int event_count = m_unsent_map_edit_queue.size();
896 // We'll log the amount of each
899 while(m_unsent_map_edit_queue.size() != 0)
901 MapEditEvent* event = m_unsent_map_edit_queue.front();
902 m_unsent_map_edit_queue.pop();
904 // Players far away from the change are stored here.
905 // Instead of sending the changes, MapBlocks are set not sent
907 std::vector<u16> far_players;
909 switch (event->type) {
912 prof.add("MEET_ADDNODE", 1);
913 sendAddNode(event->p, event->n, event->already_known_by_peer,
914 &far_players, disable_single_change_sending ? 5 : 30,
915 event->type == MEET_ADDNODE);
917 case MEET_REMOVENODE:
918 prof.add("MEET_REMOVENODE", 1);
919 sendRemoveNode(event->p, event->already_known_by_peer,
920 &far_players, disable_single_change_sending ? 5 : 30);
922 case MEET_BLOCK_NODE_METADATA_CHANGED:
923 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
924 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
925 setBlockNotSent(event->p);
928 infostream << "Server: MEET_OTHER" << std::endl;
929 prof.add("MEET_OTHER", 1);
930 for(std::set<v3s16>::iterator
931 i = event->modified_blocks.begin();
932 i != event->modified_blocks.end(); ++i) {
937 prof.add("unknown", 1);
938 warningstream << "Server: Unknown MapEditEvent "
939 << ((u32)event->type) << std::endl;
944 Set blocks not sent to far players
946 if(!far_players.empty()) {
947 // Convert list format to that wanted by SetBlocksNotSent
948 std::map<v3s16, MapBlock*> modified_blocks2;
949 for(std::set<v3s16>::iterator
950 i = event->modified_blocks.begin();
951 i != event->modified_blocks.end(); ++i) {
952 modified_blocks2[*i] =
953 m_env->getMap().getBlockNoCreateNoEx(*i);
956 // Set blocks not sent
957 for(std::vector<u16>::iterator
958 i = far_players.begin();
959 i != far_players.end(); ++i) {
960 if(RemoteClient *client = getClient(*i))
961 client->SetBlocksNotSent(modified_blocks2);
967 /*// Don't send too many at a time
969 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
973 if(event_count >= 5){
974 infostream<<"Server: MapEditEvents:"<<std::endl;
975 prof.print(infostream);
976 } else if(event_count != 0){
977 verbosestream<<"Server: MapEditEvents:"<<std::endl;
978 prof.print(verbosestream);
984 Trigger emergethread (it somehow gets to a non-triggered but
985 bysy state sometimes)
988 float &counter = m_emergethread_trigger_timer;
990 if (counter >= 2.0) {
993 m_emerge->startThreads();
997 // Save map, players and auth stuff
999 float &counter = m_savemap_timer;
1001 static const float save_interval =
1002 g_settings->getFloat("server_map_save_interval");
1003 if (counter >= save_interval) {
1005 MutexAutoLock lock(m_env_mutex);
1007 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1010 if (m_banmanager->isModified()) {
1011 m_banmanager->save();
1014 // Save changed parts of map
1015 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1018 m_env->saveLoadedPlayers();
1020 // Save environment metadata
1026 void Server::Receive()
1028 DSTACK(FUNCTION_NAME);
1029 SharedBuffer<u8> data;
1033 m_con.Receive(&pkt);
1034 peer_id = pkt.getPeerId();
1037 catch(con::InvalidIncomingDataException &e) {
1038 infostream<<"Server::Receive(): "
1039 "InvalidIncomingDataException: what()="
1040 <<e.what()<<std::endl;
1042 catch(SerializationError &e) {
1043 infostream<<"Server::Receive(): "
1044 "SerializationError: what()="
1045 <<e.what()<<std::endl;
1047 catch(ClientStateError &e) {
1048 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1049 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1050 L"Try reconnecting or updating your client");
1052 catch(con::PeerNotFoundException &e) {
1057 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1059 std::string playername = "";
1060 PlayerSAO *playersao = NULL;
1063 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1064 if (client != NULL) {
1065 playername = client->getName();
1066 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1068 } catch (std::exception &e) {
1074 RemotePlayer *player =
1075 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1077 // If failed, cancel
1078 if ((playersao == NULL) || (player == NULL)) {
1079 if (player && player->peer_id != 0) {
1080 actionstream << "Server: Failed to emerge player \"" << playername
1081 << "\" (player allocated to an another client)" << std::endl;
1082 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1083 L"name. If your client closed unexpectedly, try again in "
1086 errorstream << "Server: " << playername << ": Failed to emerge player"
1088 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1094 Send complete position information
1096 SendMovePlayer(peer_id);
1099 SendPlayerPrivileges(peer_id);
1101 // Send inventory formspec
1102 SendPlayerInventoryFormspec(peer_id);
1105 SendInventory(playersao);
1108 SendPlayerHPOrDie(playersao);
1111 SendPlayerBreath(peer_id);
1113 // Show death screen if necessary
1114 if(player->isDead())
1115 SendDeathscreen(peer_id, false, v3f(0,0,0));
1117 // Note things in chat if not in simple singleplayer mode
1118 if(!m_simple_singleplayer_mode) {
1119 // Send information about server to player in chat
1120 SendChatMessage(peer_id, getStatusString());
1122 Address addr = getPeerAddress(player->peer_id);
1123 std::string ip_str = addr.serializeString();
1124 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1129 std::vector<std::string> names = m_clients.getPlayerNames();
1131 actionstream<<player->getName() <<" joins game. List of players: ";
1133 for (std::vector<std::string>::iterator i = names.begin();
1134 i != names.end(); ++i) {
1135 actionstream << *i << " ";
1138 actionstream << player->getName() <<std::endl;
1143 inline void Server::handleCommand(NetworkPacket* pkt)
1145 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1146 (this->*opHandle.handler)(pkt);
1149 void Server::ProcessData(NetworkPacket *pkt)
1151 DSTACK(FUNCTION_NAME);
1152 // Environment is locked first.
1153 MutexAutoLock envlock(m_env_mutex);
1155 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1156 u32 peer_id = pkt->getPeerId();
1159 Address address = getPeerAddress(peer_id);
1160 std::string addr_s = address.serializeString();
1162 if(m_banmanager->isIpBanned(addr_s)) {
1163 std::string ban_name = m_banmanager->getBanName(addr_s);
1164 infostream << "Server: A banned client tried to connect from "
1165 << addr_s << "; banned name was "
1166 << ban_name << std::endl;
1167 // This actually doesn't seem to transfer to the client
1168 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1169 + utf8_to_wide(ban_name));
1173 catch(con::PeerNotFoundException &e) {
1175 * no peer for this packet found
1176 * most common reason is peer timeout, e.g. peer didn't
1177 * respond for some time, your server was overloaded or
1180 infostream << "Server::ProcessData(): Canceling: peer "
1181 << peer_id << " not found" << std::endl;
1186 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1188 // Command must be handled into ToServerCommandHandler
1189 if (command >= TOSERVER_NUM_MSG_TYPES) {
1190 infostream << "Server: Ignoring unknown command "
1191 << command << std::endl;
1195 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1200 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1202 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1203 errorstream << "Server::ProcessData(): Cancelling: Peer"
1204 " serialization format invalid or not initialized."
1205 " Skipping incoming command=" << command << std::endl;
1209 /* Handle commands related to client startup */
1210 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1215 if (m_clients.getClientState(peer_id) < CS_Active) {
1216 if (command == TOSERVER_PLAYERPOS) return;
1218 errorstream << "Got packet command: " << command << " for peer id "
1219 << peer_id << " but client isn't active yet. Dropping packet "
1225 } catch (SendFailedException &e) {
1226 errorstream << "Server::ProcessData(): SendFailedException: "
1227 << "what=" << e.what()
1229 } catch (PacketError &e) {
1230 actionstream << "Server::ProcessData(): PacketError: "
1231 << "what=" << e.what()
1236 void Server::setTimeOfDay(u32 time)
1238 m_env->setTimeOfDay(time);
1239 m_time_of_day_send_timer = 0;
1242 void Server::onMapEditEvent(MapEditEvent *event)
1244 if(m_ignore_map_edit_events)
1246 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1248 MapEditEvent *e = event->clone();
1249 m_unsent_map_edit_queue.push(e);
1252 Inventory* Server::getInventory(const InventoryLocation &loc)
1255 case InventoryLocation::UNDEFINED:
1256 case InventoryLocation::CURRENT_PLAYER:
1258 case InventoryLocation::PLAYER:
1260 Player *player = m_env->getPlayer(loc.name.c_str());
1263 PlayerSAO *playersao = player->getPlayerSAO();
1266 return playersao->getInventory();
1269 case InventoryLocation::NODEMETA:
1271 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1274 return meta->getInventory();
1277 case InventoryLocation::DETACHED:
1279 if(m_detached_inventories.count(loc.name) == 0)
1281 return m_detached_inventories[loc.name];
1285 sanity_check(false); // abort
1290 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1293 case InventoryLocation::UNDEFINED:
1295 case InventoryLocation::PLAYER:
1300 Player *player = m_env->getPlayer(loc.name.c_str());
1303 PlayerSAO *playersao = player->getPlayerSAO();
1307 SendInventory(playersao);
1310 case InventoryLocation::NODEMETA:
1312 v3s16 blockpos = getNodeBlockPos(loc.p);
1314 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1316 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1318 setBlockNotSent(blockpos);
1321 case InventoryLocation::DETACHED:
1323 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1327 sanity_check(false); // abort
1332 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1334 std::vector<u16> clients = m_clients.getClientIDs();
1336 // Set the modified blocks unsent for all the clients
1337 for (std::vector<u16>::iterator i = clients.begin();
1338 i != clients.end(); ++i) {
1339 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1340 client->SetBlocksNotSent(block);
1345 void Server::peerAdded(con::Peer *peer)
1347 DSTACK(FUNCTION_NAME);
1348 verbosestream<<"Server::peerAdded(): peer->id="
1349 <<peer->id<<std::endl;
1352 c.type = con::PEER_ADDED;
1353 c.peer_id = peer->id;
1355 m_peer_change_queue.push(c);
1358 void Server::deletingPeer(con::Peer *peer, bool timeout)
1360 DSTACK(FUNCTION_NAME);
1361 verbosestream<<"Server::deletingPeer(): peer->id="
1362 <<peer->id<<", timeout="<<timeout<<std::endl;
1364 m_clients.event(peer->id, CSE_Disconnect);
1366 c.type = con::PEER_REMOVED;
1367 c.peer_id = peer->id;
1368 c.timeout = timeout;
1369 m_peer_change_queue.push(c);
1372 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1374 *retval = m_con.getPeerStat(peer_id,type);
1375 if (*retval == -1) return false;
1379 bool Server::getClientInfo(
1388 std::string* vers_string
1391 *state = m_clients.getClientState(peer_id);
1393 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1395 if (client == NULL) {
1400 *uptime = client->uptime();
1401 *ser_vers = client->serialization_version;
1402 *prot_vers = client->net_proto_version;
1404 *major = client->getMajor();
1405 *minor = client->getMinor();
1406 *patch = client->getPatch();
1407 *vers_string = client->getPatch();
1414 void Server::handlePeerChanges()
1416 while(m_peer_change_queue.size() > 0)
1418 con::PeerChange c = m_peer_change_queue.front();
1419 m_peer_change_queue.pop();
1421 verbosestream<<"Server: Handling peer change: "
1422 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1427 case con::PEER_ADDED:
1428 m_clients.CreateClient(c.peer_id);
1431 case con::PEER_REMOVED:
1432 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1436 FATAL_ERROR("Invalid peer change event received!");
1442 void Server::printToConsoleOnly(const std::string &text)
1445 m_admin_chat->outgoing_queue.push_back(
1446 new ChatEventChat("", utf8_to_wide(text)));
1448 std::cout << text << std::endl;
1452 void Server::Send(NetworkPacket* pkt)
1454 m_clients.send(pkt->getPeerId(),
1455 clientCommandFactoryTable[pkt->getCommand()].channel,
1457 clientCommandFactoryTable[pkt->getCommand()].reliable);
1460 void Server::SendMovement(u16 peer_id)
1462 DSTACK(FUNCTION_NAME);
1463 std::ostringstream os(std::ios_base::binary);
1465 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1467 pkt << g_settings->getFloat("movement_acceleration_default");
1468 pkt << g_settings->getFloat("movement_acceleration_air");
1469 pkt << g_settings->getFloat("movement_acceleration_fast");
1470 pkt << g_settings->getFloat("movement_speed_walk");
1471 pkt << g_settings->getFloat("movement_speed_crouch");
1472 pkt << g_settings->getFloat("movement_speed_fast");
1473 pkt << g_settings->getFloat("movement_speed_climb");
1474 pkt << g_settings->getFloat("movement_speed_jump");
1475 pkt << g_settings->getFloat("movement_liquid_fluidity");
1476 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1477 pkt << g_settings->getFloat("movement_liquid_sink");
1478 pkt << g_settings->getFloat("movement_gravity");
1483 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1485 if (!g_settings->getBool("enable_damage"))
1488 u16 peer_id = playersao->getPeerID();
1489 bool is_alive = playersao->getHP() > 0;
1492 SendPlayerHP(peer_id);
1497 void Server::SendHP(u16 peer_id, u8 hp)
1499 DSTACK(FUNCTION_NAME);
1501 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1506 void Server::SendBreath(u16 peer_id, u16 breath)
1508 DSTACK(FUNCTION_NAME);
1510 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1511 pkt << (u16) breath;
1515 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1516 const std::string &custom_reason, bool reconnect)
1518 assert(reason < SERVER_ACCESSDENIED_MAX);
1520 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1522 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1523 pkt << custom_reason;
1524 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1525 reason == SERVER_ACCESSDENIED_CRASH)
1526 pkt << custom_reason << (u8)reconnect;
1530 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1532 DSTACK(FUNCTION_NAME);
1534 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1539 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1540 v3f camera_point_target)
1542 DSTACK(FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1545 pkt << set_camera_point_target << camera_point_target;
1549 void Server::SendItemDef(u16 peer_id,
1550 IItemDefManager *itemdef, u16 protocol_version)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1558 u32 length of the next item
1559 zlib-compressed serialized ItemDefManager
1561 std::ostringstream tmp_os(std::ios::binary);
1562 itemdef->serialize(tmp_os, protocol_version);
1563 std::ostringstream tmp_os2(std::ios::binary);
1564 compressZlib(tmp_os.str(), tmp_os2);
1565 pkt.putLongString(tmp_os2.str());
1568 verbosestream << "Server: Sending item definitions to id(" << peer_id
1569 << "): size=" << pkt.getSize() << std::endl;
1574 void Server::SendNodeDef(u16 peer_id,
1575 INodeDefManager *nodedef, u16 protocol_version)
1577 DSTACK(FUNCTION_NAME);
1579 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1583 u32 length of the next item
1584 zlib-compressed serialized NodeDefManager
1586 std::ostringstream tmp_os(std::ios::binary);
1587 nodedef->serialize(tmp_os, protocol_version);
1588 std::ostringstream tmp_os2(std::ios::binary);
1589 compressZlib(tmp_os.str(), tmp_os2);
1591 pkt.putLongString(tmp_os2.str());
1594 verbosestream << "Server: Sending node definitions to id(" << peer_id
1595 << "): size=" << pkt.getSize() << std::endl;
1601 Non-static send methods
1604 void Server::SendInventory(PlayerSAO* playerSAO)
1606 DSTACK(FUNCTION_NAME);
1608 UpdateCrafting(playerSAO->getPlayer());
1614 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1616 std::ostringstream os;
1617 playerSAO->getInventory()->serialize(os);
1619 std::string s = os.str();
1621 pkt.putRawString(s.c_str(), s.size());
1625 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1627 DSTACK(FUNCTION_NAME);
1629 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1632 if (peer_id != PEER_ID_INEXISTENT) {
1636 m_clients.sendToAll(0, &pkt, true);
1640 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1641 const std::string &formname)
1643 DSTACK(FUNCTION_NAME);
1645 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1647 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1653 // Spawns a particle on peer with peer_id
1654 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1655 float expirationtime, float size, bool collisiondetection,
1656 bool collision_removal,
1657 bool vertical, const std::string &texture)
1659 DSTACK(FUNCTION_NAME);
1661 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1663 pkt << pos << velocity << acceleration << expirationtime
1664 << size << collisiondetection;
1665 pkt.putLongString(texture);
1667 pkt << collision_removal;
1669 if (peer_id != PEER_ID_INEXISTENT) {
1673 m_clients.sendToAll(0, &pkt, true);
1677 // Adds a ParticleSpawner on peer with peer_id
1678 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1679 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1680 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1681 bool vertical, const std::string &texture, u32 id)
1683 DSTACK(FUNCTION_NAME);
1685 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1687 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1688 << minacc << maxacc << minexptime << maxexptime << minsize
1689 << maxsize << collisiondetection;
1691 pkt.putLongString(texture);
1693 pkt << id << vertical;
1694 pkt << collision_removal;
1696 if (peer_id != PEER_ID_INEXISTENT) {
1700 m_clients.sendToAll(0, &pkt, true);
1704 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1706 DSTACK(FUNCTION_NAME);
1708 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1710 // Ugly error in this packet
1713 if (peer_id != PEER_ID_INEXISTENT) {
1717 m_clients.sendToAll(0, &pkt, true);
1722 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1724 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1726 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1727 << form->text << form->number << form->item << form->dir
1728 << form->align << form->offset << form->world_pos << form->size;
1733 void Server::SendHUDRemove(u16 peer_id, u32 id)
1735 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1740 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1742 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1743 pkt << id << (u8) stat;
1747 case HUD_STAT_SCALE:
1748 case HUD_STAT_ALIGN:
1749 case HUD_STAT_OFFSET:
1750 pkt << *(v2f *) value;
1754 pkt << *(std::string *) value;
1756 case HUD_STAT_WORLD_POS:
1757 pkt << *(v3f *) value;
1760 pkt << *(v2s32 *) value;
1762 case HUD_STAT_NUMBER:
1766 pkt << *(u32 *) value;
1773 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1775 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1777 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1779 pkt << flags << mask;
1784 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1786 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1787 pkt << param << value;
1791 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1792 const std::string &type, const std::vector<std::string> ¶ms)
1794 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1795 pkt << bgcolor << type << (u16) params.size();
1797 for(size_t i=0; i<params.size(); i++)
1803 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1806 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1809 pkt << do_override << (u16) (ratio * 65535);
1814 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1816 DSTACK(FUNCTION_NAME);
1818 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1819 pkt << time << time_speed;
1821 if (peer_id == PEER_ID_INEXISTENT) {
1822 m_clients.sendToAll(0, &pkt, true);
1829 void Server::SendPlayerHP(u16 peer_id)
1831 DSTACK(FUNCTION_NAME);
1832 PlayerSAO *playersao = getPlayerSAO(peer_id);
1833 // In some rare case if the player is disconnected
1834 // while Lua call l_punch, for example, this can be NULL
1838 SendHP(peer_id, playersao->getHP());
1839 m_script->player_event(playersao,"health_changed");
1841 // Send to other clients
1842 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1843 ActiveObjectMessage aom(playersao->getId(), true, str);
1844 playersao->m_messages_out.push(aom);
1847 void Server::SendPlayerBreath(u16 peer_id)
1849 DSTACK(FUNCTION_NAME);
1850 PlayerSAO *playersao = getPlayerSAO(peer_id);
1853 m_script->player_event(playersao, "breath_changed");
1854 SendBreath(peer_id, playersao->getBreath());
1857 void Server::SendMovePlayer(u16 peer_id)
1859 DSTACK(FUNCTION_NAME);
1860 Player *player = m_env->getPlayer(peer_id);
1863 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1864 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1867 v3f pos = player->getPosition();
1868 f32 pitch = player->getPitch();
1869 f32 yaw = player->getYaw();
1870 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1871 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1872 << " pitch=" << pitch
1880 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1882 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1885 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1886 << animation_frames[3] << animation_speed;
1891 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1893 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1894 pkt << first << third;
1897 void Server::SendPlayerPrivileges(u16 peer_id)
1899 Player *player = m_env->getPlayer(peer_id);
1901 if(player->peer_id == PEER_ID_INEXISTENT)
1904 std::set<std::string> privs;
1905 m_script->getAuth(player->getName(), NULL, &privs);
1907 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1908 pkt << (u16) privs.size();
1910 for(std::set<std::string>::const_iterator i = privs.begin();
1911 i != privs.end(); ++i) {
1918 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1920 Player *player = m_env->getPlayer(peer_id);
1922 if(player->peer_id == PEER_ID_INEXISTENT)
1925 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1926 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1930 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1932 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1933 pkt.putRawString(datas.c_str(), datas.size());
1935 return pkt.getSize();
1938 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1940 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1941 datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 m_clients.send(pkt.getPeerId(),
1946 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1951 s32 Server::playSound(const SimpleSoundSpec &spec,
1952 const ServerSoundParams ¶ms)
1954 // Find out initial position of sound
1955 bool pos_exists = false;
1956 v3f pos = params.getPos(m_env, &pos_exists);
1957 // If position is not found while it should be, cancel sound
1958 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1961 // Filter destination clients
1962 std::vector<u16> dst_clients;
1963 if(params.to_player != "")
1965 Player *player = m_env->getPlayer(params.to_player.c_str());
1967 infostream<<"Server::playSound: Player \""<<params.to_player
1968 <<"\" not found"<<std::endl;
1971 if(player->peer_id == PEER_ID_INEXISTENT){
1972 infostream<<"Server::playSound: Player \""<<params.to_player
1973 <<"\" not connected"<<std::endl;
1976 dst_clients.push_back(player->peer_id);
1979 std::vector<u16> clients = m_clients.getClientIDs();
1981 for(std::vector<u16>::iterator
1982 i = clients.begin(); i != clients.end(); ++i) {
1983 Player *player = m_env->getPlayer(*i);
1988 if(player->getPosition().getDistanceFrom(pos) >
1989 params.max_hear_distance)
1992 dst_clients.push_back(*i);
1996 if(dst_clients.empty())
2000 s32 id = m_next_sound_id++;
2001 // The sound will exist as a reference in m_playing_sounds
2002 m_playing_sounds[id] = ServerPlayingSound();
2003 ServerPlayingSound &psound = m_playing_sounds[id];
2004 psound.params = params;
2006 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2007 pkt << id << spec.name << (float) (spec.gain * params.gain)
2008 << (u8) params.type << pos << params.object << params.loop;
2010 for(std::vector<u16>::iterator i = dst_clients.begin();
2011 i != dst_clients.end(); ++i) {
2012 psound.clients.insert(*i);
2013 m_clients.send(*i, 0, &pkt, true);
2017 void Server::stopSound(s32 handle)
2019 // Get sound reference
2020 std::map<s32, ServerPlayingSound>::iterator i =
2021 m_playing_sounds.find(handle);
2022 if(i == m_playing_sounds.end())
2024 ServerPlayingSound &psound = i->second;
2026 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2029 for(std::set<u16>::iterator i = psound.clients.begin();
2030 i != psound.clients.end(); ++i) {
2032 m_clients.send(*i, 0, &pkt, true);
2034 // Remove sound reference
2035 m_playing_sounds.erase(i);
2038 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2039 std::vector<u16> *far_players, float far_d_nodes)
2041 float maxd = far_d_nodes*BS;
2042 v3f p_f = intToFloat(p, BS);
2044 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2047 std::vector<u16> clients = m_clients.getClientIDs();
2048 for(std::vector<u16>::iterator i = clients.begin();
2049 i != clients.end(); ++i) {
2052 if(Player *player = m_env->getPlayer(*i)) {
2053 // If player is far away, only set modified blocks not sent
2054 v3f player_pos = player->getPosition();
2055 if(player_pos.getDistanceFrom(p_f) > maxd) {
2056 far_players->push_back(*i);
2063 m_clients.send(*i, 0, &pkt, true);
2067 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2068 std::vector<u16> *far_players, float far_d_nodes,
2069 bool remove_metadata)
2071 float maxd = far_d_nodes*BS;
2072 v3f p_f = intToFloat(p, BS);
2074 std::vector<u16> clients = m_clients.getClientIDs();
2075 for(std::vector<u16>::iterator i = clients.begin();
2076 i != clients.end(); ++i) {
2080 if(Player *player = m_env->getPlayer(*i)) {
2081 // If player is far away, only set modified blocks not sent
2082 v3f player_pos = player->getPosition();
2083 if(player_pos.getDistanceFrom(p_f) > maxd) {
2084 far_players->push_back(*i);
2090 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2092 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2094 pkt << p << n.param0 << n.param1 << n.param2
2095 << (u8) (remove_metadata ? 0 : 1);
2097 if (!remove_metadata) {
2098 if (client->net_proto_version <= 21) {
2099 // Old clients always clear metadata; fix it
2100 // by sending the full block again.
2101 client->SetBlockNotSent(getNodeBlockPos(p));
2108 if (pkt.getSize() > 0)
2109 m_clients.send(*i, 0, &pkt, true);
2113 void Server::setBlockNotSent(v3s16 p)
2115 std::vector<u16> clients = m_clients.getClientIDs();
2117 for(std::vector<u16>::iterator i = clients.begin();
2118 i != clients.end(); ++i) {
2119 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2120 client->SetBlockNotSent(p);
2125 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2127 DSTACK(FUNCTION_NAME);
2129 v3s16 p = block->getPos();
2132 Create a packet with the block in the right format
2135 std::ostringstream os(std::ios_base::binary);
2136 block->serialize(os, ver, false);
2137 block->serializeNetworkSpecific(os, net_proto_version);
2138 std::string s = os.str();
2140 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2143 pkt.putRawString(s.c_str(), s.size());
2147 void Server::SendBlocks(float dtime)
2149 DSTACK(FUNCTION_NAME);
2151 MutexAutoLock envlock(m_env_mutex);
2152 //TODO check if one big lock could be faster then multiple small ones
2154 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2156 std::vector<PrioritySortedBlockTransfer> queue;
2158 s32 total_sending = 0;
2161 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2163 std::vector<u16> clients = m_clients.getClientIDs();
2166 for(std::vector<u16>::iterator i = clients.begin();
2167 i != clients.end(); ++i) {
2168 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2173 total_sending += client->SendingCount();
2174 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2180 // Lowest priority number comes first.
2181 // Lowest is most important.
2182 std::sort(queue.begin(), queue.end());
2185 for(u32 i=0; i<queue.size(); i++)
2187 //TODO: Calculate limit dynamically
2188 if(total_sending >= g_settings->getS32
2189 ("max_simultaneous_block_sends_server_total"))
2192 PrioritySortedBlockTransfer q = queue[i];
2194 MapBlock *block = NULL;
2197 block = m_env->getMap().getBlockNoCreate(q.pos);
2199 catch(InvalidPositionException &e)
2204 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2209 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2211 client->SentBlock(q.pos);
2217 void Server::fillMediaCache()
2219 DSTACK(FUNCTION_NAME);
2221 infostream<<"Server: Calculating media file checksums"<<std::endl;
2223 // Collect all media file paths
2224 std::vector<std::string> paths;
2225 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2226 i != m_mods.end(); ++i) {
2227 const ModSpec &mod = *i;
2228 paths.push_back(mod.path + DIR_DELIM + "textures");
2229 paths.push_back(mod.path + DIR_DELIM + "sounds");
2230 paths.push_back(mod.path + DIR_DELIM + "media");
2231 paths.push_back(mod.path + DIR_DELIM + "models");
2233 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2235 // Collect media file information from paths into cache
2236 for(std::vector<std::string>::iterator i = paths.begin();
2237 i != paths.end(); ++i) {
2238 std::string mediapath = *i;
2239 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2240 for (u32 j = 0; j < dirlist.size(); j++) {
2241 if (dirlist[j].dir) // Ignode dirs
2243 std::string filename = dirlist[j].name;
2244 // If name contains illegal characters, ignore the file
2245 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2246 infostream<<"Server: ignoring illegal file name: \""
2247 << filename << "\"" << std::endl;
2250 // If name is not in a supported format, ignore it
2251 const char *supported_ext[] = {
2252 ".png", ".jpg", ".bmp", ".tga",
2253 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2255 ".x", ".b3d", ".md2", ".obj",
2258 if (removeStringEnd(filename, supported_ext) == ""){
2259 infostream << "Server: ignoring unsupported file extension: \""
2260 << filename << "\"" << std::endl;
2263 // Ok, attempt to load the file and add to cache
2264 std::string filepath = mediapath + DIR_DELIM + filename;
2266 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2268 errorstream << "Server::fillMediaCache(): Could not open \""
2269 << filename << "\" for reading" << std::endl;
2272 std::ostringstream tmp_os(std::ios_base::binary);
2276 fis.read(buf, 1024);
2277 std::streamsize len = fis.gcount();
2278 tmp_os.write(buf, len);
2287 errorstream<<"Server::fillMediaCache(): Failed to read \""
2288 << filename << "\"" << std::endl;
2291 if(tmp_os.str().length() == 0) {
2292 errorstream << "Server::fillMediaCache(): Empty file \""
2293 << filepath << "\"" << std::endl;
2298 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2300 unsigned char *digest = sha1.getDigest();
2301 std::string sha1_base64 = base64_encode(digest, 20);
2302 std::string sha1_hex = hex_encode((char*)digest, 20);
2306 m_media[filename] = MediaInfo(filepath, sha1_base64);
2307 verbosestream << "Server: " << sha1_hex << " is " << filename
2313 void Server::sendMediaAnnouncement(u16 peer_id)
2315 DSTACK(FUNCTION_NAME);
2317 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2321 std::ostringstream os(std::ios_base::binary);
2323 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2324 pkt << (u16) m_media.size();
2326 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2327 i != m_media.end(); ++i) {
2328 pkt << i->first << i->second.sha1_digest;
2331 pkt << g_settings->get("remote_media");
2335 struct SendableMedia
2341 SendableMedia(const std::string &name_="", const std::string &path_="",
2342 const std::string &data_=""):
2349 void Server::sendRequestedMedia(u16 peer_id,
2350 const std::vector<std::string> &tosend)
2352 DSTACK(FUNCTION_NAME);
2354 verbosestream<<"Server::sendRequestedMedia(): "
2355 <<"Sending files to client"<<std::endl;
2359 // Put 5kB in one bunch (this is not accurate)
2360 u32 bytes_per_bunch = 5000;
2362 std::vector< std::vector<SendableMedia> > file_bunches;
2363 file_bunches.push_back(std::vector<SendableMedia>());
2365 u32 file_size_bunch_total = 0;
2367 for(std::vector<std::string>::const_iterator i = tosend.begin();
2368 i != tosend.end(); ++i) {
2369 const std::string &name = *i;
2371 if(m_media.find(name) == m_media.end()) {
2372 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2373 <<"unknown file \""<<(name)<<"\""<<std::endl;
2377 //TODO get path + name
2378 std::string tpath = m_media[name].path;
2381 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2382 if(fis.good() == false){
2383 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2384 <<tpath<<"\" for reading"<<std::endl;
2387 std::ostringstream tmp_os(std::ios_base::binary);
2391 fis.read(buf, 1024);
2392 std::streamsize len = fis.gcount();
2393 tmp_os.write(buf, len);
2394 file_size_bunch_total += len;
2403 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2404 <<name<<"\""<<std::endl;
2407 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2408 <<tname<<"\""<<std::endl;*/
2410 file_bunches[file_bunches.size()-1].push_back(
2411 SendableMedia(name, tpath, tmp_os.str()));
2413 // Start next bunch if got enough data
2414 if(file_size_bunch_total >= bytes_per_bunch) {
2415 file_bunches.push_back(std::vector<SendableMedia>());
2416 file_size_bunch_total = 0;
2421 /* Create and send packets */
2423 u16 num_bunches = file_bunches.size();
2424 for(u16 i = 0; i < num_bunches; i++) {
2427 u16 total number of texture bunches
2428 u16 index of this bunch
2429 u32 number of files in this bunch
2438 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2439 pkt << num_bunches << i << (u32) file_bunches[i].size();
2441 for(std::vector<SendableMedia>::iterator
2442 j = file_bunches[i].begin();
2443 j != file_bunches[i].end(); ++j) {
2445 pkt.putLongString(j->data);
2448 verbosestream << "Server::sendRequestedMedia(): bunch "
2449 << i << "/" << num_bunches
2450 << " files=" << file_bunches[i].size()
2451 << " size=" << pkt.getSize() << std::endl;
2456 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2458 if(m_detached_inventories.count(name) == 0) {
2459 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2462 Inventory *inv = m_detached_inventories[name];
2463 std::ostringstream os(std::ios_base::binary);
2465 os << serializeString(name);
2469 std::string s = os.str();
2471 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2472 pkt.putRawString(s.c_str(), s.size());
2474 if (peer_id != PEER_ID_INEXISTENT) {
2478 m_clients.sendToAll(0, &pkt, true);
2482 void Server::sendDetachedInventories(u16 peer_id)
2484 DSTACK(FUNCTION_NAME);
2486 for(std::map<std::string, Inventory*>::iterator
2487 i = m_detached_inventories.begin();
2488 i != m_detached_inventories.end(); ++i) {
2489 const std::string &name = i->first;
2490 //Inventory *inv = i->second;
2491 sendDetachedInventory(name, peer_id);
2499 void Server::DiePlayer(u16 peer_id)
2501 DSTACK(FUNCTION_NAME);
2502 PlayerSAO *playersao = getPlayerSAO(peer_id);
2503 // In some rare cases this can be NULL -- if the player is disconnected
2504 // when a Lua function modifies l_punch, for example
2508 infostream << "Server::DiePlayer(): Player "
2509 << playersao->getPlayer()->getName()
2510 << " dies" << std::endl;
2512 playersao->setHP(0);
2514 // Trigger scripted stuff
2515 m_script->on_dieplayer(playersao);
2517 SendPlayerHP(peer_id);
2518 SendDeathscreen(peer_id, false, v3f(0,0,0));
2521 void Server::RespawnPlayer(u16 peer_id)
2523 DSTACK(FUNCTION_NAME);
2525 PlayerSAO *playersao = getPlayerSAO(peer_id);
2528 infostream << "Server::RespawnPlayer(): Player "
2529 << playersao->getPlayer()->getName()
2530 << " respawns" << std::endl;
2532 playersao->setHP(PLAYER_MAX_HP);
2533 playersao->setBreath(PLAYER_MAX_BREATH);
2535 SendPlayerHP(peer_id);
2536 SendPlayerBreath(peer_id);
2538 bool repositioned = m_script->on_respawnplayer(playersao);
2540 v3f pos = findSpawnPos();
2541 // setPos will send the new position to client
2542 playersao->setPos(pos);
2547 void Server::DenySudoAccess(u16 peer_id)
2549 DSTACK(FUNCTION_NAME);
2551 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2556 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2557 const std::string &str_reason, bool reconnect)
2559 if (proto_ver >= 25) {
2560 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2562 std::wstring wreason = utf8_to_wide(
2563 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2564 accessDeniedStrings[(u8)reason]);
2565 SendAccessDenied_Legacy(peer_id, wreason);
2568 m_clients.event(peer_id, CSE_SetDenied);
2569 m_con.DisconnectPeer(peer_id);
2573 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2575 DSTACK(FUNCTION_NAME);
2577 SendAccessDenied(peer_id, reason, custom_reason);
2578 m_clients.event(peer_id, CSE_SetDenied);
2579 m_con.DisconnectPeer(peer_id);
2582 // 13/03/15: remove this function when protocol version 25 will become
2583 // the minimum version for MT users, maybe in 1 year
2584 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2586 DSTACK(FUNCTION_NAME);
2588 SendAccessDenied_Legacy(peer_id, reason);
2589 m_clients.event(peer_id, CSE_SetDenied);
2590 m_con.DisconnectPeer(peer_id);
2593 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2595 DSTACK(FUNCTION_NAME);
2598 RemoteClient* client = getClient(peer_id, CS_Invalid);
2600 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2602 // Right now, the auth mechs don't change between login and sudo mode.
2603 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2604 client->allowed_sudo_mechs = sudo_auth_mechs;
2606 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2607 << g_settings->getFloat("dedicated_server_step")
2611 m_clients.event(peer_id, CSE_AuthAccept);
2613 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2615 // We only support SRP right now
2616 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2618 resp_pkt << sudo_auth_mechs;
2620 m_clients.event(peer_id, CSE_SudoSuccess);
2624 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2626 DSTACK(FUNCTION_NAME);
2627 std::wstring message;
2630 Clear references to playing sounds
2632 for(std::map<s32, ServerPlayingSound>::iterator
2633 i = m_playing_sounds.begin();
2634 i != m_playing_sounds.end();)
2636 ServerPlayingSound &psound = i->second;
2637 psound.clients.erase(peer_id);
2638 if(psound.clients.empty())
2639 m_playing_sounds.erase(i++);
2644 Player *player = m_env->getPlayer(peer_id);
2646 /* Run scripts and remove from environment */
2650 PlayerSAO *playersao = player->getPlayerSAO();
2653 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2655 playersao->disconnected();
2663 if(player != NULL && reason != CDR_DENY) {
2664 std::ostringstream os(std::ios_base::binary);
2665 std::vector<u16> clients = m_clients.getClientIDs();
2667 for(std::vector<u16>::iterator i = clients.begin();
2668 i != clients.end(); ++i) {
2670 Player *player = m_env->getPlayer(*i);
2674 // Get name of player
2675 os << player->getName() << " ";
2678 std::string name = player->getName();
2679 actionstream << name << " "
2680 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2681 << " List of players: " << os.str() << std::endl;
2683 m_admin_chat->outgoing_queue.push_back(
2684 new ChatEventNick(CET_NICK_REMOVE, name));
2688 MutexAutoLock env_lock(m_env_mutex);
2689 m_clients.DeleteClient(peer_id);
2693 // Send leave chat message to all remaining clients
2694 if(message.length() != 0)
2695 SendChatMessage(PEER_ID_INEXISTENT,message);
2698 void Server::UpdateCrafting(Player* player)
2700 DSTACK(FUNCTION_NAME);
2702 // Get a preview for crafting
2704 InventoryLocation loc;
2705 loc.setPlayer(player->getName());
2706 std::vector<ItemStack> output_replacements;
2707 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2708 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2710 // Put the new preview in
2711 InventoryList *plist = player->inventory.getList("craftpreview");
2712 sanity_check(plist);
2713 sanity_check(plist->getSize() >= 1);
2714 plist->changeItem(0, preview);
2717 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2719 if (evt->type == CET_NICK_ADD) {
2720 // The terminal informed us of its nick choice
2721 m_admin_nick = ((ChatEventNick *)evt)->nick;
2722 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2723 errorstream << "You haven't set up an account." << std::endl
2724 << "Please log in using the client as '"
2725 << m_admin_nick << "' with a secure password." << std::endl
2726 << "Until then, you can't execute admin tasks via the console," << std::endl
2727 << "and everybody can claim the user account instead of you," << std::endl
2728 << "giving them full control over this server." << std::endl;
2731 assert(evt->type == CET_CHAT);
2732 handleAdminChat((ChatEventChat *)evt);
2736 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2737 const std::wstring &wmessage, bool check_shout_priv,
2738 u16 peer_id_to_avoid_sending)
2740 // If something goes wrong, this player is to blame
2741 RollbackScopeActor rollback_scope(m_rollback,
2742 std::string("player:") + name);
2746 // Whether to send line to the player that sent the message, or to all players
2747 bool broadcast_line = true;
2750 bool ate = m_script->on_chat_message(name,
2751 wide_to_utf8(wmessage));
2752 // If script ate the message, don't proceed
2756 // Commands are implemented in Lua, so only catch invalid
2757 // commands that were not "eaten" and send an error back
2758 if (wmessage[0] == L'/') {
2759 std::wstring wcmd = wmessage.substr(1);
2760 broadcast_line = false;
2761 if (wcmd.length() == 0)
2762 line += L"-!- Empty command";
2764 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2766 if (check_shout_priv && !checkPriv(name, "shout")) {
2767 line += L"-!- You don't have permission to shout.";
2768 broadcast_line = false;
2778 Tell calling method to send the message to sender
2780 if (!broadcast_line) {
2784 Send the message to others
2786 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2788 std::vector<u16> clients = m_clients.getClientIDs();
2790 for (u16 i = 0; i < clients.size(); i++) {
2791 u16 cid = clients[i];
2792 if (cid != peer_id_to_avoid_sending)
2793 SendChatMessage(cid, line);
2799 void Server::handleAdminChat(const ChatEventChat *evt)
2801 std::string name = evt->nick;
2802 std::wstring wname = utf8_to_wide(name);
2803 std::wstring wmessage = evt->evt_msg;
2805 std::wstring answer = handleChat(name, wname, wmessage);
2807 // If asked to send answer to sender
2808 if (!answer.empty()) {
2809 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2813 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2815 RemoteClient *client = getClientNoEx(peer_id,state_min);
2817 throw ClientNotFoundException("Client not found");
2821 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2823 return m_clients.getClientNoEx(peer_id, state_min);
2826 std::string Server::getPlayerName(u16 peer_id)
2828 Player *player = m_env->getPlayer(peer_id);
2830 return "[id="+itos(peer_id)+"]";
2831 return player->getName();
2834 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2836 Player *player = m_env->getPlayer(peer_id);
2839 return player->getPlayerSAO();
2842 std::wstring Server::getStatusString()
2844 std::wostringstream os(std::ios_base::binary);
2847 os<<L"version="<<narrow_to_wide(g_version_string);
2849 os<<L", uptime="<<m_uptime.get();
2851 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2852 // Information about clients
2855 std::vector<u16> clients = m_clients.getClientIDs();
2856 for(std::vector<u16>::iterator i = clients.begin();
2857 i != clients.end(); ++i) {
2859 Player *player = m_env->getPlayer(*i);
2860 // Get name of player
2861 std::wstring name = L"unknown";
2863 name = narrow_to_wide(player->getName());
2864 // Add name to information string
2872 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2873 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2874 if(g_settings->get("motd") != "")
2875 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2879 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2881 std::set<std::string> privs;
2882 m_script->getAuth(name, NULL, &privs);
2886 bool Server::checkPriv(const std::string &name, const std::string &priv)
2888 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2889 return (privs.count(priv) != 0);
2892 void Server::reportPrivsModified(const std::string &name)
2895 std::vector<u16> clients = m_clients.getClientIDs();
2896 for(std::vector<u16>::iterator i = clients.begin();
2897 i != clients.end(); ++i) {
2898 Player *player = m_env->getPlayer(*i);
2899 reportPrivsModified(player->getName());
2902 Player *player = m_env->getPlayer(name.c_str());
2905 SendPlayerPrivileges(player->peer_id);
2906 PlayerSAO *sao = player->getPlayerSAO();
2909 sao->updatePrivileges(
2910 getPlayerEffectivePrivs(name),
2915 void Server::reportInventoryFormspecModified(const std::string &name)
2917 Player *player = m_env->getPlayer(name.c_str());
2920 SendPlayerInventoryFormspec(player->peer_id);
2923 void Server::setIpBanned(const std::string &ip, const std::string &name)
2925 m_banmanager->add(ip, name);
2928 void Server::unsetIpBanned(const std::string &ip_or_name)
2930 m_banmanager->remove(ip_or_name);
2933 std::string Server::getBanDescription(const std::string &ip_or_name)
2935 return m_banmanager->getBanDescription(ip_or_name);
2938 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2940 // m_env will be NULL if the server is initializing
2944 if (m_admin_nick == name && !m_admin_nick.empty()) {
2945 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2948 Player *player = m_env->getPlayer(name);
2953 if (player->peer_id == PEER_ID_INEXISTENT)
2956 SendChatMessage(player->peer_id, msg);
2959 bool Server::showFormspec(const char *playername, const std::string &formspec,
2960 const std::string &formname)
2962 // m_env will be NULL if the server is initializing
2966 Player *player = m_env->getPlayer(playername);
2970 SendShowFormspecMessage(player->peer_id, formspec, formname);
2974 u32 Server::hudAdd(Player *player, HudElement *form)
2979 u32 id = player->addHud(form);
2981 SendHUDAdd(player->peer_id, id, form);
2986 bool Server::hudRemove(Player *player, u32 id) {
2990 HudElement* todel = player->removeHud(id);
2997 SendHUDRemove(player->peer_id, id);
3001 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3006 SendHUDChange(player->peer_id, id, stat, data);
3010 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3015 SendHUDSetFlags(player->peer_id, flags, mask);
3016 player->hud_flags &= ~mask;
3017 player->hud_flags |= flags;
3019 PlayerSAO* playersao = player->getPlayerSAO();
3021 if (playersao == NULL)
3024 m_script->player_event(playersao, "hud_changed");
3028 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3032 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3035 player->setHotbarItemcount(hotbar_itemcount);
3036 std::ostringstream os(std::ios::binary);
3037 writeS32(os, hotbar_itemcount);
3038 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3042 s32 Server::hudGetHotbarItemcount(Player *player)
3046 return player->getHotbarItemcount();
3049 void Server::hudSetHotbarImage(Player *player, std::string name)
3054 player->setHotbarImage(name);
3055 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3058 std::string Server::hudGetHotbarImage(Player *player)
3062 return player->getHotbarImage();
3065 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3070 player->setHotbarSelectedImage(name);
3071 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3074 std::string Server::hudGetHotbarSelectedImage(Player *player)
3079 return player->getHotbarSelectedImage();
3082 bool Server::setLocalPlayerAnimations(Player *player,
3083 v2s32 animation_frames[4], f32 frame_speed)
3088 player->setLocalAnimations(animation_frames, frame_speed);
3089 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3093 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3098 player->eye_offset_first = first;
3099 player->eye_offset_third = third;
3100 SendEyeOffset(player->peer_id, first, third);
3104 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3105 const std::string &type, const std::vector<std::string> ¶ms)
3110 player->setSky(bgcolor, type, params);
3111 SendSetSky(player->peer_id, bgcolor, type, params);
3115 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3121 player->overrideDayNightRatio(do_override, ratio);
3122 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3126 void Server::notifyPlayers(const std::wstring &msg)
3128 SendChatMessage(PEER_ID_INEXISTENT,msg);
3131 void Server::spawnParticle(const std::string &playername, v3f pos,
3132 v3f velocity, v3f acceleration,
3133 float expirationtime, float size, bool
3134 collisiondetection, bool collision_removal,
3135 bool vertical, const std::string &texture)
3137 // m_env will be NULL if the server is initializing
3141 u16 peer_id = PEER_ID_INEXISTENT;
3142 if (playername != "") {
3143 Player* player = m_env->getPlayer(playername.c_str());
3146 peer_id = player->peer_id;
3149 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3150 expirationtime, size, collisiondetection,
3151 collision_removal, vertical, texture);
3154 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3155 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3156 float minexptime, float maxexptime, float minsize, float maxsize,
3157 bool collisiondetection, bool collision_removal,
3158 bool vertical, const std::string &texture,
3159 const std::string &playername)
3161 // m_env will be NULL if the server is initializing
3165 u16 peer_id = PEER_ID_INEXISTENT;
3166 if (playername != "") {
3167 Player* player = m_env->getPlayer(playername.c_str());
3170 peer_id = player->peer_id;
3173 u32 id = m_env->addParticleSpawner(spawntime);
3174 SendAddParticleSpawner(peer_id, amount, spawntime,
3175 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3176 minexptime, maxexptime, minsize, maxsize,
3177 collisiondetection, collision_removal, vertical, texture, id);
3182 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3184 // m_env will be NULL if the server is initializing
3186 throw ServerError("Can't delete particle spawners during initialisation!");
3188 u16 peer_id = PEER_ID_INEXISTENT;
3189 if (playername != "") {
3190 Player* player = m_env->getPlayer(playername.c_str());
3193 peer_id = player->peer_id;
3196 m_env->deleteParticleSpawner(id);
3197 SendDeleteParticleSpawner(peer_id, id);
3200 void Server::deleteParticleSpawnerAll(u32 id)
3202 m_env->deleteParticleSpawner(id);
3203 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3206 Inventory* Server::createDetachedInventory(const std::string &name)
3208 if(m_detached_inventories.count(name) > 0){
3209 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3210 delete m_detached_inventories[name];
3212 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3214 Inventory *inv = new Inventory(m_itemdef);
3216 m_detached_inventories[name] = inv;
3217 //TODO find a better way to do this
3218 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3222 // actions: time-reversed list
3223 // Return value: success/failure
3224 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3225 std::list<std::string> *log)
3227 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3228 ServerMap *map = (ServerMap*)(&m_env->getMap());
3230 // Fail if no actions to handle
3231 if(actions.empty()){
3232 log->push_back("Nothing to do.");
3239 for(std::list<RollbackAction>::const_iterator
3240 i = actions.begin();
3241 i != actions.end(); ++i)
3243 const RollbackAction &action = *i;
3245 bool success = action.applyRevert(map, this, this);
3248 std::ostringstream os;
3249 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3250 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3252 log->push_back(os.str());
3254 std::ostringstream os;
3255 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3256 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3258 log->push_back(os.str());
3262 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3263 <<" failed"<<std::endl;
3265 // Call it done if less than half failed
3266 return num_failed <= num_tried/2;
3269 // IGameDef interface
3271 IItemDefManager *Server::getItemDefManager()
3276 INodeDefManager *Server::getNodeDefManager()
3281 ICraftDefManager *Server::getCraftDefManager()
3285 ITextureSource *Server::getTextureSource()
3289 IShaderSource *Server::getShaderSource()
3293 scene::ISceneManager *Server::getSceneManager()
3298 u16 Server::allocateUnknownNodeId(const std::string &name)
3300 return m_nodedef->allocateDummy(name);
3303 ISoundManager *Server::getSoundManager()
3305 return &dummySoundManager;
3308 MtEventManager *Server::getEventManager()
3313 IWritableItemDefManager *Server::getWritableItemDefManager()
3318 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3323 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3328 const ModSpec *Server::getModSpec(const std::string &modname) const
3330 std::vector<ModSpec>::const_iterator it;
3331 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3332 const ModSpec &mod = *it;
3333 if (mod.name == modname)
3339 void Server::getModNames(std::vector<std::string> &modlist)
3341 std::vector<ModSpec>::iterator it;
3342 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3343 modlist.push_back(it->name);
3346 std::string Server::getBuiltinLuaPath()
3348 return porting::path_share + DIR_DELIM + "builtin";
3351 v3f Server::findSpawnPos()
3353 ServerMap &map = m_env->getServerMap();
3355 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3356 return nodeposf * BS;
3359 bool is_good = false;
3361 // Try to find a good place a few times
3362 for(s32 i = 0; i < 4000 && !is_good; i++) {
3364 // We're going to try to throw the player to this position
3365 v2s16 nodepos2d = v2s16(
3366 -range + (myrand() % (range * 2)),
3367 -range + (myrand() % (range * 2)));
3369 // Get spawn level at point
3370 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3371 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3372 // the mapgen to signify an unsuitable spawn position
3373 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3376 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3379 for (s32 i = 0; i < 10; i++) {
3380 v3s16 blockpos = getNodeBlockPos(nodepos);
3381 map.emergeBlock(blockpos, true);
3382 content_t c = map.getNodeNoEx(nodepos).getContent();
3383 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3385 if (air_count >= 2) {
3386 nodeposf = intToFloat(nodepos, BS);
3387 // Don't spawn the player outside map boundaries
3388 if (objectpos_over_limit(nodeposf))
3401 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3403 bool newplayer = false;
3406 Try to get an existing player
3408 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3410 // If player is already connected, cancel
3411 if(player != NULL && player->peer_id != 0)
3413 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3418 If player with the wanted peer_id already exists, cancel.
3420 if(m_env->getPlayer(peer_id) != NULL)
3422 infostream<<"emergePlayer(): Player with wrong name but same"
3423 " peer_id already exists"<<std::endl;
3427 // Load player if it isn't already loaded
3429 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3432 // Create player if it doesn't exist
3435 player = new RemotePlayer(this, name);
3436 // Set player position
3437 infostream<<"Server: Finding spawn place for player \""
3438 <<name<<"\""<<std::endl;
3439 v3f pos = findSpawnPos();
3440 player->setPosition(pos);
3442 // Make sure the player is saved
3443 player->setModified(true);
3445 // Add player to environment
3446 m_env->addPlayer(player);
3448 // If the player exists, ensure that they respawn inside legal bounds
3449 // This fixes an assert crash when the player can't be added
3450 // to the environment
3451 if (objectpos_over_limit(player->getPosition())) {
3452 actionstream << "Respawn position for player \""
3453 << name << "\" outside limits, resetting" << std::endl;
3454 v3f pos = findSpawnPos();
3455 player->setPosition(pos);
3459 // Create a new player active object
3460 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3461 getPlayerEffectivePrivs(player->getName()),
3464 player->protocol_version = proto_version;
3466 /* Clean up old HUD elements from previous sessions */
3469 /* Add object to environment */
3470 m_env->addActiveObject(playersao);
3474 m_script->on_newplayer(playersao);
3480 void dedicated_server_loop(Server &server, bool &kill)
3482 DSTACK(FUNCTION_NAME);
3484 verbosestream<<"dedicated_server_loop()"<<std::endl;
3486 IntervalLimiter m_profiler_interval;
3488 static const float steplen = g_settings->getFloat("dedicated_server_step");
3489 static const float profiler_print_interval =
3490 g_settings->getFloat("profiler_print_interval");
3493 // This is kind of a hack but can be done like this
3494 // because server.step() is very light
3496 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3497 sleep_ms((int)(steplen*1000.0));
3499 server.step(steplen);
3501 if(server.getShutdownRequested() || kill)
3503 infostream<<"Dedicated server quitting"<<std::endl;
3505 if(g_settings->getBool("server_announce"))
3506 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3514 if (profiler_print_interval != 0) {
3515 if(m_profiler_interval.step(steplen, profiler_print_interval))
3517 infostream<<"Profiler:"<<std::endl;
3518 g_profiler->print(infostream);
3519 g_profiler->clear();