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");
361 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
366 infostream<<"Server destructing"<<std::endl;
368 // Send shutdown message
369 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
372 MutexAutoLock envlock(m_env_mutex);
374 // Execute script shutdown hooks
375 m_script->on_shutdown();
377 infostream << "Server: Saving players" << std::endl;
378 m_env->saveLoadedPlayers();
380 infostream << "Server: Kicking players" << std::endl;
381 std::string kick_msg;
382 bool reconnect = false;
383 if (getShutdownRequested()) {
384 reconnect = m_shutdown_ask_reconnect;
385 kick_msg = m_shutdown_msg;
387 if (kick_msg == "") {
388 kick_msg = g_settings->get("kick_msg_shutdown");
390 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
391 kick_msg, reconnect);
393 infostream << "Server: Saving environment metadata" << std::endl;
401 // stop all emerge threads before deleting players that may have
402 // requested blocks to be emerged
403 m_emerge->stopThreads();
405 // Delete things in the reverse order of creation
415 // Deinitialize scripting
416 infostream<<"Server: Deinitializing scripting"<<std::endl;
419 // Delete detached inventories
420 for (std::map<std::string, Inventory*>::iterator
421 i = m_detached_inventories.begin();
422 i != m_detached_inventories.end(); ++i) {
427 void Server::start(Address bind_addr)
429 DSTACK(FUNCTION_NAME);
431 m_bind_addr = bind_addr;
433 infostream<<"Starting server on "
434 << bind_addr.serializeString() <<"..."<<std::endl;
436 // Stop thread if already running
439 // Initialize connection
440 m_con.SetTimeoutMs(30);
441 m_con.Serve(bind_addr);
446 // ASCII art for the win!
448 <<" .__ __ __ "<<std::endl
449 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
450 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
451 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
452 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
453 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
454 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
455 actionstream<<"Server for gameid=\""<<m_gamespec.id
456 <<"\" listening on "<<bind_addr.serializeString()<<":"
457 <<bind_addr.getPort() << "."<<std::endl;
462 DSTACK(FUNCTION_NAME);
464 infostream<<"Server: Stopping and waiting threads"<<std::endl;
466 // Stop threads (set run=false first so both start stopping)
468 //m_emergethread.setRun(false);
470 //m_emergethread.stop();
472 infostream<<"Server: Threads stopped"<<std::endl;
475 void Server::step(float dtime)
477 DSTACK(FUNCTION_NAME);
482 MutexAutoLock lock(m_step_dtime_mutex);
483 m_step_dtime += dtime;
485 // Throw if fatal error occurred in thread
486 std::string async_err = m_async_fatal_error.get();
487 if (!async_err.empty()) {
488 if (!m_simple_singleplayer_mode) {
489 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
490 g_settings->get("kick_msg_crash"),
491 g_settings->getBool("ask_reconnect_on_crash"));
493 throw ServerError(async_err);
497 void Server::AsyncRunStep(bool initial_step)
499 DSTACK(FUNCTION_NAME);
501 g_profiler->add("Server::AsyncRunStep (num)", 1);
505 MutexAutoLock lock1(m_step_dtime_mutex);
506 dtime = m_step_dtime;
510 // Send blocks to clients
514 if((dtime < 0.001) && (initial_step == false))
517 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
519 //infostream<<"Server steps "<<dtime<<std::endl;
520 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
523 MutexAutoLock lock1(m_step_dtime_mutex);
524 m_step_dtime -= dtime;
531 m_uptime.set(m_uptime.get() + dtime);
537 Update time of day and overall game time
539 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
542 Send to clients at constant intervals
545 m_time_of_day_send_timer -= dtime;
546 if(m_time_of_day_send_timer < 0.0) {
547 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
548 u16 time = m_env->getTimeOfDay();
549 float time_speed = g_settings->getFloat("time_speed");
550 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
554 MutexAutoLock lock(m_env_mutex);
555 // Figure out and report maximum lag to environment
556 float max_lag = m_env->getMaxLagEstimate();
557 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
559 if(dtime > 0.1 && dtime > max_lag * 2.0)
560 infostream<<"Server: Maximum lag peaked to "<<dtime
564 m_env->reportMaxLagEstimate(max_lag);
566 ScopeProfiler sp(g_profiler, "SEnv step");
567 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
571 static const float map_timer_and_unload_dtime = 2.92;
572 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
574 MutexAutoLock lock(m_env_mutex);
575 // Run Map's timers and unload unused data
576 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
577 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
578 g_settings->getFloat("server_unload_unused_data_timeout"),
583 Listen to the admin chat, if available
586 if (!m_admin_chat->command_queue.empty()) {
587 MutexAutoLock lock(m_env_mutex);
588 while (!m_admin_chat->command_queue.empty()) {
589 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
590 handleChatInterfaceEvent(evt);
594 m_admin_chat->outgoing_queue.push_back(
595 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
602 /* Transform liquids */
603 m_liquid_transform_timer += dtime;
604 if(m_liquid_transform_timer >= m_liquid_transform_every)
606 m_liquid_transform_timer -= m_liquid_transform_every;
608 MutexAutoLock lock(m_env_mutex);
610 ScopeProfiler sp(g_profiler, "Server: liquid transform");
612 std::map<v3s16, MapBlock*> modified_blocks;
613 m_env->getMap().transformLiquids(modified_blocks);
618 core::map<v3s16, MapBlock*> lighting_modified_blocks;
619 ServerMap &map = ((ServerMap&)m_env->getMap());
620 map.updateLighting(modified_blocks, lighting_modified_blocks);
622 // Add blocks modified by lighting to modified_blocks
623 for(core::map<v3s16, MapBlock*>::Iterator
624 i = lighting_modified_blocks.getIterator();
625 i.atEnd() == false; i++)
627 MapBlock *block = i.getNode()->getValue();
628 modified_blocks.insert(block->getPos(), block);
632 Set the modified blocks unsent for all the clients
634 if(!modified_blocks.empty())
636 SetBlocksNotSent(modified_blocks);
639 m_clients.step(dtime);
641 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
643 // send masterserver announce
645 float &counter = m_masterserver_timer;
646 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
647 g_settings->getBool("server_announce"))
649 ServerList::sendAnnounce(counter ? "update" : "start",
650 m_bind_addr.getPort(),
651 m_clients.getPlayerNames(),
653 m_env->getGameTime(),
656 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
665 Check added and deleted active objects
668 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
669 MutexAutoLock envlock(m_env_mutex);
672 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
673 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
675 // Radius inside which objects are active
676 static const s16 radius =
677 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
679 // Radius inside which players are active
680 static const bool is_transfer_limited =
681 g_settings->exists("unlimited_player_transfer_distance") &&
682 !g_settings->getBool("unlimited_player_transfer_distance");
683 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
684 s16 player_radius = player_transfer_dist;
685 if (player_radius == 0 && is_transfer_limited)
686 player_radius = radius;
688 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
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);
698 if (player == NULL) {
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 UNORDERED_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 UNORDERED_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 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
820 // Route data to every client
821 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
822 i != clients.end(); ++i) {
823 RemoteClient *client = i->second;
824 std::string reliable_data;
825 std::string unreliable_data;
826 // Go through all objects in message buffer
827 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
828 j = buffered_messages.begin();
829 j != buffered_messages.end(); ++j) {
830 // If object is not known by client, skip it
832 if (client->m_known_objects.find(id) == client->m_known_objects.end())
835 // Get message list of object
836 std::vector<ActiveObjectMessage>* list = j->second;
837 // Go through every message
838 for (std::vector<ActiveObjectMessage>::iterator
839 k = list->begin(); k != list->end(); ++k) {
840 // Compose the full new data with header
841 ActiveObjectMessage aom = *k;
842 std::string new_data;
845 writeU16((u8*)&buf[0], aom.id);
846 new_data.append(buf, 2);
848 new_data += serializeString(aom.datastring);
849 // Add data to buffer
851 reliable_data += new_data;
853 unreliable_data += new_data;
857 reliable_data and unreliable_data are now ready.
860 if(reliable_data.size() > 0) {
861 SendActiveObjectMessages(client->peer_id, reliable_data);
864 if(unreliable_data.size() > 0) {
865 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
870 // Clear buffered_messages
871 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
872 i = buffered_messages.begin();
873 i != buffered_messages.end(); ++i) {
879 Send queued-for-sending map edit events.
882 // We will be accessing the environment
883 MutexAutoLock lock(m_env_mutex);
885 // Don't send too many at a time
888 // Single change sending is disabled if queue size is not small
889 bool disable_single_change_sending = false;
890 if(m_unsent_map_edit_queue.size() >= 4)
891 disable_single_change_sending = true;
893 int event_count = m_unsent_map_edit_queue.size();
895 // We'll log the amount of each
898 while(m_unsent_map_edit_queue.size() != 0)
900 MapEditEvent* event = m_unsent_map_edit_queue.front();
901 m_unsent_map_edit_queue.pop();
903 // Players far away from the change are stored here.
904 // Instead of sending the changes, MapBlocks are set not sent
906 std::vector<u16> far_players;
908 switch (event->type) {
911 prof.add("MEET_ADDNODE", 1);
912 sendAddNode(event->p, event->n, event->already_known_by_peer,
913 &far_players, disable_single_change_sending ? 5 : 30,
914 event->type == MEET_ADDNODE);
916 case MEET_REMOVENODE:
917 prof.add("MEET_REMOVENODE", 1);
918 sendRemoveNode(event->p, event->already_known_by_peer,
919 &far_players, disable_single_change_sending ? 5 : 30);
921 case MEET_BLOCK_NODE_METADATA_CHANGED:
922 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
923 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
924 setBlockNotSent(event->p);
927 infostream << "Server: MEET_OTHER" << std::endl;
928 prof.add("MEET_OTHER", 1);
929 for(std::set<v3s16>::iterator
930 i = event->modified_blocks.begin();
931 i != event->modified_blocks.end(); ++i) {
936 prof.add("unknown", 1);
937 warningstream << "Server: Unknown MapEditEvent "
938 << ((u32)event->type) << std::endl;
943 Set blocks not sent to far players
945 if(!far_players.empty()) {
946 // Convert list format to that wanted by SetBlocksNotSent
947 std::map<v3s16, MapBlock*> modified_blocks2;
948 for(std::set<v3s16>::iterator
949 i = event->modified_blocks.begin();
950 i != event->modified_blocks.end(); ++i) {
951 modified_blocks2[*i] =
952 m_env->getMap().getBlockNoCreateNoEx(*i);
955 // Set blocks not sent
956 for(std::vector<u16>::iterator
957 i = far_players.begin();
958 i != far_players.end(); ++i) {
959 if(RemoteClient *client = getClient(*i))
960 client->SetBlocksNotSent(modified_blocks2);
966 /*// Don't send too many at a time
968 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
972 if(event_count >= 5){
973 infostream<<"Server: MapEditEvents:"<<std::endl;
974 prof.print(infostream);
975 } else if(event_count != 0){
976 verbosestream<<"Server: MapEditEvents:"<<std::endl;
977 prof.print(verbosestream);
983 Trigger emergethread (it somehow gets to a non-triggered but
984 bysy state sometimes)
987 float &counter = m_emergethread_trigger_timer;
989 if (counter >= 2.0) {
992 m_emerge->startThreads();
996 // Save map, players and auth stuff
998 float &counter = m_savemap_timer;
1000 static const float save_interval =
1001 g_settings->getFloat("server_map_save_interval");
1002 if (counter >= save_interval) {
1004 MutexAutoLock lock(m_env_mutex);
1006 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1009 if (m_banmanager->isModified()) {
1010 m_banmanager->save();
1013 // Save changed parts of map
1014 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1017 m_env->saveLoadedPlayers();
1019 // Save environment metadata
1025 void Server::Receive()
1027 DSTACK(FUNCTION_NAME);
1028 SharedBuffer<u8> data;
1032 m_con.Receive(&pkt);
1033 peer_id = pkt.getPeerId();
1036 catch(con::InvalidIncomingDataException &e) {
1037 infostream<<"Server::Receive(): "
1038 "InvalidIncomingDataException: what()="
1039 <<e.what()<<std::endl;
1041 catch(SerializationError &e) {
1042 infostream<<"Server::Receive(): "
1043 "SerializationError: what()="
1044 <<e.what()<<std::endl;
1046 catch(ClientStateError &e) {
1047 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1048 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1049 L"Try reconnecting or updating your client");
1051 catch(con::PeerNotFoundException &e) {
1056 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1058 std::string playername = "";
1059 PlayerSAO *playersao = NULL;
1062 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1063 if (client != NULL) {
1064 playername = client->getName();
1065 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1067 } catch (std::exception &e) {
1073 RemotePlayer *player =
1074 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1076 // If failed, cancel
1077 if ((playersao == NULL) || (player == NULL)) {
1078 if (player && player->peer_id != 0) {
1079 actionstream << "Server: Failed to emerge player \"" << playername
1080 << "\" (player allocated to an another client)" << std::endl;
1081 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1082 L"name. If your client closed unexpectedly, try again in "
1085 errorstream << "Server: " << playername << ": Failed to emerge player"
1087 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1093 Send complete position information
1095 SendMovePlayer(peer_id);
1098 SendPlayerPrivileges(peer_id);
1100 // Send inventory formspec
1101 SendPlayerInventoryFormspec(peer_id);
1104 SendInventory(playersao);
1107 SendPlayerHPOrDie(playersao);
1110 SendPlayerBreath(peer_id);
1112 // Show death screen if necessary
1113 if(player->isDead())
1114 SendDeathscreen(peer_id, false, v3f(0,0,0));
1116 // Note things in chat if not in simple singleplayer mode
1117 if(!m_simple_singleplayer_mode) {
1118 // Send information about server to player in chat
1119 SendChatMessage(peer_id, getStatusString());
1121 Address addr = getPeerAddress(player->peer_id);
1122 std::string ip_str = addr.serializeString();
1123 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1128 std::vector<std::string> names = m_clients.getPlayerNames();
1130 actionstream<<player->getName() <<" joins game. List of players: ";
1132 for (std::vector<std::string>::iterator i = names.begin();
1133 i != names.end(); ++i) {
1134 actionstream << *i << " ";
1137 actionstream << player->getName() <<std::endl;
1142 inline void Server::handleCommand(NetworkPacket* pkt)
1144 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1145 (this->*opHandle.handler)(pkt);
1148 void Server::ProcessData(NetworkPacket *pkt)
1150 DSTACK(FUNCTION_NAME);
1151 // Environment is locked first.
1152 MutexAutoLock envlock(m_env_mutex);
1154 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1155 u32 peer_id = pkt->getPeerId();
1158 Address address = getPeerAddress(peer_id);
1159 std::string addr_s = address.serializeString();
1161 if(m_banmanager->isIpBanned(addr_s)) {
1162 std::string ban_name = m_banmanager->getBanName(addr_s);
1163 infostream << "Server: A banned client tried to connect from "
1164 << addr_s << "; banned name was "
1165 << ban_name << std::endl;
1166 // This actually doesn't seem to transfer to the client
1167 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1168 + utf8_to_wide(ban_name));
1172 catch(con::PeerNotFoundException &e) {
1174 * no peer for this packet found
1175 * most common reason is peer timeout, e.g. peer didn't
1176 * respond for some time, your server was overloaded or
1179 infostream << "Server::ProcessData(): Canceling: peer "
1180 << peer_id << " not found" << std::endl;
1185 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1187 // Command must be handled into ToServerCommandHandler
1188 if (command >= TOSERVER_NUM_MSG_TYPES) {
1189 infostream << "Server: Ignoring unknown command "
1190 << command << std::endl;
1194 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1199 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1201 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1202 errorstream << "Server::ProcessData(): Cancelling: Peer"
1203 " serialization format invalid or not initialized."
1204 " Skipping incoming command=" << command << std::endl;
1208 /* Handle commands related to client startup */
1209 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1214 if (m_clients.getClientState(peer_id) < CS_Active) {
1215 if (command == TOSERVER_PLAYERPOS) return;
1217 errorstream << "Got packet command: " << command << " for peer id "
1218 << peer_id << " but client isn't active yet. Dropping packet "
1224 } catch (SendFailedException &e) {
1225 errorstream << "Server::ProcessData(): SendFailedException: "
1226 << "what=" << e.what()
1228 } catch (PacketError &e) {
1229 actionstream << "Server::ProcessData(): PacketError: "
1230 << "what=" << e.what()
1235 void Server::setTimeOfDay(u32 time)
1237 m_env->setTimeOfDay(time);
1238 m_time_of_day_send_timer = 0;
1241 void Server::onMapEditEvent(MapEditEvent *event)
1243 if(m_ignore_map_edit_events)
1245 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1247 MapEditEvent *e = event->clone();
1248 m_unsent_map_edit_queue.push(e);
1251 Inventory* Server::getInventory(const InventoryLocation &loc)
1254 case InventoryLocation::UNDEFINED:
1255 case InventoryLocation::CURRENT_PLAYER:
1257 case InventoryLocation::PLAYER:
1259 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1262 PlayerSAO *playersao = player->getPlayerSAO();
1265 return playersao->getInventory();
1268 case InventoryLocation::NODEMETA:
1270 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1273 return meta->getInventory();
1276 case InventoryLocation::DETACHED:
1278 if(m_detached_inventories.count(loc.name) == 0)
1280 return m_detached_inventories[loc.name];
1284 sanity_check(false); // abort
1289 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1292 case InventoryLocation::UNDEFINED:
1294 case InventoryLocation::PLAYER:
1299 RemotePlayer *player =
1300 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1305 PlayerSAO *playersao = player->getPlayerSAO();
1309 SendInventory(playersao);
1312 case InventoryLocation::NODEMETA:
1314 v3s16 blockpos = getNodeBlockPos(loc.p);
1316 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1318 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1320 setBlockNotSent(blockpos);
1323 case InventoryLocation::DETACHED:
1325 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1329 sanity_check(false); // abort
1334 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1336 std::vector<u16> clients = m_clients.getClientIDs();
1338 // Set the modified blocks unsent for all the clients
1339 for (std::vector<u16>::iterator i = clients.begin();
1340 i != clients.end(); ++i) {
1341 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1342 client->SetBlocksNotSent(block);
1347 void Server::peerAdded(con::Peer *peer)
1349 DSTACK(FUNCTION_NAME);
1350 verbosestream<<"Server::peerAdded(): peer->id="
1351 <<peer->id<<std::endl;
1354 c.type = con::PEER_ADDED;
1355 c.peer_id = peer->id;
1357 m_peer_change_queue.push(c);
1360 void Server::deletingPeer(con::Peer *peer, bool timeout)
1362 DSTACK(FUNCTION_NAME);
1363 verbosestream<<"Server::deletingPeer(): peer->id="
1364 <<peer->id<<", timeout="<<timeout<<std::endl;
1366 m_clients.event(peer->id, CSE_Disconnect);
1368 c.type = con::PEER_REMOVED;
1369 c.peer_id = peer->id;
1370 c.timeout = timeout;
1371 m_peer_change_queue.push(c);
1374 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1376 *retval = m_con.getPeerStat(peer_id,type);
1377 if (*retval == -1) return false;
1381 bool Server::getClientInfo(
1390 std::string* vers_string
1393 *state = m_clients.getClientState(peer_id);
1395 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1397 if (client == NULL) {
1402 *uptime = client->uptime();
1403 *ser_vers = client->serialization_version;
1404 *prot_vers = client->net_proto_version;
1406 *major = client->getMajor();
1407 *minor = client->getMinor();
1408 *patch = client->getPatch();
1409 *vers_string = client->getPatch();
1416 void Server::handlePeerChanges()
1418 while(m_peer_change_queue.size() > 0)
1420 con::PeerChange c = m_peer_change_queue.front();
1421 m_peer_change_queue.pop();
1423 verbosestream<<"Server: Handling peer change: "
1424 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1429 case con::PEER_ADDED:
1430 m_clients.CreateClient(c.peer_id);
1433 case con::PEER_REMOVED:
1434 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1438 FATAL_ERROR("Invalid peer change event received!");
1444 void Server::printToConsoleOnly(const std::string &text)
1447 m_admin_chat->outgoing_queue.push_back(
1448 new ChatEventChat("", utf8_to_wide(text)));
1450 std::cout << text << std::endl;
1454 void Server::Send(NetworkPacket* pkt)
1456 m_clients.send(pkt->getPeerId(),
1457 clientCommandFactoryTable[pkt->getCommand()].channel,
1459 clientCommandFactoryTable[pkt->getCommand()].reliable);
1462 void Server::SendMovement(u16 peer_id)
1464 DSTACK(FUNCTION_NAME);
1465 std::ostringstream os(std::ios_base::binary);
1467 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1469 pkt << g_settings->getFloat("movement_acceleration_default");
1470 pkt << g_settings->getFloat("movement_acceleration_air");
1471 pkt << g_settings->getFloat("movement_acceleration_fast");
1472 pkt << g_settings->getFloat("movement_speed_walk");
1473 pkt << g_settings->getFloat("movement_speed_crouch");
1474 pkt << g_settings->getFloat("movement_speed_fast");
1475 pkt << g_settings->getFloat("movement_speed_climb");
1476 pkt << g_settings->getFloat("movement_speed_jump");
1477 pkt << g_settings->getFloat("movement_liquid_fluidity");
1478 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1479 pkt << g_settings->getFloat("movement_liquid_sink");
1480 pkt << g_settings->getFloat("movement_gravity");
1485 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1487 if (!g_settings->getBool("enable_damage"))
1490 u16 peer_id = playersao->getPeerID();
1491 bool is_alive = playersao->getHP() > 0;
1494 SendPlayerHP(peer_id);
1499 void Server::SendHP(u16 peer_id, u8 hp)
1501 DSTACK(FUNCTION_NAME);
1503 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1508 void Server::SendBreath(u16 peer_id, u16 breath)
1510 DSTACK(FUNCTION_NAME);
1512 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1513 pkt << (u16) breath;
1517 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1518 const std::string &custom_reason, bool reconnect)
1520 assert(reason < SERVER_ACCESSDENIED_MAX);
1522 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1524 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1525 pkt << custom_reason;
1526 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1527 reason == SERVER_ACCESSDENIED_CRASH)
1528 pkt << custom_reason << (u8)reconnect;
1532 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1534 DSTACK(FUNCTION_NAME);
1536 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1541 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1542 v3f camera_point_target)
1544 DSTACK(FUNCTION_NAME);
1546 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1547 pkt << set_camera_point_target << camera_point_target;
1551 void Server::SendItemDef(u16 peer_id,
1552 IItemDefManager *itemdef, u16 protocol_version)
1554 DSTACK(FUNCTION_NAME);
1556 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1560 u32 length of the next item
1561 zlib-compressed serialized ItemDefManager
1563 std::ostringstream tmp_os(std::ios::binary);
1564 itemdef->serialize(tmp_os, protocol_version);
1565 std::ostringstream tmp_os2(std::ios::binary);
1566 compressZlib(tmp_os.str(), tmp_os2);
1567 pkt.putLongString(tmp_os2.str());
1570 verbosestream << "Server: Sending item definitions to id(" << peer_id
1571 << "): size=" << pkt.getSize() << std::endl;
1576 void Server::SendNodeDef(u16 peer_id,
1577 INodeDefManager *nodedef, u16 protocol_version)
1579 DSTACK(FUNCTION_NAME);
1581 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1585 u32 length of the next item
1586 zlib-compressed serialized NodeDefManager
1588 std::ostringstream tmp_os(std::ios::binary);
1589 nodedef->serialize(tmp_os, protocol_version);
1590 std::ostringstream tmp_os2(std::ios::binary);
1591 compressZlib(tmp_os.str(), tmp_os2);
1593 pkt.putLongString(tmp_os2.str());
1596 verbosestream << "Server: Sending node definitions to id(" << peer_id
1597 << "): size=" << pkt.getSize() << std::endl;
1603 Non-static send methods
1606 void Server::SendInventory(PlayerSAO* playerSAO)
1608 DSTACK(FUNCTION_NAME);
1610 UpdateCrafting(playerSAO->getPlayer());
1616 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1618 std::ostringstream os;
1619 playerSAO->getInventory()->serialize(os);
1621 std::string s = os.str();
1623 pkt.putRawString(s.c_str(), s.size());
1627 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1629 DSTACK(FUNCTION_NAME);
1631 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1634 if (peer_id != PEER_ID_INEXISTENT) {
1638 m_clients.sendToAll(0, &pkt, true);
1642 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1643 const std::string &formname)
1645 DSTACK(FUNCTION_NAME);
1647 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1649 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1655 // Spawns a particle on peer with peer_id
1656 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1657 float expirationtime, float size, bool collisiondetection,
1658 bool collision_removal,
1659 bool vertical, const std::string &texture)
1661 DSTACK(FUNCTION_NAME);
1663 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1665 pkt << pos << velocity << acceleration << expirationtime
1666 << size << collisiondetection;
1667 pkt.putLongString(texture);
1669 pkt << collision_removal;
1671 if (peer_id != PEER_ID_INEXISTENT) {
1675 m_clients.sendToAll(0, &pkt, true);
1679 // Adds a ParticleSpawner on peer with peer_id
1680 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1681 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1682 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1683 bool vertical, const std::string &texture, u32 id)
1685 DSTACK(FUNCTION_NAME);
1687 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1689 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1690 << minacc << maxacc << minexptime << maxexptime << minsize
1691 << maxsize << collisiondetection;
1693 pkt.putLongString(texture);
1695 pkt << id << vertical;
1696 pkt << collision_removal;
1698 if (peer_id != PEER_ID_INEXISTENT) {
1702 m_clients.sendToAll(0, &pkt, true);
1706 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1708 DSTACK(FUNCTION_NAME);
1710 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1712 // Ugly error in this packet
1715 if (peer_id != PEER_ID_INEXISTENT) {
1719 m_clients.sendToAll(0, &pkt, true);
1724 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1726 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1728 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1729 << form->text << form->number << form->item << form->dir
1730 << form->align << form->offset << form->world_pos << form->size;
1735 void Server::SendHUDRemove(u16 peer_id, u32 id)
1737 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1742 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1744 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1745 pkt << id << (u8) stat;
1749 case HUD_STAT_SCALE:
1750 case HUD_STAT_ALIGN:
1751 case HUD_STAT_OFFSET:
1752 pkt << *(v2f *) value;
1756 pkt << *(std::string *) value;
1758 case HUD_STAT_WORLD_POS:
1759 pkt << *(v3f *) value;
1762 pkt << *(v2s32 *) value;
1764 case HUD_STAT_NUMBER:
1768 pkt << *(u32 *) value;
1775 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1777 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1779 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1781 pkt << flags << mask;
1786 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1788 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1789 pkt << param << value;
1793 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1794 const std::string &type, const std::vector<std::string> ¶ms)
1796 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1797 pkt << bgcolor << type << (u16) params.size();
1799 for(size_t i=0; i<params.size(); i++)
1805 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1808 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1811 pkt << do_override << (u16) (ratio * 65535);
1816 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1818 DSTACK(FUNCTION_NAME);
1820 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1821 pkt << time << time_speed;
1823 if (peer_id == PEER_ID_INEXISTENT) {
1824 m_clients.sendToAll(0, &pkt, true);
1831 void Server::SendPlayerHP(u16 peer_id)
1833 DSTACK(FUNCTION_NAME);
1834 PlayerSAO *playersao = getPlayerSAO(peer_id);
1835 // In some rare case if the player is disconnected
1836 // while Lua call l_punch, for example, this can be NULL
1840 SendHP(peer_id, playersao->getHP());
1841 m_script->player_event(playersao,"health_changed");
1843 // Send to other clients
1844 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1845 ActiveObjectMessage aom(playersao->getId(), true, str);
1846 playersao->m_messages_out.push(aom);
1849 void Server::SendPlayerBreath(u16 peer_id)
1851 DSTACK(FUNCTION_NAME);
1852 PlayerSAO *playersao = getPlayerSAO(peer_id);
1855 m_script->player_event(playersao, "breath_changed");
1856 SendBreath(peer_id, playersao->getBreath());
1859 void Server::SendMovePlayer(u16 peer_id)
1861 DSTACK(FUNCTION_NAME);
1862 Player *player = m_env->getPlayer(peer_id);
1865 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1866 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1869 v3f pos = player->getPosition();
1870 f32 pitch = player->getPitch();
1871 f32 yaw = player->getYaw();
1872 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1873 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1874 << " pitch=" << pitch
1882 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1884 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1887 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1888 << animation_frames[3] << animation_speed;
1893 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1895 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1896 pkt << first << third;
1899 void Server::SendPlayerPrivileges(u16 peer_id)
1901 Player *player = m_env->getPlayer(peer_id);
1903 if(player->peer_id == PEER_ID_INEXISTENT)
1906 std::set<std::string> privs;
1907 m_script->getAuth(player->getName(), NULL, &privs);
1909 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1910 pkt << (u16) privs.size();
1912 for(std::set<std::string>::const_iterator i = privs.begin();
1913 i != privs.end(); ++i) {
1920 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1922 Player *player = m_env->getPlayer(peer_id);
1924 if(player->peer_id == PEER_ID_INEXISTENT)
1927 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1928 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1932 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1934 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1935 pkt.putRawString(datas.c_str(), datas.size());
1937 return pkt.getSize();
1940 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1942 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1943 datas.size(), peer_id);
1945 pkt.putRawString(datas.c_str(), datas.size());
1947 m_clients.send(pkt.getPeerId(),
1948 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1953 s32 Server::playSound(const SimpleSoundSpec &spec,
1954 const ServerSoundParams ¶ms)
1956 // Find out initial position of sound
1957 bool pos_exists = false;
1958 v3f pos = params.getPos(m_env, &pos_exists);
1959 // If position is not found while it should be, cancel sound
1960 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1963 // Filter destination clients
1964 std::vector<u16> dst_clients;
1965 if(params.to_player != "")
1967 Player *player = m_env->getPlayer(params.to_player.c_str());
1969 infostream<<"Server::playSound: Player \""<<params.to_player
1970 <<"\" not found"<<std::endl;
1973 if(player->peer_id == PEER_ID_INEXISTENT){
1974 infostream<<"Server::playSound: Player \""<<params.to_player
1975 <<"\" not connected"<<std::endl;
1978 dst_clients.push_back(player->peer_id);
1981 std::vector<u16> clients = m_clients.getClientIDs();
1983 for(std::vector<u16>::iterator
1984 i = clients.begin(); i != clients.end(); ++i) {
1985 Player *player = m_env->getPlayer(*i);
1990 if(player->getPosition().getDistanceFrom(pos) >
1991 params.max_hear_distance)
1994 dst_clients.push_back(*i);
1998 if(dst_clients.empty())
2002 s32 id = m_next_sound_id++;
2003 // The sound will exist as a reference in m_playing_sounds
2004 m_playing_sounds[id] = ServerPlayingSound();
2005 ServerPlayingSound &psound = m_playing_sounds[id];
2006 psound.params = params;
2008 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2009 pkt << id << spec.name << (float) (spec.gain * params.gain)
2010 << (u8) params.type << pos << params.object << params.loop;
2012 for(std::vector<u16>::iterator i = dst_clients.begin();
2013 i != dst_clients.end(); ++i) {
2014 psound.clients.insert(*i);
2015 m_clients.send(*i, 0, &pkt, true);
2019 void Server::stopSound(s32 handle)
2021 // Get sound reference
2022 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2023 if (i == m_playing_sounds.end())
2025 ServerPlayingSound &psound = i->second;
2027 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2030 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2031 i != psound.clients.end(); ++i) {
2033 m_clients.send(*i, 0, &pkt, true);
2035 // Remove sound reference
2036 m_playing_sounds.erase(i);
2039 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2040 std::vector<u16> *far_players, float far_d_nodes)
2042 float maxd = far_d_nodes*BS;
2043 v3f p_f = intToFloat(p, BS);
2045 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2048 std::vector<u16> clients = m_clients.getClientIDs();
2049 for(std::vector<u16>::iterator i = clients.begin();
2050 i != clients.end(); ++i) {
2053 if(Player *player = m_env->getPlayer(*i)) {
2054 // If player is far away, only set modified blocks not sent
2055 v3f player_pos = player->getPosition();
2056 if(player_pos.getDistanceFrom(p_f) > maxd) {
2057 far_players->push_back(*i);
2064 m_clients.send(*i, 0, &pkt, true);
2068 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2069 std::vector<u16> *far_players, float far_d_nodes,
2070 bool remove_metadata)
2072 float maxd = far_d_nodes*BS;
2073 v3f p_f = intToFloat(p, BS);
2075 std::vector<u16> clients = m_clients.getClientIDs();
2076 for(std::vector<u16>::iterator i = clients.begin();
2077 i != clients.end(); ++i) {
2081 if(Player *player = m_env->getPlayer(*i)) {
2082 // If player is far away, only set modified blocks not sent
2083 v3f player_pos = player->getPosition();
2084 if(player_pos.getDistanceFrom(p_f) > maxd) {
2085 far_players->push_back(*i);
2091 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2093 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2095 pkt << p << n.param0 << n.param1 << n.param2
2096 << (u8) (remove_metadata ? 0 : 1);
2098 if (!remove_metadata) {
2099 if (client->net_proto_version <= 21) {
2100 // Old clients always clear metadata; fix it
2101 // by sending the full block again.
2102 client->SetBlockNotSent(getNodeBlockPos(p));
2109 if (pkt.getSize() > 0)
2110 m_clients.send(*i, 0, &pkt, true);
2114 void Server::setBlockNotSent(v3s16 p)
2116 std::vector<u16> clients = m_clients.getClientIDs();
2118 for(std::vector<u16>::iterator i = clients.begin();
2119 i != clients.end(); ++i) {
2120 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2121 client->SetBlockNotSent(p);
2126 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2128 DSTACK(FUNCTION_NAME);
2130 v3s16 p = block->getPos();
2133 Create a packet with the block in the right format
2136 std::ostringstream os(std::ios_base::binary);
2137 block->serialize(os, ver, false);
2138 block->serializeNetworkSpecific(os, net_proto_version);
2139 std::string s = os.str();
2141 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2144 pkt.putRawString(s.c_str(), s.size());
2148 void Server::SendBlocks(float dtime)
2150 DSTACK(FUNCTION_NAME);
2152 MutexAutoLock envlock(m_env_mutex);
2153 //TODO check if one big lock could be faster then multiple small ones
2155 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2157 std::vector<PrioritySortedBlockTransfer> queue;
2159 s32 total_sending = 0;
2162 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2164 std::vector<u16> clients = m_clients.getClientIDs();
2167 for(std::vector<u16>::iterator i = clients.begin();
2168 i != clients.end(); ++i) {
2169 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2174 total_sending += client->SendingCount();
2175 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2181 // Lowest priority number comes first.
2182 // Lowest is most important.
2183 std::sort(queue.begin(), queue.end());
2186 for(u32 i=0; i<queue.size(); i++)
2188 //TODO: Calculate limit dynamically
2189 if(total_sending >= g_settings->getS32
2190 ("max_simultaneous_block_sends_server_total"))
2193 PrioritySortedBlockTransfer q = queue[i];
2195 MapBlock *block = NULL;
2198 block = m_env->getMap().getBlockNoCreate(q.pos);
2200 catch(InvalidPositionException &e)
2205 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2210 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2212 client->SentBlock(q.pos);
2218 void Server::fillMediaCache()
2220 DSTACK(FUNCTION_NAME);
2222 infostream<<"Server: Calculating media file checksums"<<std::endl;
2224 // Collect all media file paths
2225 std::vector<std::string> paths;
2226 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2227 i != m_mods.end(); ++i) {
2228 const ModSpec &mod = *i;
2229 paths.push_back(mod.path + DIR_DELIM + "textures");
2230 paths.push_back(mod.path + DIR_DELIM + "sounds");
2231 paths.push_back(mod.path + DIR_DELIM + "media");
2232 paths.push_back(mod.path + DIR_DELIM + "models");
2234 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2236 // Collect media file information from paths into cache
2237 for(std::vector<std::string>::iterator i = paths.begin();
2238 i != paths.end(); ++i) {
2239 std::string mediapath = *i;
2240 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2241 for (u32 j = 0; j < dirlist.size(); j++) {
2242 if (dirlist[j].dir) // Ignode dirs
2244 std::string filename = dirlist[j].name;
2245 // If name contains illegal characters, ignore the file
2246 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2247 infostream<<"Server: ignoring illegal file name: \""
2248 << filename << "\"" << std::endl;
2251 // If name is not in a supported format, ignore it
2252 const char *supported_ext[] = {
2253 ".png", ".jpg", ".bmp", ".tga",
2254 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2256 ".x", ".b3d", ".md2", ".obj",
2259 if (removeStringEnd(filename, supported_ext) == ""){
2260 infostream << "Server: ignoring unsupported file extension: \""
2261 << filename << "\"" << std::endl;
2264 // Ok, attempt to load the file and add to cache
2265 std::string filepath = mediapath + DIR_DELIM + filename;
2267 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2269 errorstream << "Server::fillMediaCache(): Could not open \""
2270 << filename << "\" for reading" << std::endl;
2273 std::ostringstream tmp_os(std::ios_base::binary);
2277 fis.read(buf, 1024);
2278 std::streamsize len = fis.gcount();
2279 tmp_os.write(buf, len);
2288 errorstream<<"Server::fillMediaCache(): Failed to read \""
2289 << filename << "\"" << std::endl;
2292 if(tmp_os.str().length() == 0) {
2293 errorstream << "Server::fillMediaCache(): Empty file \""
2294 << filepath << "\"" << std::endl;
2299 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2301 unsigned char *digest = sha1.getDigest();
2302 std::string sha1_base64 = base64_encode(digest, 20);
2303 std::string sha1_hex = hex_encode((char*)digest, 20);
2307 m_media[filename] = MediaInfo(filepath, sha1_base64);
2308 verbosestream << "Server: " << sha1_hex << " is " << filename
2314 void Server::sendMediaAnnouncement(u16 peer_id)
2316 DSTACK(FUNCTION_NAME);
2318 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2322 std::ostringstream os(std::ios_base::binary);
2324 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2325 pkt << (u16) m_media.size();
2327 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2328 i != m_media.end(); ++i) {
2329 pkt << i->first << i->second.sha1_digest;
2332 pkt << g_settings->get("remote_media");
2336 struct SendableMedia
2342 SendableMedia(const std::string &name_="", const std::string &path_="",
2343 const std::string &data_=""):
2350 void Server::sendRequestedMedia(u16 peer_id,
2351 const std::vector<std::string> &tosend)
2353 DSTACK(FUNCTION_NAME);
2355 verbosestream<<"Server::sendRequestedMedia(): "
2356 <<"Sending files to client"<<std::endl;
2360 // Put 5kB in one bunch (this is not accurate)
2361 u32 bytes_per_bunch = 5000;
2363 std::vector< std::vector<SendableMedia> > file_bunches;
2364 file_bunches.push_back(std::vector<SendableMedia>());
2366 u32 file_size_bunch_total = 0;
2368 for(std::vector<std::string>::const_iterator i = tosend.begin();
2369 i != tosend.end(); ++i) {
2370 const std::string &name = *i;
2372 if (m_media.find(name) == m_media.end()) {
2373 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2374 <<"unknown file \""<<(name)<<"\""<<std::endl;
2378 //TODO get path + name
2379 std::string tpath = m_media[name].path;
2382 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2383 if(fis.good() == false){
2384 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2385 <<tpath<<"\" for reading"<<std::endl;
2388 std::ostringstream tmp_os(std::ios_base::binary);
2392 fis.read(buf, 1024);
2393 std::streamsize len = fis.gcount();
2394 tmp_os.write(buf, len);
2395 file_size_bunch_total += len;
2404 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2405 <<name<<"\""<<std::endl;
2408 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2409 <<tname<<"\""<<std::endl;*/
2411 file_bunches[file_bunches.size()-1].push_back(
2412 SendableMedia(name, tpath, tmp_os.str()));
2414 // Start next bunch if got enough data
2415 if(file_size_bunch_total >= bytes_per_bunch) {
2416 file_bunches.push_back(std::vector<SendableMedia>());
2417 file_size_bunch_total = 0;
2422 /* Create and send packets */
2424 u16 num_bunches = file_bunches.size();
2425 for(u16 i = 0; i < num_bunches; i++) {
2428 u16 total number of texture bunches
2429 u16 index of this bunch
2430 u32 number of files in this bunch
2439 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2440 pkt << num_bunches << i << (u32) file_bunches[i].size();
2442 for(std::vector<SendableMedia>::iterator
2443 j = file_bunches[i].begin();
2444 j != file_bunches[i].end(); ++j) {
2446 pkt.putLongString(j->data);
2449 verbosestream << "Server::sendRequestedMedia(): bunch "
2450 << i << "/" << num_bunches
2451 << " files=" << file_bunches[i].size()
2452 << " size=" << pkt.getSize() << std::endl;
2457 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2459 if(m_detached_inventories.count(name) == 0) {
2460 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2463 Inventory *inv = m_detached_inventories[name];
2464 std::ostringstream os(std::ios_base::binary);
2466 os << serializeString(name);
2470 std::string s = os.str();
2472 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2473 pkt.putRawString(s.c_str(), s.size());
2475 if (peer_id != PEER_ID_INEXISTENT) {
2479 m_clients.sendToAll(0, &pkt, true);
2483 void Server::sendDetachedInventories(u16 peer_id)
2485 DSTACK(FUNCTION_NAME);
2487 for(std::map<std::string, Inventory*>::iterator
2488 i = m_detached_inventories.begin();
2489 i != m_detached_inventories.end(); ++i) {
2490 const std::string &name = i->first;
2491 //Inventory *inv = i->second;
2492 sendDetachedInventory(name, peer_id);
2500 void Server::DiePlayer(u16 peer_id)
2502 DSTACK(FUNCTION_NAME);
2503 PlayerSAO *playersao = getPlayerSAO(peer_id);
2504 // In some rare cases this can be NULL -- if the player is disconnected
2505 // when a Lua function modifies l_punch, for example
2509 infostream << "Server::DiePlayer(): Player "
2510 << playersao->getPlayer()->getName()
2511 << " dies" << std::endl;
2513 playersao->setHP(0);
2515 // Trigger scripted stuff
2516 m_script->on_dieplayer(playersao);
2518 SendPlayerHP(peer_id);
2519 SendDeathscreen(peer_id, false, v3f(0,0,0));
2522 void Server::RespawnPlayer(u16 peer_id)
2524 DSTACK(FUNCTION_NAME);
2526 PlayerSAO *playersao = getPlayerSAO(peer_id);
2529 infostream << "Server::RespawnPlayer(): Player "
2530 << playersao->getPlayer()->getName()
2531 << " respawns" << std::endl;
2533 playersao->setHP(PLAYER_MAX_HP);
2534 playersao->setBreath(PLAYER_MAX_BREATH);
2536 SendPlayerHP(peer_id);
2537 SendPlayerBreath(peer_id);
2539 bool repositioned = m_script->on_respawnplayer(playersao);
2541 v3f pos = findSpawnPos();
2542 // setPos will send the new position to client
2543 playersao->setPos(pos);
2548 void Server::DenySudoAccess(u16 peer_id)
2550 DSTACK(FUNCTION_NAME);
2552 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2557 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2558 const std::string &str_reason, bool reconnect)
2560 if (proto_ver >= 25) {
2561 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2563 std::wstring wreason = utf8_to_wide(
2564 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2565 accessDeniedStrings[(u8)reason]);
2566 SendAccessDenied_Legacy(peer_id, wreason);
2569 m_clients.event(peer_id, CSE_SetDenied);
2570 m_con.DisconnectPeer(peer_id);
2574 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2576 DSTACK(FUNCTION_NAME);
2578 SendAccessDenied(peer_id, reason, custom_reason);
2579 m_clients.event(peer_id, CSE_SetDenied);
2580 m_con.DisconnectPeer(peer_id);
2583 // 13/03/15: remove this function when protocol version 25 will become
2584 // the minimum version for MT users, maybe in 1 year
2585 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2587 DSTACK(FUNCTION_NAME);
2589 SendAccessDenied_Legacy(peer_id, reason);
2590 m_clients.event(peer_id, CSE_SetDenied);
2591 m_con.DisconnectPeer(peer_id);
2594 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2596 DSTACK(FUNCTION_NAME);
2599 RemoteClient* client = getClient(peer_id, CS_Invalid);
2601 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2603 // Right now, the auth mechs don't change between login and sudo mode.
2604 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2605 client->allowed_sudo_mechs = sudo_auth_mechs;
2607 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2608 << g_settings->getFloat("dedicated_server_step")
2612 m_clients.event(peer_id, CSE_AuthAccept);
2614 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2616 // We only support SRP right now
2617 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2619 resp_pkt << sudo_auth_mechs;
2621 m_clients.event(peer_id, CSE_SudoSuccess);
2625 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2627 DSTACK(FUNCTION_NAME);
2628 std::wstring message;
2631 Clear references to playing sounds
2633 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2634 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2635 ServerPlayingSound &psound = i->second;
2636 psound.clients.erase(peer_id);
2637 if (psound.clients.empty())
2638 m_playing_sounds.erase(i++);
2643 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(peer_id));
2645 /* Run scripts and remove from environment */
2646 if(player != NULL) {
2647 PlayerSAO *playersao = player->getPlayerSAO();
2650 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2652 playersao->disconnected();
2659 if(player != NULL && reason != CDR_DENY) {
2660 std::ostringstream os(std::ios_base::binary);
2661 std::vector<u16> clients = m_clients.getClientIDs();
2663 for(std::vector<u16>::iterator i = clients.begin();
2664 i != clients.end(); ++i) {
2666 Player *player = m_env->getPlayer(*i);
2670 // Get name of player
2671 os << player->getName() << " ";
2674 std::string name = player->getName();
2675 actionstream << name << " "
2676 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2677 << " List of players: " << os.str() << std::endl;
2679 m_admin_chat->outgoing_queue.push_back(
2680 new ChatEventNick(CET_NICK_REMOVE, name));
2684 MutexAutoLock env_lock(m_env_mutex);
2685 m_clients.DeleteClient(peer_id);
2689 // Send leave chat message to all remaining clients
2690 if(message.length() != 0)
2691 SendChatMessage(PEER_ID_INEXISTENT,message);
2694 void Server::UpdateCrafting(RemotePlayer* player)
2696 DSTACK(FUNCTION_NAME);
2698 // Get a preview for crafting
2700 InventoryLocation loc;
2701 loc.setPlayer(player->getName());
2702 std::vector<ItemStack> output_replacements;
2703 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2704 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2705 (&player->inventory)->getList("craft"), loc);
2707 // Put the new preview in
2708 InventoryList *plist = player->inventory.getList("craftpreview");
2709 sanity_check(plist);
2710 sanity_check(plist->getSize() >= 1);
2711 plist->changeItem(0, preview);
2714 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2716 if (evt->type == CET_NICK_ADD) {
2717 // The terminal informed us of its nick choice
2718 m_admin_nick = ((ChatEventNick *)evt)->nick;
2719 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2720 errorstream << "You haven't set up an account." << std::endl
2721 << "Please log in using the client as '"
2722 << m_admin_nick << "' with a secure password." << std::endl
2723 << "Until then, you can't execute admin tasks via the console," << std::endl
2724 << "and everybody can claim the user account instead of you," << std::endl
2725 << "giving them full control over this server." << std::endl;
2728 assert(evt->type == CET_CHAT);
2729 handleAdminChat((ChatEventChat *)evt);
2733 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2734 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2736 // If something goes wrong, this player is to blame
2737 RollbackScopeActor rollback_scope(m_rollback,
2738 std::string("player:") + name);
2742 // Whether to send line to the player that sent the message, or to all players
2743 bool broadcast_line = true;
2746 bool ate = m_script->on_chat_message(name,
2747 wide_to_utf8(wmessage));
2748 // If script ate the message, don't proceed
2753 switch (player->canSendChatMessage()) {
2754 case RPLAYER_CHATRESULT_FLOODING: {
2755 std::wstringstream ws;
2756 ws << L"You cannot send more messages. You are limited to "
2757 << g_settings->getFloat("chat_message_limit_per_10sec")
2758 << L" messages per 10 seconds.";
2761 case RPLAYER_CHATRESULT_KICK:
2762 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2764 case RPLAYER_CHATRESULT_OK: break;
2765 default: FATAL_ERROR("Unhandled chat filtering result found.");
2769 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2770 return L"Your message exceed the maximum chat message limit set on the server. "
2771 L"It was refused. Send a shorter message";
2774 // Commands are implemented in Lua, so only catch invalid
2775 // commands that were not "eaten" and send an error back
2776 if (wmessage[0] == L'/') {
2777 std::wstring wcmd = wmessage.substr(1);
2778 broadcast_line = false;
2779 if (wcmd.length() == 0)
2780 line += L"-!- Empty command";
2782 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2784 if (check_shout_priv && !checkPriv(name, "shout")) {
2785 line += L"-!- You don't have permission to shout.";
2786 broadcast_line = false;
2796 Tell calling method to send the message to sender
2798 if (!broadcast_line) {
2802 Send the message to others
2804 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2806 std::vector<u16> clients = m_clients.getClientIDs();
2808 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2809 for (u16 i = 0; i < clients.size(); i++) {
2810 u16 cid = clients[i];
2811 if (cid != peer_id_to_avoid_sending)
2812 SendChatMessage(cid, line);
2818 void Server::handleAdminChat(const ChatEventChat *evt)
2820 std::string name = evt->nick;
2821 std::wstring wname = utf8_to_wide(name);
2822 std::wstring wmessage = evt->evt_msg;
2824 std::wstring answer = handleChat(name, wname, wmessage);
2826 // If asked to send answer to sender
2827 if (!answer.empty()) {
2828 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2832 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2834 RemoteClient *client = getClientNoEx(peer_id,state_min);
2836 throw ClientNotFoundException("Client not found");
2840 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2842 return m_clients.getClientNoEx(peer_id, state_min);
2845 std::string Server::getPlayerName(u16 peer_id)
2847 Player *player = m_env->getPlayer(peer_id);
2849 return "[id="+itos(peer_id)+"]";
2850 return player->getName();
2853 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2855 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(peer_id));
2858 return player->getPlayerSAO();
2861 std::wstring Server::getStatusString()
2863 std::wostringstream os(std::ios_base::binary);
2866 os<<L"version="<<narrow_to_wide(g_version_string);
2868 os<<L", uptime="<<m_uptime.get();
2870 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2871 // Information about clients
2874 std::vector<u16> clients = m_clients.getClientIDs();
2875 for(std::vector<u16>::iterator i = clients.begin();
2876 i != clients.end(); ++i) {
2878 Player *player = m_env->getPlayer(*i);
2879 // Get name of player
2880 std::wstring name = L"unknown";
2882 name = narrow_to_wide(player->getName());
2883 // Add name to information string
2891 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2892 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2893 if(g_settings->get("motd") != "")
2894 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2898 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2900 std::set<std::string> privs;
2901 m_script->getAuth(name, NULL, &privs);
2905 bool Server::checkPriv(const std::string &name, const std::string &priv)
2907 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2908 return (privs.count(priv) != 0);
2911 void Server::reportPrivsModified(const std::string &name)
2914 std::vector<u16> clients = m_clients.getClientIDs();
2915 for(std::vector<u16>::iterator i = clients.begin();
2916 i != clients.end(); ++i) {
2917 Player *player = m_env->getPlayer(*i);
2918 reportPrivsModified(player->getName());
2921 RemotePlayer *player =
2922 dynamic_cast<RemotePlayer *>(m_env->getPlayer(name.c_str()));
2925 SendPlayerPrivileges(player->peer_id);
2926 PlayerSAO *sao = player->getPlayerSAO();
2929 sao->updatePrivileges(
2930 getPlayerEffectivePrivs(name),
2935 void Server::reportInventoryFormspecModified(const std::string &name)
2937 Player *player = m_env->getPlayer(name.c_str());
2940 SendPlayerInventoryFormspec(player->peer_id);
2943 void Server::setIpBanned(const std::string &ip, const std::string &name)
2945 m_banmanager->add(ip, name);
2948 void Server::unsetIpBanned(const std::string &ip_or_name)
2950 m_banmanager->remove(ip_or_name);
2953 std::string Server::getBanDescription(const std::string &ip_or_name)
2955 return m_banmanager->getBanDescription(ip_or_name);
2958 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2960 // m_env will be NULL if the server is initializing
2964 if (m_admin_nick == name && !m_admin_nick.empty()) {
2965 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2968 Player *player = m_env->getPlayer(name);
2973 if (player->peer_id == PEER_ID_INEXISTENT)
2976 SendChatMessage(player->peer_id, msg);
2979 bool Server::showFormspec(const char *playername, const std::string &formspec,
2980 const std::string &formname)
2982 // m_env will be NULL if the server is initializing
2986 Player *player = m_env->getPlayer(playername);
2990 SendShowFormspecMessage(player->peer_id, formspec, formname);
2994 u32 Server::hudAdd(Player *player, HudElement *form)
2999 u32 id = player->addHud(form);
3001 SendHUDAdd(player->peer_id, id, form);
3006 bool Server::hudRemove(Player *player, u32 id) {
3010 HudElement* todel = player->removeHud(id);
3017 SendHUDRemove(player->peer_id, id);
3021 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3026 SendHUDChange(player->peer_id, id, stat, data);
3030 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3035 SendHUDSetFlags(player->peer_id, flags, mask);
3036 player->hud_flags &= ~mask;
3037 player->hud_flags |= flags;
3039 PlayerSAO* playersao = player->getPlayerSAO();
3041 if (playersao == NULL)
3044 m_script->player_event(playersao, "hud_changed");
3048 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3053 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3056 player->setHotbarItemcount(hotbar_itemcount);
3057 std::ostringstream os(std::ios::binary);
3058 writeS32(os, hotbar_itemcount);
3059 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3063 void Server::hudSetHotbarImage(Player *player, std::string name)
3068 player->setHotbarImage(name);
3069 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3072 std::string Server::hudGetHotbarImage(Player *player)
3076 return player->getHotbarImage();
3079 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3084 player->setHotbarSelectedImage(name);
3085 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3088 std::string Server::hudGetHotbarSelectedImage(Player *player)
3093 return player->getHotbarSelectedImage();
3096 bool Server::setLocalPlayerAnimations(Player *player,
3097 v2s32 animation_frames[4], f32 frame_speed)
3102 player->setLocalAnimations(animation_frames, frame_speed);
3103 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3107 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3112 player->eye_offset_first = first;
3113 player->eye_offset_third = third;
3114 SendEyeOffset(player->peer_id, first, third);
3118 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3119 const std::string &type, const std::vector<std::string> ¶ms)
3124 player->setSky(bgcolor, type, params);
3125 SendSetSky(player->peer_id, bgcolor, type, params);
3129 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3135 player->overrideDayNightRatio(do_override, ratio);
3136 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3140 void Server::notifyPlayers(const std::wstring &msg)
3142 SendChatMessage(PEER_ID_INEXISTENT,msg);
3145 void Server::spawnParticle(const std::string &playername, v3f pos,
3146 v3f velocity, v3f acceleration,
3147 float expirationtime, float size, bool
3148 collisiondetection, bool collision_removal,
3149 bool vertical, const std::string &texture)
3151 // m_env will be NULL if the server is initializing
3155 u16 peer_id = PEER_ID_INEXISTENT;
3156 if (playername != "") {
3157 Player* player = m_env->getPlayer(playername.c_str());
3160 peer_id = player->peer_id;
3163 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3164 expirationtime, size, collisiondetection,
3165 collision_removal, vertical, texture);
3168 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3169 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3170 float minexptime, float maxexptime, float minsize, float maxsize,
3171 bool collisiondetection, bool collision_removal,
3172 bool vertical, const std::string &texture,
3173 const std::string &playername)
3175 // m_env will be NULL if the server is initializing
3179 u16 peer_id = PEER_ID_INEXISTENT;
3180 if (playername != "") {
3181 Player* player = m_env->getPlayer(playername.c_str());
3184 peer_id = player->peer_id;
3187 u32 id = m_env->addParticleSpawner(spawntime);
3188 SendAddParticleSpawner(peer_id, amount, spawntime,
3189 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3190 minexptime, maxexptime, minsize, maxsize,
3191 collisiondetection, collision_removal, vertical, texture, id);
3196 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3198 // m_env will be NULL if the server is initializing
3200 throw ServerError("Can't delete particle spawners during initialisation!");
3202 u16 peer_id = PEER_ID_INEXISTENT;
3203 if (playername != "") {
3204 Player* player = m_env->getPlayer(playername.c_str());
3207 peer_id = player->peer_id;
3210 m_env->deleteParticleSpawner(id);
3211 SendDeleteParticleSpawner(peer_id, id);
3214 void Server::deleteParticleSpawnerAll(u32 id)
3216 m_env->deleteParticleSpawner(id);
3217 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3220 Inventory* Server::createDetachedInventory(const std::string &name)
3222 if(m_detached_inventories.count(name) > 0){
3223 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3224 delete m_detached_inventories[name];
3226 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3228 Inventory *inv = new Inventory(m_itemdef);
3230 m_detached_inventories[name] = inv;
3231 //TODO find a better way to do this
3232 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3236 // actions: time-reversed list
3237 // Return value: success/failure
3238 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3239 std::list<std::string> *log)
3241 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3242 ServerMap *map = (ServerMap*)(&m_env->getMap());
3244 // Fail if no actions to handle
3245 if(actions.empty()){
3246 log->push_back("Nothing to do.");
3253 for(std::list<RollbackAction>::const_iterator
3254 i = actions.begin();
3255 i != actions.end(); ++i)
3257 const RollbackAction &action = *i;
3259 bool success = action.applyRevert(map, this, this);
3262 std::ostringstream os;
3263 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3264 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3266 log->push_back(os.str());
3268 std::ostringstream os;
3269 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3270 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3272 log->push_back(os.str());
3276 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3277 <<" failed"<<std::endl;
3279 // Call it done if less than half failed
3280 return num_failed <= num_tried/2;
3283 // IGameDef interface
3285 IItemDefManager *Server::getItemDefManager()
3290 INodeDefManager *Server::getNodeDefManager()
3295 ICraftDefManager *Server::getCraftDefManager()
3299 ITextureSource *Server::getTextureSource()
3303 IShaderSource *Server::getShaderSource()
3307 scene::ISceneManager *Server::getSceneManager()
3312 u16 Server::allocateUnknownNodeId(const std::string &name)
3314 return m_nodedef->allocateDummy(name);
3317 ISoundManager *Server::getSoundManager()
3319 return &dummySoundManager;
3322 MtEventManager *Server::getEventManager()
3327 IWritableItemDefManager *Server::getWritableItemDefManager()
3332 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3337 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3342 const ModSpec *Server::getModSpec(const std::string &modname) const
3344 std::vector<ModSpec>::const_iterator it;
3345 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3346 const ModSpec &mod = *it;
3347 if (mod.name == modname)
3353 void Server::getModNames(std::vector<std::string> &modlist)
3355 std::vector<ModSpec>::iterator it;
3356 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3357 modlist.push_back(it->name);
3360 std::string Server::getBuiltinLuaPath()
3362 return porting::path_share + DIR_DELIM + "builtin";
3365 v3f Server::findSpawnPos()
3367 ServerMap &map = m_env->getServerMap();
3369 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3370 return nodeposf * BS;
3373 bool is_good = false;
3375 // Try to find a good place a few times
3376 for(s32 i = 0; i < 4000 && !is_good; i++) {
3378 // We're going to try to throw the player to this position
3379 v2s16 nodepos2d = v2s16(
3380 -range + (myrand() % (range * 2)),
3381 -range + (myrand() % (range * 2)));
3383 // Get spawn level at point
3384 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3385 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3386 // the mapgen to signify an unsuitable spawn position
3387 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3390 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3393 for (s32 i = 0; i < 10; i++) {
3394 v3s16 blockpos = getNodeBlockPos(nodepos);
3395 map.emergeBlock(blockpos, true);
3396 content_t c = map.getNodeNoEx(nodepos).getContent();
3397 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3399 if (air_count >= 2) {
3400 nodeposf = intToFloat(nodepos, BS);
3401 // Don't spawn the player outside map boundaries
3402 if (objectpos_over_limit(nodeposf))
3415 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3417 bool newplayer = false;
3420 Try to get an existing player
3422 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3424 // If player is already connected, cancel
3425 if(player != NULL && player->peer_id != 0)
3427 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3432 If player with the wanted peer_id already exists, cancel.
3434 if(m_env->getPlayer(peer_id) != NULL)
3436 infostream<<"emergePlayer(): Player with wrong name but same"
3437 " peer_id already exists"<<std::endl;
3441 // Load player if it isn't already loaded
3443 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3446 // Create player if it doesn't exist
3449 player = new RemotePlayer(this, name);
3450 // Set player position
3451 infostream<<"Server: Finding spawn place for player \""
3452 <<name<<"\""<<std::endl;
3453 v3f pos = findSpawnPos();
3454 player->setPosition(pos);
3456 // Make sure the player is saved
3457 player->setModified(true);
3459 // Add player to environment
3460 m_env->addPlayer(player);
3462 // If the player exists, ensure that they respawn inside legal bounds
3463 // This fixes an assert crash when the player can't be added
3464 // to the environment
3465 if (objectpos_over_limit(player->getPosition())) {
3466 actionstream << "Respawn position for player \""
3467 << name << "\" outside limits, resetting" << std::endl;
3468 v3f pos = findSpawnPos();
3469 player->setPosition(pos);
3473 // Create a new player active object
3474 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3475 getPlayerEffectivePrivs(player->getName()),
3478 player->protocol_version = proto_version;
3480 /* Clean up old HUD elements from previous sessions */
3483 /* Add object to environment */
3484 m_env->addActiveObject(playersao);
3488 m_script->on_newplayer(playersao);
3494 void dedicated_server_loop(Server &server, bool &kill)
3496 DSTACK(FUNCTION_NAME);
3498 verbosestream<<"dedicated_server_loop()"<<std::endl;
3500 IntervalLimiter m_profiler_interval;
3502 static const float steplen = g_settings->getFloat("dedicated_server_step");
3503 static const float profiler_print_interval =
3504 g_settings->getFloat("profiler_print_interval");
3507 // This is kind of a hack but can be done like this
3508 // because server.step() is very light
3510 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3511 sleep_ms((int)(steplen*1000.0));
3513 server.step(steplen);
3515 if(server.getShutdownRequested() || kill)
3517 infostream<<"Dedicated server quitting"<<std::endl;
3519 if(g_settings->getBool("server_announce"))
3520 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3528 if (profiler_print_interval != 0) {
3529 if(m_profiler_interval.step(steplen, profiler_print_interval))
3531 infostream<<"Profiler:"<<std::endl;
3532 g_profiler->print(infostream);
3533 g_profiler->clear();