3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_async_fatal_error(""),
166 m_enable_rollback_recording(false),
169 m_itemdef(createItemDefManager()),
170 m_nodedef(createNodeDefManager()),
171 m_craftdef(createCraftDefManager()),
172 m_event(new EventManager()),
174 m_time_of_day_send_timer(0),
177 m_shutdown_requested(false),
178 m_shutdown_ask_reconnect(false),
180 m_ignore_map_edit_events(false),
181 m_ignore_map_edit_events_peer_id(0),
185 m_liquid_transform_timer = 0.0;
186 m_liquid_transform_every = 1.0;
187 m_masterserver_timer = 0.0;
188 m_emergethread_trigger_timer = 0.0;
189 m_savemap_timer = 0.0;
192 m_lag = g_settings->getFloat("dedicated_server_step");
195 throw ServerError("Supplied empty world path");
197 if(!gamespec.isValid())
198 throw ServerError("Supplied invalid gamespec");
200 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
201 if(m_simple_singleplayer_mode)
202 infostream<<" in simple singleplayer mode"<<std::endl;
204 infostream<<std::endl;
205 infostream<<"- world: "<<m_path_world<<std::endl;
206 infostream<<"- game: "<<m_gamespec.path<<std::endl;
208 // Create world if it doesn't exist
209 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
210 throw ServerError("Failed to initialize world");
212 // Create server thread
213 m_thread = new ServerThread(this);
215 // Create emerge manager
216 m_emerge = new EmergeManager(this);
218 // Create ban manager
219 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
220 m_banmanager = new BanManager(ban_path);
222 ModConfiguration modconf(m_path_world);
223 m_mods = modconf.getMods();
224 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
225 // complain about mods with unsatisfied dependencies
226 if(!modconf.isConsistent()) {
227 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
228 it != unsatisfied_mods.end(); ++it) {
230 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
231 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
232 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
233 errorstream << " \"" << *dep_it << "\"";
234 errorstream << std::endl;
238 Settings worldmt_settings;
239 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
240 worldmt_settings.readConfigFile(worldmt.c_str());
241 std::vector<std::string> names = worldmt_settings.getNames();
242 std::set<std::string> load_mod_names;
243 for(std::vector<std::string>::iterator it = names.begin();
244 it != names.end(); ++it) {
245 std::string name = *it;
246 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
247 load_mod_names.insert(name.substr(9));
249 // complain about mods declared to be loaded, but not found
250 for(std::vector<ModSpec>::iterator it = m_mods.begin();
251 it != m_mods.end(); ++it)
252 load_mod_names.erase((*it).name);
253 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
254 it != unsatisfied_mods.end(); ++it)
255 load_mod_names.erase((*it).name);
256 if(!load_mod_names.empty()) {
257 errorstream << "The following mods could not be found:";
258 for(std::set<std::string>::iterator it = load_mod_names.begin();
259 it != load_mod_names.end(); ++it)
260 errorstream << " \"" << (*it) << "\"";
261 errorstream << std::endl;
265 MutexAutoLock envlock(m_env_mutex);
267 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
268 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
270 // Initialize scripting
271 infostream<<"Server: Initializing Lua"<<std::endl;
273 m_script = new GameScripting(this);
275 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
277 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
280 infostream << "Server: Loading mods: ";
281 for(std::vector<ModSpec>::iterator i = m_mods.begin();
282 i != m_mods.end(); ++i) {
283 const ModSpec &mod = *i;
284 infostream << mod.name << " ";
286 infostream << std::endl;
287 // Load and run "mod" scripts
288 for (std::vector<ModSpec>::iterator it = m_mods.begin();
289 it != m_mods.end(); ++it) {
290 const ModSpec &mod = *it;
291 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
292 throw ModError("Error loading mod \"" + mod.name +
293 "\": Mod name does not follow naming conventions: "
294 "Only chararacters [a-z0-9_] are allowed.");
296 std::string script_path = mod.path + DIR_DELIM + "init.lua";
297 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
298 << script_path << "\"]" << std::endl;
299 m_script->loadMod(script_path, mod.name);
302 // Read Textures and calculate sha1 sums
305 // Apply item aliases in the node definition manager
306 m_nodedef->updateAliases(m_itemdef);
308 // Apply texture overrides from texturepack/override.txt
309 std::string texture_path = g_settings->get("texture_path");
310 if (texture_path != "" && fs::IsDir(texture_path))
311 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
313 m_nodedef->setNodeRegistrationStatus(true);
315 // Perform pending node name resolutions
316 m_nodedef->runNodeResolveCallbacks();
318 // unmap node names for connected nodeboxes
319 m_nodedef->mapNodeboxConnections();
321 // init the recipe hashes to speed up crafting
322 m_craftdef->initHashes(this);
324 // Initialize Environment
325 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
327 m_clients.setEnv(m_env);
329 if (!servermap->settings_mgr.makeMapgenParams())
330 FATAL_ERROR("Couldn't create any mapgen type");
332 // Initialize mapgens
333 m_emerge->initMapgens(servermap->getMapgenParams());
335 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
336 if (m_enable_rollback_recording) {
337 // Create rollback manager
338 m_rollback = new RollbackManager(m_path_world, this);
341 // Give environment reference to scripting api
342 m_script->initializeEnvironment(m_env);
344 // Register us to receive map edit events
345 servermap->addEventReceiver(this);
347 // If file exists, load environment metadata
348 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
349 infostream << "Server: Loading environment metadata" << std::endl;
352 m_env->loadDefaultMeta();
355 // Add some test ActiveBlockModifiers to environment
356 add_legacy_abms(m_env, m_nodedef);
358 m_liquid_transform_every = g_settings->getFloat("liquid_update");
359 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
364 infostream<<"Server destructing"<<std::endl;
366 // Send shutdown message
367 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
370 MutexAutoLock envlock(m_env_mutex);
372 // Execute script shutdown hooks
373 m_script->on_shutdown();
375 infostream << "Server: Saving players" << std::endl;
376 m_env->saveLoadedPlayers();
378 infostream << "Server: Kicking players" << std::endl;
379 std::string kick_msg;
380 bool reconnect = false;
381 if (getShutdownRequested()) {
382 reconnect = m_shutdown_ask_reconnect;
383 kick_msg = m_shutdown_msg;
385 if (kick_msg == "") {
386 kick_msg = g_settings->get("kick_msg_shutdown");
388 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
389 kick_msg, reconnect);
391 infostream << "Server: Saving environment metadata" << std::endl;
399 // stop all emerge threads before deleting players that may have
400 // requested blocks to be emerged
401 m_emerge->stopThreads();
403 // Delete things in the reverse order of creation
413 // Deinitialize scripting
414 infostream<<"Server: Deinitializing scripting"<<std::endl;
417 // Delete detached inventories
418 for (std::map<std::string, Inventory*>::iterator
419 i = m_detached_inventories.begin();
420 i != m_detached_inventories.end(); ++i) {
425 void Server::start(Address bind_addr)
427 DSTACK(FUNCTION_NAME);
429 m_bind_addr = bind_addr;
431 infostream<<"Starting server on "
432 << bind_addr.serializeString() <<"..."<<std::endl;
434 // Stop thread if already running
437 // Initialize connection
438 m_con.SetTimeoutMs(30);
439 m_con.Serve(bind_addr);
444 // ASCII art for the win!
446 <<" .__ __ __ "<<std::endl
447 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
448 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
449 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
450 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
451 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
452 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
453 actionstream<<"Server for gameid=\""<<m_gamespec.id
454 <<"\" listening on "<<bind_addr.serializeString()<<":"
455 <<bind_addr.getPort() << "."<<std::endl;
460 DSTACK(FUNCTION_NAME);
462 infostream<<"Server: Stopping and waiting threads"<<std::endl;
464 // Stop threads (set run=false first so both start stopping)
466 //m_emergethread.setRun(false);
468 //m_emergethread.stop();
470 infostream<<"Server: Threads stopped"<<std::endl;
473 void Server::step(float dtime)
475 DSTACK(FUNCTION_NAME);
480 MutexAutoLock lock(m_step_dtime_mutex);
481 m_step_dtime += dtime;
483 // Throw if fatal error occurred in thread
484 std::string async_err = m_async_fatal_error.get();
485 if (!async_err.empty()) {
486 if (!m_simple_singleplayer_mode) {
487 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
488 g_settings->get("kick_msg_crash"),
489 g_settings->getBool("ask_reconnect_on_crash"));
491 throw ServerError(async_err);
495 void Server::AsyncRunStep(bool initial_step)
497 DSTACK(FUNCTION_NAME);
499 g_profiler->add("Server::AsyncRunStep (num)", 1);
503 MutexAutoLock lock1(m_step_dtime_mutex);
504 dtime = m_step_dtime;
508 // Send blocks to clients
512 if((dtime < 0.001) && (initial_step == false))
515 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
517 //infostream<<"Server steps "<<dtime<<std::endl;
518 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
521 MutexAutoLock lock1(m_step_dtime_mutex);
522 m_step_dtime -= dtime;
529 m_uptime.set(m_uptime.get() + dtime);
535 Update time of day and overall game time
537 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
540 Send to clients at constant intervals
543 m_time_of_day_send_timer -= dtime;
544 if(m_time_of_day_send_timer < 0.0) {
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
552 MutexAutoLock lock(m_env_mutex);
553 // Figure out and report maximum lag to environment
554 float max_lag = m_env->getMaxLagEstimate();
555 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
557 if(dtime > 0.1 && dtime > max_lag * 2.0)
558 infostream<<"Server: Maximum lag peaked to "<<dtime
562 m_env->reportMaxLagEstimate(max_lag);
564 ScopeProfiler sp(g_profiler, "SEnv step");
565 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
569 static const float map_timer_and_unload_dtime = 2.92;
570 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
572 MutexAutoLock lock(m_env_mutex);
573 // Run Map's timers and unload unused data
574 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
575 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
576 g_settings->getFloat("server_unload_unused_data_timeout"),
581 Listen to the admin chat, if available
584 if (!m_admin_chat->command_queue.empty()) {
585 MutexAutoLock lock(m_env_mutex);
586 while (!m_admin_chat->command_queue.empty()) {
587 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
588 handleChatInterfaceEvent(evt);
592 m_admin_chat->outgoing_queue.push_back(
593 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
600 /* Transform liquids */
601 m_liquid_transform_timer += dtime;
602 if(m_liquid_transform_timer >= m_liquid_transform_every)
604 m_liquid_transform_timer -= m_liquid_transform_every;
606 MutexAutoLock lock(m_env_mutex);
608 ScopeProfiler sp(g_profiler, "Server: liquid transform");
610 std::map<v3s16, MapBlock*> modified_blocks;
611 m_env->getMap().transformLiquids(modified_blocks);
616 core::map<v3s16, MapBlock*> lighting_modified_blocks;
617 ServerMap &map = ((ServerMap&)m_env->getMap());
618 map.updateLighting(modified_blocks, lighting_modified_blocks);
620 // Add blocks modified by lighting to modified_blocks
621 for(core::map<v3s16, MapBlock*>::Iterator
622 i = lighting_modified_blocks.getIterator();
623 i.atEnd() == false; i++)
625 MapBlock *block = i.getNode()->getValue();
626 modified_blocks.insert(block->getPos(), block);
630 Set the modified blocks unsent for all the clients
632 if(!modified_blocks.empty())
634 SetBlocksNotSent(modified_blocks);
637 m_clients.step(dtime);
639 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
641 // send masterserver announce
643 float &counter = m_masterserver_timer;
644 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
645 g_settings->getBool("server_announce"))
647 ServerList::sendAnnounce(counter ? "update" : "start",
648 m_bind_addr.getPort(),
649 m_clients.getPlayerNames(),
651 m_env->getGameTime(),
654 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
663 Check added and deleted active objects
666 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
667 MutexAutoLock envlock(m_env_mutex);
670 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
671 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
673 // Radius inside which objects are active
674 static const s16 radius =
675 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
677 // Radius inside which players are active
678 static const bool is_transfer_limited =
679 g_settings->exists("unlimited_player_transfer_distance") &&
680 !g_settings->getBool("unlimited_player_transfer_distance");
681 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
682 s16 player_radius = player_transfer_dist;
683 if (player_radius == 0 && is_transfer_limited)
684 player_radius = radius;
686 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
687 i != clients.end(); ++i) {
688 RemoteClient *client = i->second;
690 // If definitions and textures have not been sent, don't
691 // send objects either
692 if (client->getState() < CS_DefinitionsSent)
695 Player *player = m_env->getPlayer(client->peer_id);
696 if (player == NULL) {
697 // This can happen if the client timeouts somehow
698 /*warningstream<<FUNCTION_NAME<<": Client "
700 <<" has no associated player"<<std::endl;*/
704 std::queue<u16> removed_objects;
705 std::queue<u16> added_objects;
706 m_env->getRemovedActiveObjects(player, radius, player_radius,
707 client->m_known_objects, removed_objects);
708 m_env->getAddedActiveObjects(player, radius, player_radius,
709 client->m_known_objects, added_objects);
711 // Ignore if nothing happened
712 if (removed_objects.empty() && added_objects.empty()) {
716 std::string data_buffer;
720 // Handle removed objects
721 writeU16((u8*)buf, removed_objects.size());
722 data_buffer.append(buf, 2);
723 while (!removed_objects.empty()) {
725 u16 id = removed_objects.front();
726 ServerActiveObject* obj = m_env->getActiveObject(id);
728 // Add to data buffer for sending
729 writeU16((u8*)buf, id);
730 data_buffer.append(buf, 2);
732 // Remove from known objects
733 client->m_known_objects.erase(id);
735 if(obj && obj->m_known_by_count > 0)
736 obj->m_known_by_count--;
737 removed_objects.pop();
740 // Handle added objects
741 writeU16((u8*)buf, added_objects.size());
742 data_buffer.append(buf, 2);
743 while (!added_objects.empty()) {
745 u16 id = added_objects.front();
746 ServerActiveObject* obj = m_env->getActiveObject(id);
749 u8 type = ACTIVEOBJECT_TYPE_INVALID;
751 warningstream<<FUNCTION_NAME
752 <<": NULL object"<<std::endl;
754 type = obj->getSendType();
756 // Add to data buffer for sending
757 writeU16((u8*)buf, id);
758 data_buffer.append(buf, 2);
759 writeU8((u8*)buf, type);
760 data_buffer.append(buf, 1);
763 data_buffer.append(serializeLongString(
764 obj->getClientInitializationData(client->net_proto_version)));
766 data_buffer.append(serializeLongString(""));
768 // Add to known objects
769 client->m_known_objects.insert(id);
772 obj->m_known_by_count++;
777 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
778 verbosestream << "Server: Sent object remove/add: "
779 << removed_objects.size() << " removed, "
780 << added_objects.size() << " added, "
781 << "packet size is " << pktSize << std::endl;
790 MutexAutoLock envlock(m_env_mutex);
791 ScopeProfiler sp(g_profiler, "Server: sending object messages");
794 // Value = data sent by object
795 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
797 // Get active object messages from environment
799 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
803 std::vector<ActiveObjectMessage>* message_list = NULL;
804 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
805 n = buffered_messages.find(aom.id);
806 if (n == buffered_messages.end()) {
807 message_list = new std::vector<ActiveObjectMessage>;
808 buffered_messages[aom.id] = message_list;
811 message_list = n->second;
813 message_list->push_back(aom);
817 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
818 // Route data to every client
819 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
820 i != clients.end(); ++i) {
821 RemoteClient *client = i->second;
822 std::string reliable_data;
823 std::string unreliable_data;
824 // Go through all objects in message buffer
825 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
826 j = buffered_messages.begin();
827 j != buffered_messages.end(); ++j) {
828 // If object is not known by client, skip it
830 if (client->m_known_objects.find(id) == client->m_known_objects.end())
833 // Get message list of object
834 std::vector<ActiveObjectMessage>* list = j->second;
835 // Go through every message
836 for (std::vector<ActiveObjectMessage>::iterator
837 k = list->begin(); k != list->end(); ++k) {
838 // Compose the full new data with header
839 ActiveObjectMessage aom = *k;
840 std::string new_data;
843 writeU16((u8*)&buf[0], aom.id);
844 new_data.append(buf, 2);
846 new_data += serializeString(aom.datastring);
847 // Add data to buffer
849 reliable_data += new_data;
851 unreliable_data += new_data;
855 reliable_data and unreliable_data are now ready.
858 if(reliable_data.size() > 0) {
859 SendActiveObjectMessages(client->peer_id, reliable_data);
862 if(unreliable_data.size() > 0) {
863 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
868 // Clear buffered_messages
869 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
870 i = buffered_messages.begin();
871 i != buffered_messages.end(); ++i) {
877 Send queued-for-sending map edit events.
880 // We will be accessing the environment
881 MutexAutoLock lock(m_env_mutex);
883 // Don't send too many at a time
886 // Single change sending is disabled if queue size is not small
887 bool disable_single_change_sending = false;
888 if(m_unsent_map_edit_queue.size() >= 4)
889 disable_single_change_sending = true;
891 int event_count = m_unsent_map_edit_queue.size();
893 // We'll log the amount of each
896 while(m_unsent_map_edit_queue.size() != 0)
898 MapEditEvent* event = m_unsent_map_edit_queue.front();
899 m_unsent_map_edit_queue.pop();
901 // Players far away from the change are stored here.
902 // Instead of sending the changes, MapBlocks are set not sent
904 std::vector<u16> far_players;
906 switch (event->type) {
909 prof.add("MEET_ADDNODE", 1);
910 sendAddNode(event->p, event->n, event->already_known_by_peer,
911 &far_players, disable_single_change_sending ? 5 : 30,
912 event->type == MEET_ADDNODE);
914 case MEET_REMOVENODE:
915 prof.add("MEET_REMOVENODE", 1);
916 sendRemoveNode(event->p, event->already_known_by_peer,
917 &far_players, disable_single_change_sending ? 5 : 30);
919 case MEET_BLOCK_NODE_METADATA_CHANGED:
920 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
921 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
922 setBlockNotSent(event->p);
925 infostream << "Server: MEET_OTHER" << std::endl;
926 prof.add("MEET_OTHER", 1);
927 for(std::set<v3s16>::iterator
928 i = event->modified_blocks.begin();
929 i != event->modified_blocks.end(); ++i) {
934 prof.add("unknown", 1);
935 warningstream << "Server: Unknown MapEditEvent "
936 << ((u32)event->type) << std::endl;
941 Set blocks not sent to far players
943 if(!far_players.empty()) {
944 // Convert list format to that wanted by SetBlocksNotSent
945 std::map<v3s16, MapBlock*> modified_blocks2;
946 for(std::set<v3s16>::iterator
947 i = event->modified_blocks.begin();
948 i != event->modified_blocks.end(); ++i) {
949 modified_blocks2[*i] =
950 m_env->getMap().getBlockNoCreateNoEx(*i);
953 // Set blocks not sent
954 for(std::vector<u16>::iterator
955 i = far_players.begin();
956 i != far_players.end(); ++i) {
957 if(RemoteClient *client = getClient(*i))
958 client->SetBlocksNotSent(modified_blocks2);
964 /*// Don't send too many at a time
966 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
970 if(event_count >= 5){
971 infostream<<"Server: MapEditEvents:"<<std::endl;
972 prof.print(infostream);
973 } else if(event_count != 0){
974 verbosestream<<"Server: MapEditEvents:"<<std::endl;
975 prof.print(verbosestream);
981 Trigger emergethread (it somehow gets to a non-triggered but
982 bysy state sometimes)
985 float &counter = m_emergethread_trigger_timer;
987 if (counter >= 2.0) {
990 m_emerge->startThreads();
994 // Save map, players and auth stuff
996 float &counter = m_savemap_timer;
998 static const float save_interval =
999 g_settings->getFloat("server_map_save_interval");
1000 if (counter >= save_interval) {
1002 MutexAutoLock lock(m_env_mutex);
1004 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1007 if (m_banmanager->isModified()) {
1008 m_banmanager->save();
1011 // Save changed parts of map
1012 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1015 m_env->saveLoadedPlayers();
1017 // Save environment metadata
1023 void Server::Receive()
1025 DSTACK(FUNCTION_NAME);
1026 SharedBuffer<u8> data;
1030 m_con.Receive(&pkt);
1031 peer_id = pkt.getPeerId();
1034 catch(con::InvalidIncomingDataException &e) {
1035 infostream<<"Server::Receive(): "
1036 "InvalidIncomingDataException: what()="
1037 <<e.what()<<std::endl;
1039 catch(SerializationError &e) {
1040 infostream<<"Server::Receive(): "
1041 "SerializationError: what()="
1042 <<e.what()<<std::endl;
1044 catch(ClientStateError &e) {
1045 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1046 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1047 L"Try reconnecting or updating your client");
1049 catch(con::PeerNotFoundException &e) {
1054 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1056 std::string playername = "";
1057 PlayerSAO *playersao = NULL;
1060 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1061 if (client != NULL) {
1062 playername = client->getName();
1063 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1065 } catch (std::exception &e) {
1071 RemotePlayer *player =
1072 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1074 // If failed, cancel
1075 if ((playersao == NULL) || (player == NULL)) {
1076 if (player && player->peer_id != 0) {
1077 actionstream << "Server: Failed to emerge player \"" << playername
1078 << "\" (player allocated to an another client)" << std::endl;
1079 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1080 L"name. If your client closed unexpectedly, try again in "
1083 errorstream << "Server: " << playername << ": Failed to emerge player"
1085 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1091 Send complete position information
1093 SendMovePlayer(peer_id);
1096 SendPlayerPrivileges(peer_id);
1098 // Send inventory formspec
1099 SendPlayerInventoryFormspec(peer_id);
1102 SendInventory(playersao);
1105 SendPlayerHPOrDie(playersao);
1108 SendPlayerBreath(peer_id);
1110 // Show death screen if necessary
1111 if(player->isDead())
1112 SendDeathscreen(peer_id, false, v3f(0,0,0));
1114 // Note things in chat if not in simple singleplayer mode
1115 if(!m_simple_singleplayer_mode) {
1116 // Send information about server to player in chat
1117 SendChatMessage(peer_id, getStatusString());
1119 Address addr = getPeerAddress(player->peer_id);
1120 std::string ip_str = addr.serializeString();
1121 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1126 std::vector<std::string> names = m_clients.getPlayerNames();
1128 actionstream<<player->getName() <<" joins game. List of players: ";
1130 for (std::vector<std::string>::iterator i = names.begin();
1131 i != names.end(); ++i) {
1132 actionstream << *i << " ";
1135 actionstream << player->getName() <<std::endl;
1140 inline void Server::handleCommand(NetworkPacket* pkt)
1142 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1143 (this->*opHandle.handler)(pkt);
1146 void Server::ProcessData(NetworkPacket *pkt)
1148 DSTACK(FUNCTION_NAME);
1149 // Environment is locked first.
1150 MutexAutoLock envlock(m_env_mutex);
1152 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1153 u32 peer_id = pkt->getPeerId();
1156 Address address = getPeerAddress(peer_id);
1157 std::string addr_s = address.serializeString();
1159 if(m_banmanager->isIpBanned(addr_s)) {
1160 std::string ban_name = m_banmanager->getBanName(addr_s);
1161 infostream << "Server: A banned client tried to connect from "
1162 << addr_s << "; banned name was "
1163 << ban_name << std::endl;
1164 // This actually doesn't seem to transfer to the client
1165 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1166 + utf8_to_wide(ban_name));
1170 catch(con::PeerNotFoundException &e) {
1172 * no peer for this packet found
1173 * most common reason is peer timeout, e.g. peer didn't
1174 * respond for some time, your server was overloaded or
1177 infostream << "Server::ProcessData(): Canceling: peer "
1178 << peer_id << " not found" << std::endl;
1183 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1185 // Command must be handled into ToServerCommandHandler
1186 if (command >= TOSERVER_NUM_MSG_TYPES) {
1187 infostream << "Server: Ignoring unknown command "
1188 << command << std::endl;
1192 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1197 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1199 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1200 errorstream << "Server::ProcessData(): Cancelling: Peer"
1201 " serialization format invalid or not initialized."
1202 " Skipping incoming command=" << command << std::endl;
1206 /* Handle commands related to client startup */
1207 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1212 if (m_clients.getClientState(peer_id) < CS_Active) {
1213 if (command == TOSERVER_PLAYERPOS) return;
1215 errorstream << "Got packet command: " << command << " for peer id "
1216 << peer_id << " but client isn't active yet. Dropping packet "
1222 } catch (SendFailedException &e) {
1223 errorstream << "Server::ProcessData(): SendFailedException: "
1224 << "what=" << e.what()
1226 } catch (PacketError &e) {
1227 actionstream << "Server::ProcessData(): PacketError: "
1228 << "what=" << e.what()
1233 void Server::setTimeOfDay(u32 time)
1235 m_env->setTimeOfDay(time);
1236 m_time_of_day_send_timer = 0;
1239 void Server::onMapEditEvent(MapEditEvent *event)
1241 if(m_ignore_map_edit_events)
1243 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1245 MapEditEvent *e = event->clone();
1246 m_unsent_map_edit_queue.push(e);
1249 Inventory* Server::getInventory(const InventoryLocation &loc)
1252 case InventoryLocation::UNDEFINED:
1253 case InventoryLocation::CURRENT_PLAYER:
1255 case InventoryLocation::PLAYER:
1257 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1260 PlayerSAO *playersao = player->getPlayerSAO();
1263 return playersao->getInventory();
1266 case InventoryLocation::NODEMETA:
1268 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1271 return meta->getInventory();
1274 case InventoryLocation::DETACHED:
1276 if(m_detached_inventories.count(loc.name) == 0)
1278 return m_detached_inventories[loc.name];
1282 sanity_check(false); // abort
1287 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1290 case InventoryLocation::UNDEFINED:
1292 case InventoryLocation::PLAYER:
1297 RemotePlayer *player =
1298 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1303 PlayerSAO *playersao = player->getPlayerSAO();
1307 SendInventory(playersao);
1310 case InventoryLocation::NODEMETA:
1312 v3s16 blockpos = getNodeBlockPos(loc.p);
1314 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1316 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1318 setBlockNotSent(blockpos);
1321 case InventoryLocation::DETACHED:
1323 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1327 sanity_check(false); // abort
1332 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1334 std::vector<u16> clients = m_clients.getClientIDs();
1336 // Set the modified blocks unsent for all the clients
1337 for (std::vector<u16>::iterator i = clients.begin();
1338 i != clients.end(); ++i) {
1339 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1340 client->SetBlocksNotSent(block);
1345 void Server::peerAdded(con::Peer *peer)
1347 DSTACK(FUNCTION_NAME);
1348 verbosestream<<"Server::peerAdded(): peer->id="
1349 <<peer->id<<std::endl;
1352 c.type = con::PEER_ADDED;
1353 c.peer_id = peer->id;
1355 m_peer_change_queue.push(c);
1358 void Server::deletingPeer(con::Peer *peer, bool timeout)
1360 DSTACK(FUNCTION_NAME);
1361 verbosestream<<"Server::deletingPeer(): peer->id="
1362 <<peer->id<<", timeout="<<timeout<<std::endl;
1364 m_clients.event(peer->id, CSE_Disconnect);
1366 c.type = con::PEER_REMOVED;
1367 c.peer_id = peer->id;
1368 c.timeout = timeout;
1369 m_peer_change_queue.push(c);
1372 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1374 *retval = m_con.getPeerStat(peer_id,type);
1375 if (*retval == -1) return false;
1379 bool Server::getClientInfo(
1388 std::string* vers_string
1391 *state = m_clients.getClientState(peer_id);
1393 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1395 if (client == NULL) {
1400 *uptime = client->uptime();
1401 *ser_vers = client->serialization_version;
1402 *prot_vers = client->net_proto_version;
1404 *major = client->getMajor();
1405 *minor = client->getMinor();
1406 *patch = client->getPatch();
1407 *vers_string = client->getPatch();
1414 void Server::handlePeerChanges()
1416 while(m_peer_change_queue.size() > 0)
1418 con::PeerChange c = m_peer_change_queue.front();
1419 m_peer_change_queue.pop();
1421 verbosestream<<"Server: Handling peer change: "
1422 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1427 case con::PEER_ADDED:
1428 m_clients.CreateClient(c.peer_id);
1431 case con::PEER_REMOVED:
1432 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1436 FATAL_ERROR("Invalid peer change event received!");
1442 void Server::printToConsoleOnly(const std::string &text)
1445 m_admin_chat->outgoing_queue.push_back(
1446 new ChatEventChat("", utf8_to_wide(text)));
1448 std::cout << text << std::endl;
1452 void Server::Send(NetworkPacket* pkt)
1454 m_clients.send(pkt->getPeerId(),
1455 clientCommandFactoryTable[pkt->getCommand()].channel,
1457 clientCommandFactoryTable[pkt->getCommand()].reliable);
1460 void Server::SendMovement(u16 peer_id)
1462 DSTACK(FUNCTION_NAME);
1463 std::ostringstream os(std::ios_base::binary);
1465 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1467 pkt << g_settings->getFloat("movement_acceleration_default");
1468 pkt << g_settings->getFloat("movement_acceleration_air");
1469 pkt << g_settings->getFloat("movement_acceleration_fast");
1470 pkt << g_settings->getFloat("movement_speed_walk");
1471 pkt << g_settings->getFloat("movement_speed_crouch");
1472 pkt << g_settings->getFloat("movement_speed_fast");
1473 pkt << g_settings->getFloat("movement_speed_climb");
1474 pkt << g_settings->getFloat("movement_speed_jump");
1475 pkt << g_settings->getFloat("movement_liquid_fluidity");
1476 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1477 pkt << g_settings->getFloat("movement_liquid_sink");
1478 pkt << g_settings->getFloat("movement_gravity");
1483 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1485 if (!g_settings->getBool("enable_damage"))
1488 u16 peer_id = playersao->getPeerID();
1489 bool is_alive = playersao->getHP() > 0;
1492 SendPlayerHP(peer_id);
1497 void Server::SendHP(u16 peer_id, u8 hp)
1499 DSTACK(FUNCTION_NAME);
1501 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1506 void Server::SendBreath(u16 peer_id, u16 breath)
1508 DSTACK(FUNCTION_NAME);
1510 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1511 pkt << (u16) breath;
1515 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1516 const std::string &custom_reason, bool reconnect)
1518 assert(reason < SERVER_ACCESSDENIED_MAX);
1520 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1522 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1523 pkt << custom_reason;
1524 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1525 reason == SERVER_ACCESSDENIED_CRASH)
1526 pkt << custom_reason << (u8)reconnect;
1530 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1532 DSTACK(FUNCTION_NAME);
1534 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1539 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1540 v3f camera_point_target)
1542 DSTACK(FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1545 pkt << set_camera_point_target << camera_point_target;
1549 void Server::SendItemDef(u16 peer_id,
1550 IItemDefManager *itemdef, u16 protocol_version)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1558 u32 length of the next item
1559 zlib-compressed serialized ItemDefManager
1561 std::ostringstream tmp_os(std::ios::binary);
1562 itemdef->serialize(tmp_os, protocol_version);
1563 std::ostringstream tmp_os2(std::ios::binary);
1564 compressZlib(tmp_os.str(), tmp_os2);
1565 pkt.putLongString(tmp_os2.str());
1568 verbosestream << "Server: Sending item definitions to id(" << peer_id
1569 << "): size=" << pkt.getSize() << std::endl;
1574 void Server::SendNodeDef(u16 peer_id,
1575 INodeDefManager *nodedef, u16 protocol_version)
1577 DSTACK(FUNCTION_NAME);
1579 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1583 u32 length of the next item
1584 zlib-compressed serialized NodeDefManager
1586 std::ostringstream tmp_os(std::ios::binary);
1587 nodedef->serialize(tmp_os, protocol_version);
1588 std::ostringstream tmp_os2(std::ios::binary);
1589 compressZlib(tmp_os.str(), tmp_os2);
1591 pkt.putLongString(tmp_os2.str());
1594 verbosestream << "Server: Sending node definitions to id(" << peer_id
1595 << "): size=" << pkt.getSize() << std::endl;
1601 Non-static send methods
1604 void Server::SendInventory(PlayerSAO* playerSAO)
1606 DSTACK(FUNCTION_NAME);
1608 UpdateCrafting(playerSAO->getPlayer());
1614 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1616 std::ostringstream os;
1617 playerSAO->getInventory()->serialize(os);
1619 std::string s = os.str();
1621 pkt.putRawString(s.c_str(), s.size());
1625 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1627 DSTACK(FUNCTION_NAME);
1629 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1632 if (peer_id != PEER_ID_INEXISTENT) {
1636 m_clients.sendToAll(0, &pkt, true);
1640 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1641 const std::string &formname)
1643 DSTACK(FUNCTION_NAME);
1645 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1647 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1653 // Spawns a particle on peer with peer_id
1654 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1655 float expirationtime, float size, bool collisiondetection,
1656 bool collision_removal,
1657 bool vertical, const std::string &texture)
1659 DSTACK(FUNCTION_NAME);
1661 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1663 pkt << pos << velocity << acceleration << expirationtime
1664 << size << collisiondetection;
1665 pkt.putLongString(texture);
1667 pkt << collision_removal;
1669 if (peer_id != PEER_ID_INEXISTENT) {
1673 m_clients.sendToAll(0, &pkt, true);
1677 // Adds a ParticleSpawner on peer with peer_id
1678 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1679 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1680 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1681 bool vertical, const std::string &texture, u32 id)
1683 DSTACK(FUNCTION_NAME);
1685 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1687 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1688 << minacc << maxacc << minexptime << maxexptime << minsize
1689 << maxsize << collisiondetection;
1691 pkt.putLongString(texture);
1693 pkt << id << vertical;
1694 pkt << collision_removal;
1696 if (peer_id != PEER_ID_INEXISTENT) {
1700 m_clients.sendToAll(0, &pkt, true);
1704 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1706 DSTACK(FUNCTION_NAME);
1708 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1710 // Ugly error in this packet
1713 if (peer_id != PEER_ID_INEXISTENT) {
1717 m_clients.sendToAll(0, &pkt, true);
1722 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1724 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1726 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1727 << form->text << form->number << form->item << form->dir
1728 << form->align << form->offset << form->world_pos << form->size;
1733 void Server::SendHUDRemove(u16 peer_id, u32 id)
1735 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1740 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1742 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1743 pkt << id << (u8) stat;
1747 case HUD_STAT_SCALE:
1748 case HUD_STAT_ALIGN:
1749 case HUD_STAT_OFFSET:
1750 pkt << *(v2f *) value;
1754 pkt << *(std::string *) value;
1756 case HUD_STAT_WORLD_POS:
1757 pkt << *(v3f *) value;
1760 pkt << *(v2s32 *) value;
1762 case HUD_STAT_NUMBER:
1766 pkt << *(u32 *) value;
1773 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1775 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1777 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1779 pkt << flags << mask;
1784 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1786 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1787 pkt << param << value;
1791 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1792 const std::string &type, const std::vector<std::string> ¶ms)
1794 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1795 pkt << bgcolor << type << (u16) params.size();
1797 for(size_t i=0; i<params.size(); i++)
1803 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1806 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1809 pkt << do_override << (u16) (ratio * 65535);
1814 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1816 DSTACK(FUNCTION_NAME);
1818 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1819 pkt << time << time_speed;
1821 if (peer_id == PEER_ID_INEXISTENT) {
1822 m_clients.sendToAll(0, &pkt, true);
1829 void Server::SendPlayerHP(u16 peer_id)
1831 DSTACK(FUNCTION_NAME);
1832 PlayerSAO *playersao = getPlayerSAO(peer_id);
1833 // In some rare case if the player is disconnected
1834 // while Lua call l_punch, for example, this can be NULL
1838 SendHP(peer_id, playersao->getHP());
1839 m_script->player_event(playersao,"health_changed");
1841 // Send to other clients
1842 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1843 ActiveObjectMessage aom(playersao->getId(), true, str);
1844 playersao->m_messages_out.push(aom);
1847 void Server::SendPlayerBreath(u16 peer_id)
1849 DSTACK(FUNCTION_NAME);
1850 PlayerSAO *playersao = getPlayerSAO(peer_id);
1853 m_script->player_event(playersao, "breath_changed");
1854 SendBreath(peer_id, playersao->getBreath());
1857 void Server::SendMovePlayer(u16 peer_id)
1859 DSTACK(FUNCTION_NAME);
1860 Player *player = m_env->getPlayer(peer_id);
1863 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1864 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1867 v3f pos = player->getPosition();
1868 f32 pitch = player->getPitch();
1869 f32 yaw = player->getYaw();
1870 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1871 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1872 << " pitch=" << pitch
1880 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1882 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1885 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1886 << animation_frames[3] << animation_speed;
1891 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1893 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1894 pkt << first << third;
1897 void Server::SendPlayerPrivileges(u16 peer_id)
1899 Player *player = m_env->getPlayer(peer_id);
1901 if(player->peer_id == PEER_ID_INEXISTENT)
1904 std::set<std::string> privs;
1905 m_script->getAuth(player->getName(), NULL, &privs);
1907 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1908 pkt << (u16) privs.size();
1910 for(std::set<std::string>::const_iterator i = privs.begin();
1911 i != privs.end(); ++i) {
1918 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1920 Player *player = m_env->getPlayer(peer_id);
1922 if(player->peer_id == PEER_ID_INEXISTENT)
1925 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1926 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1930 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1932 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1933 pkt.putRawString(datas.c_str(), datas.size());
1935 return pkt.getSize();
1938 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1940 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1941 datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 m_clients.send(pkt.getPeerId(),
1946 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1951 s32 Server::playSound(const SimpleSoundSpec &spec,
1952 const ServerSoundParams ¶ms)
1954 // Find out initial position of sound
1955 bool pos_exists = false;
1956 v3f pos = params.getPos(m_env, &pos_exists);
1957 // If position is not found while it should be, cancel sound
1958 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1961 // Filter destination clients
1962 std::vector<u16> dst_clients;
1963 if(params.to_player != "")
1965 Player *player = m_env->getPlayer(params.to_player.c_str());
1967 infostream<<"Server::playSound: Player \""<<params.to_player
1968 <<"\" not found"<<std::endl;
1971 if(player->peer_id == PEER_ID_INEXISTENT){
1972 infostream<<"Server::playSound: Player \""<<params.to_player
1973 <<"\" not connected"<<std::endl;
1976 dst_clients.push_back(player->peer_id);
1979 std::vector<u16> clients = m_clients.getClientIDs();
1981 for(std::vector<u16>::iterator
1982 i = clients.begin(); i != clients.end(); ++i) {
1983 Player *player = m_env->getPlayer(*i);
1988 if(player->getPosition().getDistanceFrom(pos) >
1989 params.max_hear_distance)
1992 dst_clients.push_back(*i);
1996 if(dst_clients.empty())
2000 s32 id = m_next_sound_id++;
2001 // The sound will exist as a reference in m_playing_sounds
2002 m_playing_sounds[id] = ServerPlayingSound();
2003 ServerPlayingSound &psound = m_playing_sounds[id];
2004 psound.params = params;
2006 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2007 pkt << id << spec.name << (float) (spec.gain * params.gain)
2008 << (u8) params.type << pos << params.object << params.loop;
2010 for(std::vector<u16>::iterator i = dst_clients.begin();
2011 i != dst_clients.end(); ++i) {
2012 psound.clients.insert(*i);
2013 m_clients.send(*i, 0, &pkt, true);
2017 void Server::stopSound(s32 handle)
2019 // Get sound reference
2020 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2021 if (i == m_playing_sounds.end())
2023 ServerPlayingSound &psound = i->second;
2025 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2028 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2029 i != psound.clients.end(); ++i) {
2031 m_clients.send(*i, 0, &pkt, true);
2033 // Remove sound reference
2034 m_playing_sounds.erase(i);
2037 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2038 std::vector<u16> *far_players, float far_d_nodes)
2040 float maxd = far_d_nodes*BS;
2041 v3f p_f = intToFloat(p, BS);
2043 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2046 std::vector<u16> clients = m_clients.getClientIDs();
2047 for(std::vector<u16>::iterator i = clients.begin();
2048 i != clients.end(); ++i) {
2051 if(Player *player = m_env->getPlayer(*i)) {
2052 // If player is far away, only set modified blocks not sent
2053 v3f player_pos = player->getPosition();
2054 if(player_pos.getDistanceFrom(p_f) > maxd) {
2055 far_players->push_back(*i);
2062 m_clients.send(*i, 0, &pkt, true);
2066 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2067 std::vector<u16> *far_players, float far_d_nodes,
2068 bool remove_metadata)
2070 float maxd = far_d_nodes*BS;
2071 v3f p_f = intToFloat(p, BS);
2073 std::vector<u16> clients = m_clients.getClientIDs();
2074 for(std::vector<u16>::iterator i = clients.begin();
2075 i != clients.end(); ++i) {
2079 if(Player *player = m_env->getPlayer(*i)) {
2080 // If player is far away, only set modified blocks not sent
2081 v3f player_pos = player->getPosition();
2082 if(player_pos.getDistanceFrom(p_f) > maxd) {
2083 far_players->push_back(*i);
2089 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2091 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2093 pkt << p << n.param0 << n.param1 << n.param2
2094 << (u8) (remove_metadata ? 0 : 1);
2096 if (!remove_metadata) {
2097 if (client->net_proto_version <= 21) {
2098 // Old clients always clear metadata; fix it
2099 // by sending the full block again.
2100 client->SetBlockNotSent(getNodeBlockPos(p));
2107 if (pkt.getSize() > 0)
2108 m_clients.send(*i, 0, &pkt, true);
2112 void Server::setBlockNotSent(v3s16 p)
2114 std::vector<u16> clients = m_clients.getClientIDs();
2116 for(std::vector<u16>::iterator i = clients.begin();
2117 i != clients.end(); ++i) {
2118 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2119 client->SetBlockNotSent(p);
2124 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2126 DSTACK(FUNCTION_NAME);
2128 v3s16 p = block->getPos();
2131 Create a packet with the block in the right format
2134 std::ostringstream os(std::ios_base::binary);
2135 block->serialize(os, ver, false);
2136 block->serializeNetworkSpecific(os, net_proto_version);
2137 std::string s = os.str();
2139 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2142 pkt.putRawString(s.c_str(), s.size());
2146 void Server::SendBlocks(float dtime)
2148 DSTACK(FUNCTION_NAME);
2150 MutexAutoLock envlock(m_env_mutex);
2151 //TODO check if one big lock could be faster then multiple small ones
2153 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2155 std::vector<PrioritySortedBlockTransfer> queue;
2157 s32 total_sending = 0;
2160 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2162 std::vector<u16> clients = m_clients.getClientIDs();
2165 for(std::vector<u16>::iterator i = clients.begin();
2166 i != clients.end(); ++i) {
2167 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2172 total_sending += client->SendingCount();
2173 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2179 // Lowest priority number comes first.
2180 // Lowest is most important.
2181 std::sort(queue.begin(), queue.end());
2184 for(u32 i=0; i<queue.size(); i++)
2186 //TODO: Calculate limit dynamically
2187 if(total_sending >= g_settings->getS32
2188 ("max_simultaneous_block_sends_server_total"))
2191 PrioritySortedBlockTransfer q = queue[i];
2193 MapBlock *block = NULL;
2196 block = m_env->getMap().getBlockNoCreate(q.pos);
2198 catch(InvalidPositionException &e)
2203 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2208 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2210 client->SentBlock(q.pos);
2216 void Server::fillMediaCache()
2218 DSTACK(FUNCTION_NAME);
2220 infostream<<"Server: Calculating media file checksums"<<std::endl;
2222 // Collect all media file paths
2223 std::vector<std::string> paths;
2224 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2225 i != m_mods.end(); ++i) {
2226 const ModSpec &mod = *i;
2227 paths.push_back(mod.path + DIR_DELIM + "textures");
2228 paths.push_back(mod.path + DIR_DELIM + "sounds");
2229 paths.push_back(mod.path + DIR_DELIM + "media");
2230 paths.push_back(mod.path + DIR_DELIM + "models");
2232 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2234 // Collect media file information from paths into cache
2235 for(std::vector<std::string>::iterator i = paths.begin();
2236 i != paths.end(); ++i) {
2237 std::string mediapath = *i;
2238 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2239 for (u32 j = 0; j < dirlist.size(); j++) {
2240 if (dirlist[j].dir) // Ignode dirs
2242 std::string filename = dirlist[j].name;
2243 // If name contains illegal characters, ignore the file
2244 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2245 infostream<<"Server: ignoring illegal file name: \""
2246 << filename << "\"" << std::endl;
2249 // If name is not in a supported format, ignore it
2250 const char *supported_ext[] = {
2251 ".png", ".jpg", ".bmp", ".tga",
2252 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2254 ".x", ".b3d", ".md2", ".obj",
2257 if (removeStringEnd(filename, supported_ext) == ""){
2258 infostream << "Server: ignoring unsupported file extension: \""
2259 << filename << "\"" << std::endl;
2262 // Ok, attempt to load the file and add to cache
2263 std::string filepath = mediapath + DIR_DELIM + filename;
2265 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2267 errorstream << "Server::fillMediaCache(): Could not open \""
2268 << filename << "\" for reading" << std::endl;
2271 std::ostringstream tmp_os(std::ios_base::binary);
2275 fis.read(buf, 1024);
2276 std::streamsize len = fis.gcount();
2277 tmp_os.write(buf, len);
2286 errorstream<<"Server::fillMediaCache(): Failed to read \""
2287 << filename << "\"" << std::endl;
2290 if(tmp_os.str().length() == 0) {
2291 errorstream << "Server::fillMediaCache(): Empty file \""
2292 << filepath << "\"" << std::endl;
2297 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2299 unsigned char *digest = sha1.getDigest();
2300 std::string sha1_base64 = base64_encode(digest, 20);
2301 std::string sha1_hex = hex_encode((char*)digest, 20);
2305 m_media[filename] = MediaInfo(filepath, sha1_base64);
2306 verbosestream << "Server: " << sha1_hex << " is " << filename
2312 void Server::sendMediaAnnouncement(u16 peer_id)
2314 DSTACK(FUNCTION_NAME);
2316 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2320 std::ostringstream os(std::ios_base::binary);
2322 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2323 pkt << (u16) m_media.size();
2325 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2326 i != m_media.end(); ++i) {
2327 pkt << i->first << i->second.sha1_digest;
2330 pkt << g_settings->get("remote_media");
2334 struct SendableMedia
2340 SendableMedia(const std::string &name_="", const std::string &path_="",
2341 const std::string &data_=""):
2348 void Server::sendRequestedMedia(u16 peer_id,
2349 const std::vector<std::string> &tosend)
2351 DSTACK(FUNCTION_NAME);
2353 verbosestream<<"Server::sendRequestedMedia(): "
2354 <<"Sending files to client"<<std::endl;
2358 // Put 5kB in one bunch (this is not accurate)
2359 u32 bytes_per_bunch = 5000;
2361 std::vector< std::vector<SendableMedia> > file_bunches;
2362 file_bunches.push_back(std::vector<SendableMedia>());
2364 u32 file_size_bunch_total = 0;
2366 for(std::vector<std::string>::const_iterator i = tosend.begin();
2367 i != tosend.end(); ++i) {
2368 const std::string &name = *i;
2370 if (m_media.find(name) == m_media.end()) {
2371 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2372 <<"unknown file \""<<(name)<<"\""<<std::endl;
2376 //TODO get path + name
2377 std::string tpath = m_media[name].path;
2380 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2381 if(fis.good() == false){
2382 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2383 <<tpath<<"\" for reading"<<std::endl;
2386 std::ostringstream tmp_os(std::ios_base::binary);
2390 fis.read(buf, 1024);
2391 std::streamsize len = fis.gcount();
2392 tmp_os.write(buf, len);
2393 file_size_bunch_total += len;
2402 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2403 <<name<<"\""<<std::endl;
2406 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2407 <<tname<<"\""<<std::endl;*/
2409 file_bunches[file_bunches.size()-1].push_back(
2410 SendableMedia(name, tpath, tmp_os.str()));
2412 // Start next bunch if got enough data
2413 if(file_size_bunch_total >= bytes_per_bunch) {
2414 file_bunches.push_back(std::vector<SendableMedia>());
2415 file_size_bunch_total = 0;
2420 /* Create and send packets */
2422 u16 num_bunches = file_bunches.size();
2423 for(u16 i = 0; i < num_bunches; i++) {
2426 u16 total number of texture bunches
2427 u16 index of this bunch
2428 u32 number of files in this bunch
2437 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2438 pkt << num_bunches << i << (u32) file_bunches[i].size();
2440 for(std::vector<SendableMedia>::iterator
2441 j = file_bunches[i].begin();
2442 j != file_bunches[i].end(); ++j) {
2444 pkt.putLongString(j->data);
2447 verbosestream << "Server::sendRequestedMedia(): bunch "
2448 << i << "/" << num_bunches
2449 << " files=" << file_bunches[i].size()
2450 << " size=" << pkt.getSize() << std::endl;
2455 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2457 if(m_detached_inventories.count(name) == 0) {
2458 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2461 Inventory *inv = m_detached_inventories[name];
2462 std::ostringstream os(std::ios_base::binary);
2464 os << serializeString(name);
2468 std::string s = os.str();
2470 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2471 pkt.putRawString(s.c_str(), s.size());
2473 if (peer_id != PEER_ID_INEXISTENT) {
2477 m_clients.sendToAll(0, &pkt, true);
2481 void Server::sendDetachedInventories(u16 peer_id)
2483 DSTACK(FUNCTION_NAME);
2485 for(std::map<std::string, Inventory*>::iterator
2486 i = m_detached_inventories.begin();
2487 i != m_detached_inventories.end(); ++i) {
2488 const std::string &name = i->first;
2489 //Inventory *inv = i->second;
2490 sendDetachedInventory(name, peer_id);
2498 void Server::DiePlayer(u16 peer_id)
2500 DSTACK(FUNCTION_NAME);
2501 PlayerSAO *playersao = getPlayerSAO(peer_id);
2502 // In some rare cases this can be NULL -- if the player is disconnected
2503 // when a Lua function modifies l_punch, for example
2507 infostream << "Server::DiePlayer(): Player "
2508 << playersao->getPlayer()->getName()
2509 << " dies" << std::endl;
2511 playersao->setHP(0);
2513 // Trigger scripted stuff
2514 m_script->on_dieplayer(playersao);
2516 SendPlayerHP(peer_id);
2517 SendDeathscreen(peer_id, false, v3f(0,0,0));
2520 void Server::RespawnPlayer(u16 peer_id)
2522 DSTACK(FUNCTION_NAME);
2524 PlayerSAO *playersao = getPlayerSAO(peer_id);
2527 infostream << "Server::RespawnPlayer(): Player "
2528 << playersao->getPlayer()->getName()
2529 << " respawns" << std::endl;
2531 playersao->setHP(PLAYER_MAX_HP);
2532 playersao->setBreath(PLAYER_MAX_BREATH);
2534 SendPlayerHP(peer_id);
2535 SendPlayerBreath(peer_id);
2537 bool repositioned = m_script->on_respawnplayer(playersao);
2539 v3f pos = findSpawnPos();
2540 // setPos will send the new position to client
2541 playersao->setPos(pos);
2546 void Server::DenySudoAccess(u16 peer_id)
2548 DSTACK(FUNCTION_NAME);
2550 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2555 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2556 const std::string &str_reason, bool reconnect)
2558 if (proto_ver >= 25) {
2559 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2561 std::wstring wreason = utf8_to_wide(
2562 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2563 accessDeniedStrings[(u8)reason]);
2564 SendAccessDenied_Legacy(peer_id, wreason);
2567 m_clients.event(peer_id, CSE_SetDenied);
2568 m_con.DisconnectPeer(peer_id);
2572 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2574 DSTACK(FUNCTION_NAME);
2576 SendAccessDenied(peer_id, reason, custom_reason);
2577 m_clients.event(peer_id, CSE_SetDenied);
2578 m_con.DisconnectPeer(peer_id);
2581 // 13/03/15: remove this function when protocol version 25 will become
2582 // the minimum version for MT users, maybe in 1 year
2583 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2585 DSTACK(FUNCTION_NAME);
2587 SendAccessDenied_Legacy(peer_id, reason);
2588 m_clients.event(peer_id, CSE_SetDenied);
2589 m_con.DisconnectPeer(peer_id);
2592 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2594 DSTACK(FUNCTION_NAME);
2597 RemoteClient* client = getClient(peer_id, CS_Invalid);
2599 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2601 // Right now, the auth mechs don't change between login and sudo mode.
2602 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2603 client->allowed_sudo_mechs = sudo_auth_mechs;
2605 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2606 << g_settings->getFloat("dedicated_server_step")
2610 m_clients.event(peer_id, CSE_AuthAccept);
2612 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2614 // We only support SRP right now
2615 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2617 resp_pkt << sudo_auth_mechs;
2619 m_clients.event(peer_id, CSE_SudoSuccess);
2623 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2625 DSTACK(FUNCTION_NAME);
2626 std::wstring message;
2629 Clear references to playing sounds
2631 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2632 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2633 ServerPlayingSound &psound = i->second;
2634 psound.clients.erase(peer_id);
2635 if (psound.clients.empty())
2636 m_playing_sounds.erase(i++);
2641 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(peer_id));
2643 /* Run scripts and remove from environment */
2644 if(player != NULL) {
2645 PlayerSAO *playersao = player->getPlayerSAO();
2648 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2650 playersao->disconnected();
2657 if(player != NULL && reason != CDR_DENY) {
2658 std::ostringstream os(std::ios_base::binary);
2659 std::vector<u16> clients = m_clients.getClientIDs();
2661 for(std::vector<u16>::iterator i = clients.begin();
2662 i != clients.end(); ++i) {
2664 Player *player = m_env->getPlayer(*i);
2668 // Get name of player
2669 os << player->getName() << " ";
2672 std::string name = player->getName();
2673 actionstream << name << " "
2674 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2675 << " List of players: " << os.str() << std::endl;
2677 m_admin_chat->outgoing_queue.push_back(
2678 new ChatEventNick(CET_NICK_REMOVE, name));
2682 MutexAutoLock env_lock(m_env_mutex);
2683 m_clients.DeleteClient(peer_id);
2687 // Send leave chat message to all remaining clients
2688 if(message.length() != 0)
2689 SendChatMessage(PEER_ID_INEXISTENT,message);
2692 void Server::UpdateCrafting(RemotePlayer* player)
2694 DSTACK(FUNCTION_NAME);
2696 // Get a preview for crafting
2698 InventoryLocation loc;
2699 loc.setPlayer(player->getName());
2700 std::vector<ItemStack> output_replacements;
2701 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2702 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2703 (&player->inventory)->getList("craft"), loc);
2705 // Put the new preview in
2706 InventoryList *plist = player->inventory.getList("craftpreview");
2707 sanity_check(plist);
2708 sanity_check(plist->getSize() >= 1);
2709 plist->changeItem(0, preview);
2712 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2714 if (evt->type == CET_NICK_ADD) {
2715 // The terminal informed us of its nick choice
2716 m_admin_nick = ((ChatEventNick *)evt)->nick;
2717 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2718 errorstream << "You haven't set up an account." << std::endl
2719 << "Please log in using the client as '"
2720 << m_admin_nick << "' with a secure password." << std::endl
2721 << "Until then, you can't execute admin tasks via the console," << std::endl
2722 << "and everybody can claim the user account instead of you," << std::endl
2723 << "giving them full control over this server." << std::endl;
2726 assert(evt->type == CET_CHAT);
2727 handleAdminChat((ChatEventChat *)evt);
2731 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2732 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2734 // If something goes wrong, this player is to blame
2735 RollbackScopeActor rollback_scope(m_rollback,
2736 std::string("player:") + name);
2740 // Whether to send line to the player that sent the message, or to all players
2741 bool broadcast_line = true;
2744 bool ate = m_script->on_chat_message(name,
2745 wide_to_utf8(wmessage));
2746 // If script ate the message, don't proceed
2751 switch (player->canSendChatMessage()) {
2752 case RPLAYER_CHATRESULT_FLOODING: {
2753 std::wstringstream ws;
2754 ws << L"You cannot send more messages. You are limited to "
2755 << g_settings->getFloat("chat_message_limit_per_10sec")
2756 << L" messages per 10 seconds.";
2759 case RPLAYER_CHATRESULT_KICK:
2760 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2762 case RPLAYER_CHATRESULT_OK: break;
2763 default: FATAL_ERROR("Unhandled chat filtering result found.");
2767 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2768 return L"Your message exceed the maximum chat message limit set on the server. "
2769 L"It was refused. Send a shorter message";
2772 // Commands are implemented in Lua, so only catch invalid
2773 // commands that were not "eaten" and send an error back
2774 if (wmessage[0] == L'/') {
2775 std::wstring wcmd = wmessage.substr(1);
2776 broadcast_line = false;
2777 if (wcmd.length() == 0)
2778 line += L"-!- Empty command";
2780 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2782 if (check_shout_priv && !checkPriv(name, "shout")) {
2783 line += L"-!- You don't have permission to shout.";
2784 broadcast_line = false;
2794 Tell calling method to send the message to sender
2796 if (!broadcast_line) {
2800 Send the message to others
2802 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2804 std::vector<u16> clients = m_clients.getClientIDs();
2806 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2807 for (u16 i = 0; i < clients.size(); i++) {
2808 u16 cid = clients[i];
2809 if (cid != peer_id_to_avoid_sending)
2810 SendChatMessage(cid, line);
2816 void Server::handleAdminChat(const ChatEventChat *evt)
2818 std::string name = evt->nick;
2819 std::wstring wname = utf8_to_wide(name);
2820 std::wstring wmessage = evt->evt_msg;
2822 std::wstring answer = handleChat(name, wname, wmessage);
2824 // If asked to send answer to sender
2825 if (!answer.empty()) {
2826 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2830 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2832 RemoteClient *client = getClientNoEx(peer_id,state_min);
2834 throw ClientNotFoundException("Client not found");
2838 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2840 return m_clients.getClientNoEx(peer_id, state_min);
2843 std::string Server::getPlayerName(u16 peer_id)
2845 Player *player = m_env->getPlayer(peer_id);
2847 return "[id="+itos(peer_id)+"]";
2848 return player->getName();
2851 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2853 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(peer_id));
2856 return player->getPlayerSAO();
2859 std::wstring Server::getStatusString()
2861 std::wostringstream os(std::ios_base::binary);
2864 os<<L"version="<<narrow_to_wide(g_version_string);
2866 os<<L", uptime="<<m_uptime.get();
2868 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2869 // Information about clients
2872 std::vector<u16> clients = m_clients.getClientIDs();
2873 for(std::vector<u16>::iterator i = clients.begin();
2874 i != clients.end(); ++i) {
2876 Player *player = m_env->getPlayer(*i);
2877 // Get name of player
2878 std::wstring name = L"unknown";
2880 name = narrow_to_wide(player->getName());
2881 // Add name to information string
2889 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2890 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2891 if(g_settings->get("motd") != "")
2892 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2896 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2898 std::set<std::string> privs;
2899 m_script->getAuth(name, NULL, &privs);
2903 bool Server::checkPriv(const std::string &name, const std::string &priv)
2905 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2906 return (privs.count(priv) != 0);
2909 void Server::reportPrivsModified(const std::string &name)
2912 std::vector<u16> clients = m_clients.getClientIDs();
2913 for(std::vector<u16>::iterator i = clients.begin();
2914 i != clients.end(); ++i) {
2915 Player *player = m_env->getPlayer(*i);
2916 reportPrivsModified(player->getName());
2919 RemotePlayer *player =
2920 dynamic_cast<RemotePlayer *>(m_env->getPlayer(name.c_str()));
2923 SendPlayerPrivileges(player->peer_id);
2924 PlayerSAO *sao = player->getPlayerSAO();
2927 sao->updatePrivileges(
2928 getPlayerEffectivePrivs(name),
2933 void Server::reportInventoryFormspecModified(const std::string &name)
2935 Player *player = m_env->getPlayer(name.c_str());
2938 SendPlayerInventoryFormspec(player->peer_id);
2941 void Server::setIpBanned(const std::string &ip, const std::string &name)
2943 m_banmanager->add(ip, name);
2946 void Server::unsetIpBanned(const std::string &ip_or_name)
2948 m_banmanager->remove(ip_or_name);
2951 std::string Server::getBanDescription(const std::string &ip_or_name)
2953 return m_banmanager->getBanDescription(ip_or_name);
2956 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2958 // m_env will be NULL if the server is initializing
2962 if (m_admin_nick == name && !m_admin_nick.empty()) {
2963 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2966 Player *player = m_env->getPlayer(name);
2971 if (player->peer_id == PEER_ID_INEXISTENT)
2974 SendChatMessage(player->peer_id, msg);
2977 bool Server::showFormspec(const char *playername, const std::string &formspec,
2978 const std::string &formname)
2980 // m_env will be NULL if the server is initializing
2984 Player *player = m_env->getPlayer(playername);
2988 SendShowFormspecMessage(player->peer_id, formspec, formname);
2992 u32 Server::hudAdd(Player *player, HudElement *form)
2997 u32 id = player->addHud(form);
2999 SendHUDAdd(player->peer_id, id, form);
3004 bool Server::hudRemove(Player *player, u32 id) {
3008 HudElement* todel = player->removeHud(id);
3015 SendHUDRemove(player->peer_id, id);
3019 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3024 SendHUDChange(player->peer_id, id, stat, data);
3028 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3033 SendHUDSetFlags(player->peer_id, flags, mask);
3034 player->hud_flags &= ~mask;
3035 player->hud_flags |= flags;
3037 PlayerSAO* playersao = player->getPlayerSAO();
3039 if (playersao == NULL)
3042 m_script->player_event(playersao, "hud_changed");
3046 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3051 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3054 player->setHotbarItemcount(hotbar_itemcount);
3055 std::ostringstream os(std::ios::binary);
3056 writeS32(os, hotbar_itemcount);
3057 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3061 void Server::hudSetHotbarImage(Player *player, std::string name)
3066 player->setHotbarImage(name);
3067 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3070 std::string Server::hudGetHotbarImage(Player *player)
3074 return player->getHotbarImage();
3077 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3082 player->setHotbarSelectedImage(name);
3083 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3086 std::string Server::hudGetHotbarSelectedImage(Player *player)
3091 return player->getHotbarSelectedImage();
3094 bool Server::setLocalPlayerAnimations(Player *player,
3095 v2s32 animation_frames[4], f32 frame_speed)
3100 player->setLocalAnimations(animation_frames, frame_speed);
3101 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3105 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3110 player->eye_offset_first = first;
3111 player->eye_offset_third = third;
3112 SendEyeOffset(player->peer_id, first, third);
3116 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3117 const std::string &type, const std::vector<std::string> ¶ms)
3122 player->setSky(bgcolor, type, params);
3123 SendSetSky(player->peer_id, bgcolor, type, params);
3127 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3133 player->overrideDayNightRatio(do_override, ratio);
3134 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3138 void Server::notifyPlayers(const std::wstring &msg)
3140 SendChatMessage(PEER_ID_INEXISTENT,msg);
3143 void Server::spawnParticle(const std::string &playername, v3f pos,
3144 v3f velocity, v3f acceleration,
3145 float expirationtime, float size, bool
3146 collisiondetection, bool collision_removal,
3147 bool vertical, const std::string &texture)
3149 // m_env will be NULL if the server is initializing
3153 u16 peer_id = PEER_ID_INEXISTENT;
3154 if (playername != "") {
3155 Player* player = m_env->getPlayer(playername.c_str());
3158 peer_id = player->peer_id;
3161 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3162 expirationtime, size, collisiondetection,
3163 collision_removal, vertical, texture);
3166 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3167 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3168 float minexptime, float maxexptime, float minsize, float maxsize,
3169 bool collisiondetection, bool collision_removal,
3170 bool vertical, const std::string &texture,
3171 const std::string &playername)
3173 // m_env will be NULL if the server is initializing
3177 u16 peer_id = PEER_ID_INEXISTENT;
3178 if (playername != "") {
3179 Player* player = m_env->getPlayer(playername.c_str());
3182 peer_id = player->peer_id;
3185 u32 id = m_env->addParticleSpawner(spawntime);
3186 SendAddParticleSpawner(peer_id, amount, spawntime,
3187 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3188 minexptime, maxexptime, minsize, maxsize,
3189 collisiondetection, collision_removal, vertical, texture, id);
3194 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3196 // m_env will be NULL if the server is initializing
3198 throw ServerError("Can't delete particle spawners during initialisation!");
3200 u16 peer_id = PEER_ID_INEXISTENT;
3201 if (playername != "") {
3202 Player* player = m_env->getPlayer(playername.c_str());
3205 peer_id = player->peer_id;
3208 m_env->deleteParticleSpawner(id);
3209 SendDeleteParticleSpawner(peer_id, id);
3212 Inventory* Server::createDetachedInventory(const std::string &name)
3214 if(m_detached_inventories.count(name) > 0){
3215 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3216 delete m_detached_inventories[name];
3218 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3220 Inventory *inv = new Inventory(m_itemdef);
3222 m_detached_inventories[name] = inv;
3223 //TODO find a better way to do this
3224 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3228 // actions: time-reversed list
3229 // Return value: success/failure
3230 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3231 std::list<std::string> *log)
3233 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3234 ServerMap *map = (ServerMap*)(&m_env->getMap());
3236 // Fail if no actions to handle
3237 if(actions.empty()){
3238 log->push_back("Nothing to do.");
3245 for(std::list<RollbackAction>::const_iterator
3246 i = actions.begin();
3247 i != actions.end(); ++i)
3249 const RollbackAction &action = *i;
3251 bool success = action.applyRevert(map, this, this);
3254 std::ostringstream os;
3255 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3256 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3258 log->push_back(os.str());
3260 std::ostringstream os;
3261 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3262 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3264 log->push_back(os.str());
3268 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3269 <<" failed"<<std::endl;
3271 // Call it done if less than half failed
3272 return num_failed <= num_tried/2;
3275 // IGameDef interface
3277 IItemDefManager *Server::getItemDefManager()
3282 INodeDefManager *Server::getNodeDefManager()
3287 ICraftDefManager *Server::getCraftDefManager()
3291 ITextureSource *Server::getTextureSource()
3295 IShaderSource *Server::getShaderSource()
3299 scene::ISceneManager *Server::getSceneManager()
3304 u16 Server::allocateUnknownNodeId(const std::string &name)
3306 return m_nodedef->allocateDummy(name);
3309 ISoundManager *Server::getSoundManager()
3311 return &dummySoundManager;
3314 MtEventManager *Server::getEventManager()
3319 IWritableItemDefManager *Server::getWritableItemDefManager()
3324 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3329 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3334 const ModSpec *Server::getModSpec(const std::string &modname) const
3336 std::vector<ModSpec>::const_iterator it;
3337 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3338 const ModSpec &mod = *it;
3339 if (mod.name == modname)
3345 void Server::getModNames(std::vector<std::string> &modlist)
3347 std::vector<ModSpec>::iterator it;
3348 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3349 modlist.push_back(it->name);
3352 std::string Server::getBuiltinLuaPath()
3354 return porting::path_share + DIR_DELIM + "builtin";
3357 v3f Server::findSpawnPos()
3359 ServerMap &map = m_env->getServerMap();
3361 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3362 return nodeposf * BS;
3365 bool is_good = false;
3367 // Try to find a good place a few times
3368 for(s32 i = 0; i < 4000 && !is_good; i++) {
3370 // We're going to try to throw the player to this position
3371 v2s16 nodepos2d = v2s16(
3372 -range + (myrand() % (range * 2)),
3373 -range + (myrand() % (range * 2)));
3375 // Get spawn level at point
3376 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3377 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3378 // the mapgen to signify an unsuitable spawn position
3379 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3382 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3385 for (s32 i = 0; i < 10; i++) {
3386 v3s16 blockpos = getNodeBlockPos(nodepos);
3387 map.emergeBlock(blockpos, true);
3388 content_t c = map.getNodeNoEx(nodepos).getContent();
3389 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3391 if (air_count >= 2) {
3392 nodeposf = intToFloat(nodepos, BS);
3393 // Don't spawn the player outside map boundaries
3394 if (objectpos_over_limit(nodeposf))
3407 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3409 bool newplayer = false;
3412 Try to get an existing player
3414 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3416 // If player is already connected, cancel
3417 if(player != NULL && player->peer_id != 0)
3419 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3424 If player with the wanted peer_id already exists, cancel.
3426 if(m_env->getPlayer(peer_id) != NULL)
3428 infostream<<"emergePlayer(): Player with wrong name but same"
3429 " peer_id already exists"<<std::endl;
3433 // Load player if it isn't already loaded
3435 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3438 // Create player if it doesn't exist
3441 player = new RemotePlayer(this, name);
3442 // Set player position
3443 infostream<<"Server: Finding spawn place for player \""
3444 <<name<<"\""<<std::endl;
3445 v3f pos = findSpawnPos();
3446 player->setPosition(pos);
3448 // Make sure the player is saved
3449 player->setModified(true);
3451 // Add player to environment
3452 m_env->addPlayer(player);
3454 // If the player exists, ensure that they respawn inside legal bounds
3455 // This fixes an assert crash when the player can't be added
3456 // to the environment
3457 if (objectpos_over_limit(player->getPosition())) {
3458 actionstream << "Respawn position for player \""
3459 << name << "\" outside limits, resetting" << std::endl;
3460 v3f pos = findSpawnPos();
3461 player->setPosition(pos);
3465 // Create a new player active object
3466 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3467 getPlayerEffectivePrivs(player->getName()),
3470 player->protocol_version = proto_version;
3472 /* Clean up old HUD elements from previous sessions */
3475 /* Add object to environment */
3476 m_env->addActiveObject(playersao);
3480 m_script->on_newplayer(playersao);
3486 void dedicated_server_loop(Server &server, bool &kill)
3488 DSTACK(FUNCTION_NAME);
3490 verbosestream<<"dedicated_server_loop()"<<std::endl;
3492 IntervalLimiter m_profiler_interval;
3494 static const float steplen = g_settings->getFloat("dedicated_server_step");
3495 static const float profiler_print_interval =
3496 g_settings->getFloat("profiler_print_interval");
3499 // This is kind of a hack but can be done like this
3500 // because server.step() is very light
3502 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3503 sleep_ms((int)(steplen*1000.0));
3505 server.step(steplen);
3507 if(server.getShutdownRequested() || kill)
3509 infostream<<"Dedicated server quitting"<<std::endl;
3511 if(g_settings->getBool("server_announce"))
3512 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3520 if (profiler_print_interval != 0) {
3521 if(m_profiler_interval.step(steplen, profiler_print_interval))
3523 infostream<<"Profiler:"<<std::endl;
3524 g_profiler->print(infostream);
3525 g_profiler->clear();