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 // Send information about joining in chat
1124 std::string name = "unknown";
1125 Player *player = m_env->getPlayer(peer_id);
1127 name = player->getName();
1129 std::wstring message;
1131 message += narrow_to_wide(name);
1132 message += L" joined the game.";
1133 SendChatMessage(PEER_ID_INEXISTENT,message);
1135 m_admin_chat->outgoing_queue.push_back(
1136 new ChatEventNick(CET_NICK_ADD, name));
1139 Address addr = getPeerAddress(player->peer_id);
1140 std::string ip_str = addr.serializeString();
1141 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1146 std::vector<std::string> names = m_clients.getPlayerNames();
1148 actionstream<<player->getName() <<" joins game. List of players: ";
1150 for (std::vector<std::string>::iterator i = names.begin();
1151 i != names.end(); ++i) {
1152 actionstream << *i << " ";
1155 actionstream << player->getName() <<std::endl;
1160 inline void Server::handleCommand(NetworkPacket* pkt)
1162 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1163 (this->*opHandle.handler)(pkt);
1166 void Server::ProcessData(NetworkPacket *pkt)
1168 DSTACK(FUNCTION_NAME);
1169 // Environment is locked first.
1170 MutexAutoLock envlock(m_env_mutex);
1172 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1173 u32 peer_id = pkt->getPeerId();
1176 Address address = getPeerAddress(peer_id);
1177 std::string addr_s = address.serializeString();
1179 if(m_banmanager->isIpBanned(addr_s)) {
1180 std::string ban_name = m_banmanager->getBanName(addr_s);
1181 infostream << "Server: A banned client tried to connect from "
1182 << addr_s << "; banned name was "
1183 << ban_name << std::endl;
1184 // This actually doesn't seem to transfer to the client
1185 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1186 + utf8_to_wide(ban_name));
1190 catch(con::PeerNotFoundException &e) {
1192 * no peer for this packet found
1193 * most common reason is peer timeout, e.g. peer didn't
1194 * respond for some time, your server was overloaded or
1197 infostream << "Server::ProcessData(): Canceling: peer "
1198 << peer_id << " not found" << std::endl;
1203 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1205 // Command must be handled into ToServerCommandHandler
1206 if (command >= TOSERVER_NUM_MSG_TYPES) {
1207 infostream << "Server: Ignoring unknown command "
1208 << command << std::endl;
1212 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1217 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1219 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1220 errorstream << "Server::ProcessData(): Cancelling: Peer"
1221 " serialization format invalid or not initialized."
1222 " Skipping incoming command=" << command << std::endl;
1226 /* Handle commands related to client startup */
1227 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1232 if (m_clients.getClientState(peer_id) < CS_Active) {
1233 if (command == TOSERVER_PLAYERPOS) return;
1235 errorstream << "Got packet command: " << command << " for peer id "
1236 << peer_id << " but client isn't active yet. Dropping packet "
1242 } catch (SendFailedException &e) {
1243 errorstream << "Server::ProcessData(): SendFailedException: "
1244 << "what=" << e.what()
1246 } catch (PacketError &e) {
1247 actionstream << "Server::ProcessData(): PacketError: "
1248 << "what=" << e.what()
1253 void Server::setTimeOfDay(u32 time)
1255 m_env->setTimeOfDay(time);
1256 m_time_of_day_send_timer = 0;
1259 void Server::onMapEditEvent(MapEditEvent *event)
1261 if(m_ignore_map_edit_events)
1263 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1265 MapEditEvent *e = event->clone();
1266 m_unsent_map_edit_queue.push(e);
1269 Inventory* Server::getInventory(const InventoryLocation &loc)
1272 case InventoryLocation::UNDEFINED:
1273 case InventoryLocation::CURRENT_PLAYER:
1275 case InventoryLocation::PLAYER:
1277 Player *player = m_env->getPlayer(loc.name.c_str());
1280 PlayerSAO *playersao = player->getPlayerSAO();
1283 return playersao->getInventory();
1286 case InventoryLocation::NODEMETA:
1288 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1291 return meta->getInventory();
1294 case InventoryLocation::DETACHED:
1296 if(m_detached_inventories.count(loc.name) == 0)
1298 return m_detached_inventories[loc.name];
1302 sanity_check(false); // abort
1307 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1310 case InventoryLocation::UNDEFINED:
1312 case InventoryLocation::PLAYER:
1317 Player *player = m_env->getPlayer(loc.name.c_str());
1320 PlayerSAO *playersao = player->getPlayerSAO();
1324 SendInventory(playersao);
1327 case InventoryLocation::NODEMETA:
1329 v3s16 blockpos = getNodeBlockPos(loc.p);
1331 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1333 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1335 setBlockNotSent(blockpos);
1338 case InventoryLocation::DETACHED:
1340 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1344 sanity_check(false); // abort
1349 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1351 std::vector<u16> clients = m_clients.getClientIDs();
1353 // Set the modified blocks unsent for all the clients
1354 for (std::vector<u16>::iterator i = clients.begin();
1355 i != clients.end(); ++i) {
1356 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1357 client->SetBlocksNotSent(block);
1362 void Server::peerAdded(con::Peer *peer)
1364 DSTACK(FUNCTION_NAME);
1365 verbosestream<<"Server::peerAdded(): peer->id="
1366 <<peer->id<<std::endl;
1369 c.type = con::PEER_ADDED;
1370 c.peer_id = peer->id;
1372 m_peer_change_queue.push(c);
1375 void Server::deletingPeer(con::Peer *peer, bool timeout)
1377 DSTACK(FUNCTION_NAME);
1378 verbosestream<<"Server::deletingPeer(): peer->id="
1379 <<peer->id<<", timeout="<<timeout<<std::endl;
1381 m_clients.event(peer->id, CSE_Disconnect);
1383 c.type = con::PEER_REMOVED;
1384 c.peer_id = peer->id;
1385 c.timeout = timeout;
1386 m_peer_change_queue.push(c);
1389 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1391 *retval = m_con.getPeerStat(peer_id,type);
1392 if (*retval == -1) return false;
1396 bool Server::getClientInfo(
1405 std::string* vers_string
1408 *state = m_clients.getClientState(peer_id);
1410 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1412 if (client == NULL) {
1417 *uptime = client->uptime();
1418 *ser_vers = client->serialization_version;
1419 *prot_vers = client->net_proto_version;
1421 *major = client->getMajor();
1422 *minor = client->getMinor();
1423 *patch = client->getPatch();
1424 *vers_string = client->getPatch();
1431 void Server::handlePeerChanges()
1433 while(m_peer_change_queue.size() > 0)
1435 con::PeerChange c = m_peer_change_queue.front();
1436 m_peer_change_queue.pop();
1438 verbosestream<<"Server: Handling peer change: "
1439 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1444 case con::PEER_ADDED:
1445 m_clients.CreateClient(c.peer_id);
1448 case con::PEER_REMOVED:
1449 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1453 FATAL_ERROR("Invalid peer change event received!");
1459 void Server::printToConsoleOnly(const std::string &text)
1462 m_admin_chat->outgoing_queue.push_back(
1463 new ChatEventChat("", utf8_to_wide(text)));
1465 std::cout << text << std::endl;
1469 void Server::Send(NetworkPacket* pkt)
1471 m_clients.send(pkt->getPeerId(),
1472 clientCommandFactoryTable[pkt->getCommand()].channel,
1474 clientCommandFactoryTable[pkt->getCommand()].reliable);
1477 void Server::SendMovement(u16 peer_id)
1479 DSTACK(FUNCTION_NAME);
1480 std::ostringstream os(std::ios_base::binary);
1482 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1484 pkt << g_settings->getFloat("movement_acceleration_default");
1485 pkt << g_settings->getFloat("movement_acceleration_air");
1486 pkt << g_settings->getFloat("movement_acceleration_fast");
1487 pkt << g_settings->getFloat("movement_speed_walk");
1488 pkt << g_settings->getFloat("movement_speed_crouch");
1489 pkt << g_settings->getFloat("movement_speed_fast");
1490 pkt << g_settings->getFloat("movement_speed_climb");
1491 pkt << g_settings->getFloat("movement_speed_jump");
1492 pkt << g_settings->getFloat("movement_liquid_fluidity");
1493 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1494 pkt << g_settings->getFloat("movement_liquid_sink");
1495 pkt << g_settings->getFloat("movement_gravity");
1500 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1502 if (!g_settings->getBool("enable_damage"))
1505 u16 peer_id = playersao->getPeerID();
1506 bool is_alive = playersao->getHP() > 0;
1509 SendPlayerHP(peer_id);
1514 void Server::SendHP(u16 peer_id, u8 hp)
1516 DSTACK(FUNCTION_NAME);
1518 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1523 void Server::SendBreath(u16 peer_id, u16 breath)
1525 DSTACK(FUNCTION_NAME);
1527 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1528 pkt << (u16) breath;
1532 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1533 const std::string &custom_reason, bool reconnect)
1535 assert(reason < SERVER_ACCESSDENIED_MAX);
1537 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1539 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1540 pkt << custom_reason;
1541 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1542 reason == SERVER_ACCESSDENIED_CRASH)
1543 pkt << custom_reason << (u8)reconnect;
1547 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1549 DSTACK(FUNCTION_NAME);
1551 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1556 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1557 v3f camera_point_target)
1559 DSTACK(FUNCTION_NAME);
1561 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1562 pkt << set_camera_point_target << camera_point_target;
1566 void Server::SendItemDef(u16 peer_id,
1567 IItemDefManager *itemdef, u16 protocol_version)
1569 DSTACK(FUNCTION_NAME);
1571 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1575 u32 length of the next item
1576 zlib-compressed serialized ItemDefManager
1578 std::ostringstream tmp_os(std::ios::binary);
1579 itemdef->serialize(tmp_os, protocol_version);
1580 std::ostringstream tmp_os2(std::ios::binary);
1581 compressZlib(tmp_os.str(), tmp_os2);
1582 pkt.putLongString(tmp_os2.str());
1585 verbosestream << "Server: Sending item definitions to id(" << peer_id
1586 << "): size=" << pkt.getSize() << std::endl;
1591 void Server::SendNodeDef(u16 peer_id,
1592 INodeDefManager *nodedef, u16 protocol_version)
1594 DSTACK(FUNCTION_NAME);
1596 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1600 u32 length of the next item
1601 zlib-compressed serialized NodeDefManager
1603 std::ostringstream tmp_os(std::ios::binary);
1604 nodedef->serialize(tmp_os, protocol_version);
1605 std::ostringstream tmp_os2(std::ios::binary);
1606 compressZlib(tmp_os.str(), tmp_os2);
1608 pkt.putLongString(tmp_os2.str());
1611 verbosestream << "Server: Sending node definitions to id(" << peer_id
1612 << "): size=" << pkt.getSize() << std::endl;
1618 Non-static send methods
1621 void Server::SendInventory(PlayerSAO* playerSAO)
1623 DSTACK(FUNCTION_NAME);
1625 UpdateCrafting(playerSAO->getPlayer());
1631 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1633 std::ostringstream os;
1634 playerSAO->getInventory()->serialize(os);
1636 std::string s = os.str();
1638 pkt.putRawString(s.c_str(), s.size());
1642 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1644 DSTACK(FUNCTION_NAME);
1646 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1649 if (peer_id != PEER_ID_INEXISTENT) {
1653 m_clients.sendToAll(0, &pkt, true);
1657 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1658 const std::string &formname)
1660 DSTACK(FUNCTION_NAME);
1662 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1664 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1670 // Spawns a particle on peer with peer_id
1671 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1672 float expirationtime, float size, bool collisiondetection,
1673 bool collision_removal,
1674 bool vertical, const std::string &texture)
1676 DSTACK(FUNCTION_NAME);
1678 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1680 pkt << pos << velocity << acceleration << expirationtime
1681 << size << collisiondetection;
1682 pkt.putLongString(texture);
1684 pkt << collision_removal;
1686 if (peer_id != PEER_ID_INEXISTENT) {
1690 m_clients.sendToAll(0, &pkt, true);
1694 // Adds a ParticleSpawner on peer with peer_id
1695 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1696 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1697 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1698 bool vertical, const std::string &texture, u32 id)
1700 DSTACK(FUNCTION_NAME);
1702 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1704 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1705 << minacc << maxacc << minexptime << maxexptime << minsize
1706 << maxsize << collisiondetection;
1708 pkt.putLongString(texture);
1710 pkt << id << vertical;
1711 pkt << collision_removal;
1713 if (peer_id != PEER_ID_INEXISTENT) {
1717 m_clients.sendToAll(0, &pkt, true);
1721 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1723 DSTACK(FUNCTION_NAME);
1725 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1727 // Ugly error in this packet
1730 if (peer_id != PEER_ID_INEXISTENT) {
1734 m_clients.sendToAll(0, &pkt, true);
1739 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1741 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1743 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1744 << form->text << form->number << form->item << form->dir
1745 << form->align << form->offset << form->world_pos << form->size;
1750 void Server::SendHUDRemove(u16 peer_id, u32 id)
1752 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1757 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1759 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1760 pkt << id << (u8) stat;
1764 case HUD_STAT_SCALE:
1765 case HUD_STAT_ALIGN:
1766 case HUD_STAT_OFFSET:
1767 pkt << *(v2f *) value;
1771 pkt << *(std::string *) value;
1773 case HUD_STAT_WORLD_POS:
1774 pkt << *(v3f *) value;
1777 pkt << *(v2s32 *) value;
1779 case HUD_STAT_NUMBER:
1783 pkt << *(u32 *) value;
1790 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1792 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1794 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1796 pkt << flags << mask;
1801 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1803 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1804 pkt << param << value;
1808 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1809 const std::string &type, const std::vector<std::string> ¶ms)
1811 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1812 pkt << bgcolor << type << (u16) params.size();
1814 for(size_t i=0; i<params.size(); i++)
1820 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1823 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1826 pkt << do_override << (u16) (ratio * 65535);
1831 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1833 DSTACK(FUNCTION_NAME);
1835 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1836 pkt << time << time_speed;
1838 if (peer_id == PEER_ID_INEXISTENT) {
1839 m_clients.sendToAll(0, &pkt, true);
1846 void Server::SendPlayerHP(u16 peer_id)
1848 DSTACK(FUNCTION_NAME);
1849 PlayerSAO *playersao = getPlayerSAO(peer_id);
1850 // In some rare case if the player is disconnected
1851 // while Lua call l_punch, for example, this can be NULL
1855 SendHP(peer_id, playersao->getHP());
1856 m_script->player_event(playersao,"health_changed");
1858 // Send to other clients
1859 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1860 ActiveObjectMessage aom(playersao->getId(), true, str);
1861 playersao->m_messages_out.push(aom);
1864 void Server::SendPlayerBreath(u16 peer_id)
1866 DSTACK(FUNCTION_NAME);
1867 PlayerSAO *playersao = getPlayerSAO(peer_id);
1870 m_script->player_event(playersao, "breath_changed");
1871 SendBreath(peer_id, playersao->getBreath());
1874 void Server::SendMovePlayer(u16 peer_id)
1876 DSTACK(FUNCTION_NAME);
1877 Player *player = m_env->getPlayer(peer_id);
1880 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1881 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1884 v3f pos = player->getPosition();
1885 f32 pitch = player->getPitch();
1886 f32 yaw = player->getYaw();
1887 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1888 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1889 << " pitch=" << pitch
1897 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1899 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1902 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1903 << animation_frames[3] << animation_speed;
1908 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1910 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1911 pkt << first << third;
1914 void Server::SendPlayerPrivileges(u16 peer_id)
1916 Player *player = m_env->getPlayer(peer_id);
1918 if(player->peer_id == PEER_ID_INEXISTENT)
1921 std::set<std::string> privs;
1922 m_script->getAuth(player->getName(), NULL, &privs);
1924 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1925 pkt << (u16) privs.size();
1927 for(std::set<std::string>::const_iterator i = privs.begin();
1928 i != privs.end(); ++i) {
1935 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1937 Player *player = m_env->getPlayer(peer_id);
1939 if(player->peer_id == PEER_ID_INEXISTENT)
1942 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1943 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1947 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1949 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1950 pkt.putRawString(datas.c_str(), datas.size());
1952 return pkt.getSize();
1955 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1957 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1958 datas.size(), peer_id);
1960 pkt.putRawString(datas.c_str(), datas.size());
1962 m_clients.send(pkt.getPeerId(),
1963 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1968 s32 Server::playSound(const SimpleSoundSpec &spec,
1969 const ServerSoundParams ¶ms)
1971 // Find out initial position of sound
1972 bool pos_exists = false;
1973 v3f pos = params.getPos(m_env, &pos_exists);
1974 // If position is not found while it should be, cancel sound
1975 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1978 // Filter destination clients
1979 std::vector<u16> dst_clients;
1980 if(params.to_player != "")
1982 Player *player = m_env->getPlayer(params.to_player.c_str());
1984 infostream<<"Server::playSound: Player \""<<params.to_player
1985 <<"\" not found"<<std::endl;
1988 if(player->peer_id == PEER_ID_INEXISTENT){
1989 infostream<<"Server::playSound: Player \""<<params.to_player
1990 <<"\" not connected"<<std::endl;
1993 dst_clients.push_back(player->peer_id);
1996 std::vector<u16> clients = m_clients.getClientIDs();
1998 for(std::vector<u16>::iterator
1999 i = clients.begin(); i != clients.end(); ++i) {
2000 Player *player = m_env->getPlayer(*i);
2005 if(player->getPosition().getDistanceFrom(pos) >
2006 params.max_hear_distance)
2009 dst_clients.push_back(*i);
2013 if(dst_clients.empty())
2017 s32 id = m_next_sound_id++;
2018 // The sound will exist as a reference in m_playing_sounds
2019 m_playing_sounds[id] = ServerPlayingSound();
2020 ServerPlayingSound &psound = m_playing_sounds[id];
2021 psound.params = params;
2023 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2024 pkt << id << spec.name << (float) (spec.gain * params.gain)
2025 << (u8) params.type << pos << params.object << params.loop;
2027 for(std::vector<u16>::iterator i = dst_clients.begin();
2028 i != dst_clients.end(); ++i) {
2029 psound.clients.insert(*i);
2030 m_clients.send(*i, 0, &pkt, true);
2034 void Server::stopSound(s32 handle)
2036 // Get sound reference
2037 std::map<s32, ServerPlayingSound>::iterator i =
2038 m_playing_sounds.find(handle);
2039 if(i == m_playing_sounds.end())
2041 ServerPlayingSound &psound = i->second;
2043 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2046 for(std::set<u16>::iterator i = psound.clients.begin();
2047 i != psound.clients.end(); ++i) {
2049 m_clients.send(*i, 0, &pkt, true);
2051 // Remove sound reference
2052 m_playing_sounds.erase(i);
2055 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2056 std::vector<u16> *far_players, float far_d_nodes)
2058 float maxd = far_d_nodes*BS;
2059 v3f p_f = intToFloat(p, BS);
2061 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2064 std::vector<u16> clients = m_clients.getClientIDs();
2065 for(std::vector<u16>::iterator i = clients.begin();
2066 i != clients.end(); ++i) {
2069 if(Player *player = m_env->getPlayer(*i)) {
2070 // If player is far away, only set modified blocks not sent
2071 v3f player_pos = player->getPosition();
2072 if(player_pos.getDistanceFrom(p_f) > maxd) {
2073 far_players->push_back(*i);
2080 m_clients.send(*i, 0, &pkt, true);
2084 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2085 std::vector<u16> *far_players, float far_d_nodes,
2086 bool remove_metadata)
2088 float maxd = far_d_nodes*BS;
2089 v3f p_f = intToFloat(p, BS);
2091 std::vector<u16> clients = m_clients.getClientIDs();
2092 for(std::vector<u16>::iterator i = clients.begin();
2093 i != clients.end(); ++i) {
2097 if(Player *player = m_env->getPlayer(*i)) {
2098 // If player is far away, only set modified blocks not sent
2099 v3f player_pos = player->getPosition();
2100 if(player_pos.getDistanceFrom(p_f) > maxd) {
2101 far_players->push_back(*i);
2107 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2109 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2111 pkt << p << n.param0 << n.param1 << n.param2
2112 << (u8) (remove_metadata ? 0 : 1);
2114 if (!remove_metadata) {
2115 if (client->net_proto_version <= 21) {
2116 // Old clients always clear metadata; fix it
2117 // by sending the full block again.
2118 client->SetBlockNotSent(getNodeBlockPos(p));
2125 if (pkt.getSize() > 0)
2126 m_clients.send(*i, 0, &pkt, true);
2130 void Server::setBlockNotSent(v3s16 p)
2132 std::vector<u16> clients = m_clients.getClientIDs();
2134 for(std::vector<u16>::iterator i = clients.begin();
2135 i != clients.end(); ++i) {
2136 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2137 client->SetBlockNotSent(p);
2142 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2144 DSTACK(FUNCTION_NAME);
2146 v3s16 p = block->getPos();
2149 Create a packet with the block in the right format
2152 std::ostringstream os(std::ios_base::binary);
2153 block->serialize(os, ver, false);
2154 block->serializeNetworkSpecific(os, net_proto_version);
2155 std::string s = os.str();
2157 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2160 pkt.putRawString(s.c_str(), s.size());
2164 void Server::SendBlocks(float dtime)
2166 DSTACK(FUNCTION_NAME);
2168 MutexAutoLock envlock(m_env_mutex);
2169 //TODO check if one big lock could be faster then multiple small ones
2171 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2173 std::vector<PrioritySortedBlockTransfer> queue;
2175 s32 total_sending = 0;
2178 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2180 std::vector<u16> clients = m_clients.getClientIDs();
2183 for(std::vector<u16>::iterator i = clients.begin();
2184 i != clients.end(); ++i) {
2185 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2190 total_sending += client->SendingCount();
2191 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2197 // Lowest priority number comes first.
2198 // Lowest is most important.
2199 std::sort(queue.begin(), queue.end());
2202 for(u32 i=0; i<queue.size(); i++)
2204 //TODO: Calculate limit dynamically
2205 if(total_sending >= g_settings->getS32
2206 ("max_simultaneous_block_sends_server_total"))
2209 PrioritySortedBlockTransfer q = queue[i];
2211 MapBlock *block = NULL;
2214 block = m_env->getMap().getBlockNoCreate(q.pos);
2216 catch(InvalidPositionException &e)
2221 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2226 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2228 client->SentBlock(q.pos);
2234 void Server::fillMediaCache()
2236 DSTACK(FUNCTION_NAME);
2238 infostream<<"Server: Calculating media file checksums"<<std::endl;
2240 // Collect all media file paths
2241 std::vector<std::string> paths;
2242 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2243 i != m_mods.end(); ++i) {
2244 const ModSpec &mod = *i;
2245 paths.push_back(mod.path + DIR_DELIM + "textures");
2246 paths.push_back(mod.path + DIR_DELIM + "sounds");
2247 paths.push_back(mod.path + DIR_DELIM + "media");
2248 paths.push_back(mod.path + DIR_DELIM + "models");
2250 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2252 // Collect media file information from paths into cache
2253 for(std::vector<std::string>::iterator i = paths.begin();
2254 i != paths.end(); ++i) {
2255 std::string mediapath = *i;
2256 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2257 for (u32 j = 0; j < dirlist.size(); j++) {
2258 if (dirlist[j].dir) // Ignode dirs
2260 std::string filename = dirlist[j].name;
2261 // If name contains illegal characters, ignore the file
2262 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2263 infostream<<"Server: ignoring illegal file name: \""
2264 << filename << "\"" << std::endl;
2267 // If name is not in a supported format, ignore it
2268 const char *supported_ext[] = {
2269 ".png", ".jpg", ".bmp", ".tga",
2270 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2272 ".x", ".b3d", ".md2", ".obj",
2275 if (removeStringEnd(filename, supported_ext) == ""){
2276 infostream << "Server: ignoring unsupported file extension: \""
2277 << filename << "\"" << std::endl;
2280 // Ok, attempt to load the file and add to cache
2281 std::string filepath = mediapath + DIR_DELIM + filename;
2283 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2285 errorstream << "Server::fillMediaCache(): Could not open \""
2286 << filename << "\" for reading" << std::endl;
2289 std::ostringstream tmp_os(std::ios_base::binary);
2293 fis.read(buf, 1024);
2294 std::streamsize len = fis.gcount();
2295 tmp_os.write(buf, len);
2304 errorstream<<"Server::fillMediaCache(): Failed to read \""
2305 << filename << "\"" << std::endl;
2308 if(tmp_os.str().length() == 0) {
2309 errorstream << "Server::fillMediaCache(): Empty file \""
2310 << filepath << "\"" << std::endl;
2315 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2317 unsigned char *digest = sha1.getDigest();
2318 std::string sha1_base64 = base64_encode(digest, 20);
2319 std::string sha1_hex = hex_encode((char*)digest, 20);
2323 m_media[filename] = MediaInfo(filepath, sha1_base64);
2324 verbosestream << "Server: " << sha1_hex << " is " << filename
2330 void Server::sendMediaAnnouncement(u16 peer_id)
2332 DSTACK(FUNCTION_NAME);
2334 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2338 std::ostringstream os(std::ios_base::binary);
2340 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2341 pkt << (u16) m_media.size();
2343 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2344 i != m_media.end(); ++i) {
2345 pkt << i->first << i->second.sha1_digest;
2348 pkt << g_settings->get("remote_media");
2352 struct SendableMedia
2358 SendableMedia(const std::string &name_="", const std::string &path_="",
2359 const std::string &data_=""):
2366 void Server::sendRequestedMedia(u16 peer_id,
2367 const std::vector<std::string> &tosend)
2369 DSTACK(FUNCTION_NAME);
2371 verbosestream<<"Server::sendRequestedMedia(): "
2372 <<"Sending files to client"<<std::endl;
2376 // Put 5kB in one bunch (this is not accurate)
2377 u32 bytes_per_bunch = 5000;
2379 std::vector< std::vector<SendableMedia> > file_bunches;
2380 file_bunches.push_back(std::vector<SendableMedia>());
2382 u32 file_size_bunch_total = 0;
2384 for(std::vector<std::string>::const_iterator i = tosend.begin();
2385 i != tosend.end(); ++i) {
2386 const std::string &name = *i;
2388 if(m_media.find(name) == m_media.end()) {
2389 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2390 <<"unknown file \""<<(name)<<"\""<<std::endl;
2394 //TODO get path + name
2395 std::string tpath = m_media[name].path;
2398 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2399 if(fis.good() == false){
2400 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2401 <<tpath<<"\" for reading"<<std::endl;
2404 std::ostringstream tmp_os(std::ios_base::binary);
2408 fis.read(buf, 1024);
2409 std::streamsize len = fis.gcount();
2410 tmp_os.write(buf, len);
2411 file_size_bunch_total += len;
2420 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2421 <<name<<"\""<<std::endl;
2424 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2425 <<tname<<"\""<<std::endl;*/
2427 file_bunches[file_bunches.size()-1].push_back(
2428 SendableMedia(name, tpath, tmp_os.str()));
2430 // Start next bunch if got enough data
2431 if(file_size_bunch_total >= bytes_per_bunch) {
2432 file_bunches.push_back(std::vector<SendableMedia>());
2433 file_size_bunch_total = 0;
2438 /* Create and send packets */
2440 u16 num_bunches = file_bunches.size();
2441 for(u16 i = 0; i < num_bunches; i++) {
2444 u16 total number of texture bunches
2445 u16 index of this bunch
2446 u32 number of files in this bunch
2455 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2456 pkt << num_bunches << i << (u32) file_bunches[i].size();
2458 for(std::vector<SendableMedia>::iterator
2459 j = file_bunches[i].begin();
2460 j != file_bunches[i].end(); ++j) {
2462 pkt.putLongString(j->data);
2465 verbosestream << "Server::sendRequestedMedia(): bunch "
2466 << i << "/" << num_bunches
2467 << " files=" << file_bunches[i].size()
2468 << " size=" << pkt.getSize() << std::endl;
2473 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2475 if(m_detached_inventories.count(name) == 0) {
2476 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2479 Inventory *inv = m_detached_inventories[name];
2480 std::ostringstream os(std::ios_base::binary);
2482 os << serializeString(name);
2486 std::string s = os.str();
2488 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2489 pkt.putRawString(s.c_str(), s.size());
2491 if (peer_id != PEER_ID_INEXISTENT) {
2495 m_clients.sendToAll(0, &pkt, true);
2499 void Server::sendDetachedInventories(u16 peer_id)
2501 DSTACK(FUNCTION_NAME);
2503 for(std::map<std::string, Inventory*>::iterator
2504 i = m_detached_inventories.begin();
2505 i != m_detached_inventories.end(); ++i) {
2506 const std::string &name = i->first;
2507 //Inventory *inv = i->second;
2508 sendDetachedInventory(name, peer_id);
2516 void Server::DiePlayer(u16 peer_id)
2518 DSTACK(FUNCTION_NAME);
2519 PlayerSAO *playersao = getPlayerSAO(peer_id);
2520 // In some rare cases this can be NULL -- if the player is disconnected
2521 // when a Lua function modifies l_punch, for example
2525 infostream << "Server::DiePlayer(): Player "
2526 << playersao->getPlayer()->getName()
2527 << " dies" << std::endl;
2529 playersao->setHP(0);
2531 // Trigger scripted stuff
2532 m_script->on_dieplayer(playersao);
2534 SendPlayerHP(peer_id);
2535 SendDeathscreen(peer_id, false, v3f(0,0,0));
2538 void Server::RespawnPlayer(u16 peer_id)
2540 DSTACK(FUNCTION_NAME);
2542 PlayerSAO *playersao = getPlayerSAO(peer_id);
2545 infostream << "Server::RespawnPlayer(): Player "
2546 << playersao->getPlayer()->getName()
2547 << " respawns" << std::endl;
2549 playersao->setHP(PLAYER_MAX_HP);
2550 playersao->setBreath(PLAYER_MAX_BREATH);
2552 SendPlayerHP(peer_id);
2553 SendPlayerBreath(peer_id);
2555 bool repositioned = m_script->on_respawnplayer(playersao);
2557 v3f pos = findSpawnPos();
2558 // setPos will send the new position to client
2559 playersao->setPos(pos);
2564 void Server::DenySudoAccess(u16 peer_id)
2566 DSTACK(FUNCTION_NAME);
2568 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2573 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2574 const std::string &str_reason, bool reconnect)
2576 if (proto_ver >= 25) {
2577 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2579 std::wstring wreason = utf8_to_wide(
2580 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2581 accessDeniedStrings[(u8)reason]);
2582 SendAccessDenied_Legacy(peer_id, wreason);
2585 m_clients.event(peer_id, CSE_SetDenied);
2586 m_con.DisconnectPeer(peer_id);
2590 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2592 DSTACK(FUNCTION_NAME);
2594 SendAccessDenied(peer_id, reason, custom_reason);
2595 m_clients.event(peer_id, CSE_SetDenied);
2596 m_con.DisconnectPeer(peer_id);
2599 // 13/03/15: remove this function when protocol version 25 will become
2600 // the minimum version for MT users, maybe in 1 year
2601 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2603 DSTACK(FUNCTION_NAME);
2605 SendAccessDenied_Legacy(peer_id, reason);
2606 m_clients.event(peer_id, CSE_SetDenied);
2607 m_con.DisconnectPeer(peer_id);
2610 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2612 DSTACK(FUNCTION_NAME);
2615 RemoteClient* client = getClient(peer_id, CS_Invalid);
2617 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2619 // Right now, the auth mechs don't change between login and sudo mode.
2620 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2621 client->allowed_sudo_mechs = sudo_auth_mechs;
2623 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2624 << g_settings->getFloat("dedicated_server_step")
2628 m_clients.event(peer_id, CSE_AuthAccept);
2630 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2632 // We only support SRP right now
2633 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2635 resp_pkt << sudo_auth_mechs;
2637 m_clients.event(peer_id, CSE_SudoSuccess);
2641 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2643 DSTACK(FUNCTION_NAME);
2644 std::wstring message;
2647 Clear references to playing sounds
2649 for(std::map<s32, ServerPlayingSound>::iterator
2650 i = m_playing_sounds.begin();
2651 i != m_playing_sounds.end();)
2653 ServerPlayingSound &psound = i->second;
2654 psound.clients.erase(peer_id);
2655 if(psound.clients.empty())
2656 m_playing_sounds.erase(i++);
2661 Player *player = m_env->getPlayer(peer_id);
2663 // Collect information about leaving in chat
2665 if(player != NULL && reason != CDR_DENY)
2667 std::wstring name = narrow_to_wide(player->getName());
2670 message += L" left the game.";
2671 if(reason == CDR_TIMEOUT)
2672 message += L" (timed out)";
2676 /* Run scripts and remove from environment */
2680 PlayerSAO *playersao = player->getPlayerSAO();
2683 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2685 playersao->disconnected();
2693 if(player != NULL && reason != CDR_DENY) {
2694 std::ostringstream os(std::ios_base::binary);
2695 std::vector<u16> clients = m_clients.getClientIDs();
2697 for(std::vector<u16>::iterator i = clients.begin();
2698 i != clients.end(); ++i) {
2700 Player *player = m_env->getPlayer(*i);
2704 // Get name of player
2705 os << player->getName() << " ";
2708 std::string name = player->getName();
2709 actionstream << name << " "
2710 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2711 << " List of players: " << os.str() << std::endl;
2713 m_admin_chat->outgoing_queue.push_back(
2714 new ChatEventNick(CET_NICK_REMOVE, name));
2718 MutexAutoLock env_lock(m_env_mutex);
2719 m_clients.DeleteClient(peer_id);
2723 // Send leave chat message to all remaining clients
2724 if(message.length() != 0)
2725 SendChatMessage(PEER_ID_INEXISTENT,message);
2728 void Server::UpdateCrafting(Player* player)
2730 DSTACK(FUNCTION_NAME);
2732 // Get a preview for crafting
2734 InventoryLocation loc;
2735 loc.setPlayer(player->getName());
2736 std::vector<ItemStack> output_replacements;
2737 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2738 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2740 // Put the new preview in
2741 InventoryList *plist = player->inventory.getList("craftpreview");
2742 sanity_check(plist);
2743 sanity_check(plist->getSize() >= 1);
2744 plist->changeItem(0, preview);
2747 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2749 if (evt->type == CET_NICK_ADD) {
2750 // The terminal informed us of its nick choice
2751 m_admin_nick = ((ChatEventNick *)evt)->nick;
2752 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2753 errorstream << "You haven't set up an account." << std::endl
2754 << "Please log in using the client as '"
2755 << m_admin_nick << "' with a secure password." << std::endl
2756 << "Until then, you can't execute admin tasks via the console," << std::endl
2757 << "and everybody can claim the user account instead of you," << std::endl
2758 << "giving them full control over this server." << std::endl;
2761 assert(evt->type == CET_CHAT);
2762 handleAdminChat((ChatEventChat *)evt);
2766 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2767 const std::wstring &wmessage, bool check_shout_priv,
2768 u16 peer_id_to_avoid_sending)
2770 // If something goes wrong, this player is to blame
2771 RollbackScopeActor rollback_scope(m_rollback,
2772 std::string("player:") + name);
2776 // Whether to send line to the player that sent the message, or to all players
2777 bool broadcast_line = true;
2780 bool ate = m_script->on_chat_message(name,
2781 wide_to_utf8(wmessage));
2782 // If script ate the message, don't proceed
2786 // Commands are implemented in Lua, so only catch invalid
2787 // commands that were not "eaten" and send an error back
2788 if (wmessage[0] == L'/') {
2789 std::wstring wcmd = wmessage.substr(1);
2790 broadcast_line = false;
2791 if (wcmd.length() == 0)
2792 line += L"-!- Empty command";
2794 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2796 if (check_shout_priv && !checkPriv(name, "shout")) {
2797 line += L"-!- You don't have permission to shout.";
2798 broadcast_line = false;
2808 Tell calling method to send the message to sender
2810 if (!broadcast_line) {
2814 Send the message to others
2816 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2818 std::vector<u16> clients = m_clients.getClientIDs();
2820 for (u16 i = 0; i < clients.size(); i++) {
2821 u16 cid = clients[i];
2822 if (cid != peer_id_to_avoid_sending)
2823 SendChatMessage(cid, line);
2829 void Server::handleAdminChat(const ChatEventChat *evt)
2831 std::string name = evt->nick;
2832 std::wstring wname = utf8_to_wide(name);
2833 std::wstring wmessage = evt->evt_msg;
2835 std::wstring answer = handleChat(name, wname, wmessage);
2837 // If asked to send answer to sender
2838 if (!answer.empty()) {
2839 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2843 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2845 RemoteClient *client = getClientNoEx(peer_id,state_min);
2847 throw ClientNotFoundException("Client not found");
2851 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2853 return m_clients.getClientNoEx(peer_id, state_min);
2856 std::string Server::getPlayerName(u16 peer_id)
2858 Player *player = m_env->getPlayer(peer_id);
2860 return "[id="+itos(peer_id)+"]";
2861 return player->getName();
2864 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2866 Player *player = m_env->getPlayer(peer_id);
2869 return player->getPlayerSAO();
2872 std::wstring Server::getStatusString()
2874 std::wostringstream os(std::ios_base::binary);
2877 os<<L"version="<<narrow_to_wide(g_version_string);
2879 os<<L", uptime="<<m_uptime.get();
2881 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2882 // Information about clients
2885 std::vector<u16> clients = m_clients.getClientIDs();
2886 for(std::vector<u16>::iterator i = clients.begin();
2887 i != clients.end(); ++i) {
2889 Player *player = m_env->getPlayer(*i);
2890 // Get name of player
2891 std::wstring name = L"unknown";
2893 name = narrow_to_wide(player->getName());
2894 // Add name to information string
2902 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2903 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2904 if(g_settings->get("motd") != "")
2905 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2909 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2911 std::set<std::string> privs;
2912 m_script->getAuth(name, NULL, &privs);
2916 bool Server::checkPriv(const std::string &name, const std::string &priv)
2918 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2919 return (privs.count(priv) != 0);
2922 void Server::reportPrivsModified(const std::string &name)
2925 std::vector<u16> clients = m_clients.getClientIDs();
2926 for(std::vector<u16>::iterator i = clients.begin();
2927 i != clients.end(); ++i) {
2928 Player *player = m_env->getPlayer(*i);
2929 reportPrivsModified(player->getName());
2932 Player *player = m_env->getPlayer(name.c_str());
2935 SendPlayerPrivileges(player->peer_id);
2936 PlayerSAO *sao = player->getPlayerSAO();
2939 sao->updatePrivileges(
2940 getPlayerEffectivePrivs(name),
2945 void Server::reportInventoryFormspecModified(const std::string &name)
2947 Player *player = m_env->getPlayer(name.c_str());
2950 SendPlayerInventoryFormspec(player->peer_id);
2953 void Server::setIpBanned(const std::string &ip, const std::string &name)
2955 m_banmanager->add(ip, name);
2958 void Server::unsetIpBanned(const std::string &ip_or_name)
2960 m_banmanager->remove(ip_or_name);
2963 std::string Server::getBanDescription(const std::string &ip_or_name)
2965 return m_banmanager->getBanDescription(ip_or_name);
2968 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2970 // m_env will be NULL if the server is initializing
2974 if (m_admin_nick == name && !m_admin_nick.empty()) {
2975 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2978 Player *player = m_env->getPlayer(name);
2983 if (player->peer_id == PEER_ID_INEXISTENT)
2986 SendChatMessage(player->peer_id, msg);
2989 bool Server::showFormspec(const char *playername, const std::string &formspec,
2990 const std::string &formname)
2992 // m_env will be NULL if the server is initializing
2996 Player *player = m_env->getPlayer(playername);
3000 SendShowFormspecMessage(player->peer_id, formspec, formname);
3004 u32 Server::hudAdd(Player *player, HudElement *form)
3009 u32 id = player->addHud(form);
3011 SendHUDAdd(player->peer_id, id, form);
3016 bool Server::hudRemove(Player *player, u32 id) {
3020 HudElement* todel = player->removeHud(id);
3027 SendHUDRemove(player->peer_id, id);
3031 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3036 SendHUDChange(player->peer_id, id, stat, data);
3040 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3045 SendHUDSetFlags(player->peer_id, flags, mask);
3046 player->hud_flags &= ~mask;
3047 player->hud_flags |= flags;
3049 PlayerSAO* playersao = player->getPlayerSAO();
3051 if (playersao == NULL)
3054 m_script->player_event(playersao, "hud_changed");
3058 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3062 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3065 player->setHotbarItemcount(hotbar_itemcount);
3066 std::ostringstream os(std::ios::binary);
3067 writeS32(os, hotbar_itemcount);
3068 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3072 s32 Server::hudGetHotbarItemcount(Player *player)
3076 return player->getHotbarItemcount();
3079 void Server::hudSetHotbarImage(Player *player, std::string name)
3084 player->setHotbarImage(name);
3085 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3088 std::string Server::hudGetHotbarImage(Player *player)
3092 return player->getHotbarImage();
3095 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3100 player->setHotbarSelectedImage(name);
3101 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3104 std::string Server::hudGetHotbarSelectedImage(Player *player)
3109 return player->getHotbarSelectedImage();
3112 bool Server::setLocalPlayerAnimations(Player *player,
3113 v2s32 animation_frames[4], f32 frame_speed)
3118 player->setLocalAnimations(animation_frames, frame_speed);
3119 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3123 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3128 player->eye_offset_first = first;
3129 player->eye_offset_third = third;
3130 SendEyeOffset(player->peer_id, first, third);
3134 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3135 const std::string &type, const std::vector<std::string> ¶ms)
3140 player->setSky(bgcolor, type, params);
3141 SendSetSky(player->peer_id, bgcolor, type, params);
3145 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3151 player->overrideDayNightRatio(do_override, ratio);
3152 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3156 void Server::notifyPlayers(const std::wstring &msg)
3158 SendChatMessage(PEER_ID_INEXISTENT,msg);
3161 void Server::spawnParticle(const std::string &playername, v3f pos,
3162 v3f velocity, v3f acceleration,
3163 float expirationtime, float size, bool
3164 collisiondetection, bool collision_removal,
3165 bool vertical, const std::string &texture)
3167 // m_env will be NULL if the server is initializing
3171 u16 peer_id = PEER_ID_INEXISTENT;
3172 if (playername != "") {
3173 Player* player = m_env->getPlayer(playername.c_str());
3176 peer_id = player->peer_id;
3179 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3180 expirationtime, size, collisiondetection,
3181 collision_removal, vertical, texture);
3184 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3185 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3186 float minexptime, float maxexptime, float minsize, float maxsize,
3187 bool collisiondetection, bool collision_removal,
3188 bool vertical, const std::string &texture,
3189 const std::string &playername)
3191 // m_env will be NULL if the server is initializing
3195 u16 peer_id = PEER_ID_INEXISTENT;
3196 if (playername != "") {
3197 Player* player = m_env->getPlayer(playername.c_str());
3200 peer_id = player->peer_id;
3203 u32 id = m_env->addParticleSpawner(spawntime);
3204 SendAddParticleSpawner(peer_id, amount, spawntime,
3205 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3206 minexptime, maxexptime, minsize, maxsize,
3207 collisiondetection, collision_removal, vertical, texture, id);
3212 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3214 // m_env will be NULL if the server is initializing
3216 throw ServerError("Can't delete particle spawners during initialisation!");
3218 u16 peer_id = PEER_ID_INEXISTENT;
3219 if (playername != "") {
3220 Player* player = m_env->getPlayer(playername.c_str());
3223 peer_id = player->peer_id;
3226 m_env->deleteParticleSpawner(id);
3227 SendDeleteParticleSpawner(peer_id, id);
3230 void Server::deleteParticleSpawnerAll(u32 id)
3232 m_env->deleteParticleSpawner(id);
3233 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3236 Inventory* Server::createDetachedInventory(const std::string &name)
3238 if(m_detached_inventories.count(name) > 0){
3239 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3240 delete m_detached_inventories[name];
3242 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3244 Inventory *inv = new Inventory(m_itemdef);
3246 m_detached_inventories[name] = inv;
3247 //TODO find a better way to do this
3248 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3252 // actions: time-reversed list
3253 // Return value: success/failure
3254 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3255 std::list<std::string> *log)
3257 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3258 ServerMap *map = (ServerMap*)(&m_env->getMap());
3260 // Fail if no actions to handle
3261 if(actions.empty()){
3262 log->push_back("Nothing to do.");
3269 for(std::list<RollbackAction>::const_iterator
3270 i = actions.begin();
3271 i != actions.end(); ++i)
3273 const RollbackAction &action = *i;
3275 bool success = action.applyRevert(map, this, this);
3278 std::ostringstream os;
3279 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3280 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3282 log->push_back(os.str());
3284 std::ostringstream os;
3285 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3286 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3288 log->push_back(os.str());
3292 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3293 <<" failed"<<std::endl;
3295 // Call it done if less than half failed
3296 return num_failed <= num_tried/2;
3299 // IGameDef interface
3301 IItemDefManager *Server::getItemDefManager()
3306 INodeDefManager *Server::getNodeDefManager()
3311 ICraftDefManager *Server::getCraftDefManager()
3315 ITextureSource *Server::getTextureSource()
3319 IShaderSource *Server::getShaderSource()
3323 scene::ISceneManager *Server::getSceneManager()
3328 u16 Server::allocateUnknownNodeId(const std::string &name)
3330 return m_nodedef->allocateDummy(name);
3333 ISoundManager *Server::getSoundManager()
3335 return &dummySoundManager;
3338 MtEventManager *Server::getEventManager()
3343 IWritableItemDefManager *Server::getWritableItemDefManager()
3348 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3353 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3358 const ModSpec *Server::getModSpec(const std::string &modname) const
3360 std::vector<ModSpec>::const_iterator it;
3361 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3362 const ModSpec &mod = *it;
3363 if (mod.name == modname)
3369 void Server::getModNames(std::vector<std::string> &modlist)
3371 std::vector<ModSpec>::iterator it;
3372 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3373 modlist.push_back(it->name);
3376 std::string Server::getBuiltinLuaPath()
3378 return porting::path_share + DIR_DELIM + "builtin";
3381 v3f Server::findSpawnPos()
3383 ServerMap &map = m_env->getServerMap();
3385 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3386 return nodeposf * BS;
3389 bool is_good = false;
3391 // Try to find a good place a few times
3392 for(s32 i = 0; i < 4000 && !is_good; i++) {
3394 // We're going to try to throw the player to this position
3395 v2s16 nodepos2d = v2s16(
3396 -range + (myrand() % (range * 2)),
3397 -range + (myrand() % (range * 2)));
3399 // Get spawn level at point
3400 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3401 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3402 // the mapgen to signify an unsuitable spawn position
3403 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3406 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3409 for (s32 i = 0; i < 10; i++) {
3410 v3s16 blockpos = getNodeBlockPos(nodepos);
3411 map.emergeBlock(blockpos, true);
3412 content_t c = map.getNodeNoEx(nodepos).getContent();
3413 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3415 if (air_count >= 2) {
3416 nodeposf = intToFloat(nodepos, BS);
3417 // Don't spawn the player outside map boundaries
3418 if (objectpos_over_limit(nodeposf))
3431 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3433 bool newplayer = false;
3436 Try to get an existing player
3438 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3440 // If player is already connected, cancel
3441 if(player != NULL && player->peer_id != 0)
3443 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3448 If player with the wanted peer_id already exists, cancel.
3450 if(m_env->getPlayer(peer_id) != NULL)
3452 infostream<<"emergePlayer(): Player with wrong name but same"
3453 " peer_id already exists"<<std::endl;
3457 // Load player if it isn't already loaded
3459 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3462 // Create player if it doesn't exist
3465 player = new RemotePlayer(this, name);
3466 // Set player position
3467 infostream<<"Server: Finding spawn place for player \""
3468 <<name<<"\""<<std::endl;
3469 v3f pos = findSpawnPos();
3470 player->setPosition(pos);
3472 // Make sure the player is saved
3473 player->setModified(true);
3475 // Add player to environment
3476 m_env->addPlayer(player);
3478 // If the player exists, ensure that they respawn inside legal bounds
3479 // This fixes an assert crash when the player can't be added
3480 // to the environment
3481 if (objectpos_over_limit(player->getPosition())) {
3482 actionstream << "Respawn position for player \""
3483 << name << "\" outside limits, resetting" << std::endl;
3484 v3f pos = findSpawnPos();
3485 player->setPosition(pos);
3489 // Create a new player active object
3490 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3491 getPlayerEffectivePrivs(player->getName()),
3494 player->protocol_version = proto_version;
3496 /* Clean up old HUD elements from previous sessions */
3499 /* Add object to environment */
3500 m_env->addActiveObject(playersao);
3504 m_script->on_newplayer(playersao);
3510 void dedicated_server_loop(Server &server, bool &kill)
3512 DSTACK(FUNCTION_NAME);
3514 verbosestream<<"dedicated_server_loop()"<<std::endl;
3516 IntervalLimiter m_profiler_interval;
3518 static const float steplen = g_settings->getFloat("dedicated_server_step");
3519 static const float profiler_print_interval =
3520 g_settings->getFloat("profiler_print_interval");
3523 // This is kind of a hack but can be done like this
3524 // because server.step() is very light
3526 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3527 sleep_ms((int)(steplen*1000.0));
3529 server.step(steplen);
3531 if(server.getShutdownRequested() || kill)
3533 infostream<<"Dedicated server quitting"<<std::endl;
3535 if(g_settings->getBool("server_announce"))
3536 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3544 if (profiler_print_interval != 0) {
3545 if(m_profiler_interval.step(steplen, profiler_print_interval))
3547 infostream<<"Profiler:"<<std::endl;
3548 g_profiler->print(infostream);
3549 g_profiler->clear();