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 // Load mapgen params from Settings
270 m_emerge->loadMapgenParams();
272 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
273 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
275 // Initialize scripting
276 infostream<<"Server: Initializing Lua"<<std::endl;
278 m_script = new GameScripting(this);
280 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
282 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
285 infostream << "Server: Loading mods: ";
286 for(std::vector<ModSpec>::iterator i = m_mods.begin();
287 i != m_mods.end(); ++i) {
288 const ModSpec &mod = *i;
289 infostream << mod.name << " ";
291 infostream << std::endl;
292 // Load and run "mod" scripts
293 for (std::vector<ModSpec>::iterator it = m_mods.begin();
294 it != m_mods.end(); ++it) {
295 const ModSpec &mod = *it;
296 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
297 throw ModError("Error loading mod \"" + mod.name +
298 "\": Mod name does not follow naming conventions: "
299 "Only chararacters [a-z0-9_] are allowed.");
301 std::string script_path = mod.path + DIR_DELIM + "init.lua";
302 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
303 << script_path << "\"]" << std::endl;
304 m_script->loadMod(script_path, mod.name);
307 // Read Textures and calculate sha1 sums
310 // Apply item aliases in the node definition manager
311 m_nodedef->updateAliases(m_itemdef);
313 // Apply texture overrides from texturepack/override.txt
314 std::string texture_path = g_settings->get("texture_path");
315 if (texture_path != "" && fs::IsDir(texture_path))
316 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
318 m_nodedef->setNodeRegistrationStatus(true);
320 // Perform pending node name resolutions
321 m_nodedef->runNodeResolveCallbacks();
323 // unmap node names for connected nodeboxes
324 m_nodedef->mapNodeboxConnections();
326 // init the recipe hashes to speed up crafting
327 m_craftdef->initHashes(this);
329 // Initialize Environment
330 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
332 m_clients.setEnv(m_env);
334 // Initialize mapgens
335 m_emerge->initMapgens();
337 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
338 if (m_enable_rollback_recording) {
339 // Create rollback manager
340 m_rollback = new RollbackManager(m_path_world, this);
343 // Give environment reference to scripting api
344 m_script->initializeEnvironment(m_env);
346 // Register us to receive map edit events
347 servermap->addEventReceiver(this);
349 // If file exists, load environment metadata
350 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
351 infostream << "Server: Loading environment metadata" << std::endl;
354 m_env->loadDefaultMeta();
357 // Add some test ActiveBlockModifiers to environment
358 add_legacy_abms(m_env, m_nodedef);
360 m_liquid_transform_every = g_settings->getFloat("liquid_update");
365 infostream<<"Server destructing"<<std::endl;
367 // Send shutdown message
368 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
371 MutexAutoLock envlock(m_env_mutex);
373 // Execute script shutdown hooks
374 m_script->on_shutdown();
376 infostream << "Server: Saving players" << std::endl;
377 m_env->saveLoadedPlayers();
379 infostream << "Server: Kicking players" << std::endl;
380 std::string kick_msg;
381 bool reconnect = false;
382 if (getShutdownRequested()) {
383 reconnect = m_shutdown_ask_reconnect;
384 kick_msg = m_shutdown_msg;
386 if (kick_msg == "") {
387 kick_msg = g_settings->get("kick_msg_shutdown");
389 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
390 kick_msg, reconnect);
392 infostream << "Server: Saving environment metadata" << std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
407 // N.B. the EmergeManager should be deleted after the Environment since Map
408 // depends on EmergeManager to write its current params to the map meta
417 // Deinitialize scripting
418 infostream<<"Server: Deinitializing scripting"<<std::endl;
421 // Delete detached inventories
422 for (std::map<std::string, Inventory*>::iterator
423 i = m_detached_inventories.begin();
424 i != m_detached_inventories.end(); ++i) {
429 void Server::start(Address bind_addr)
431 DSTACK(FUNCTION_NAME);
433 m_bind_addr = bind_addr;
435 infostream<<"Starting server on "
436 << bind_addr.serializeString() <<"..."<<std::endl;
438 // Stop thread if already running
441 // Initialize connection
442 m_con.SetTimeoutMs(30);
443 m_con.Serve(bind_addr);
448 // ASCII art for the win!
450 <<" .__ __ __ "<<std::endl
451 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
452 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
453 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
454 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
455 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
456 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
457 actionstream<<"Server for gameid=\""<<m_gamespec.id
458 <<"\" listening on "<<bind_addr.serializeString()<<":"
459 <<bind_addr.getPort() << "."<<std::endl;
464 DSTACK(FUNCTION_NAME);
466 infostream<<"Server: Stopping and waiting threads"<<std::endl;
468 // Stop threads (set run=false first so both start stopping)
470 //m_emergethread.setRun(false);
472 //m_emergethread.stop();
474 infostream<<"Server: Threads stopped"<<std::endl;
477 void Server::step(float dtime)
479 DSTACK(FUNCTION_NAME);
484 MutexAutoLock lock(m_step_dtime_mutex);
485 m_step_dtime += dtime;
487 // Throw if fatal error occurred in thread
488 std::string async_err = m_async_fatal_error.get();
489 if (!async_err.empty()) {
490 if (!m_simple_singleplayer_mode) {
491 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
492 g_settings->get("kick_msg_crash"),
493 g_settings->getBool("ask_reconnect_on_crash"));
495 throw ServerError(async_err);
499 void Server::AsyncRunStep(bool initial_step)
501 DSTACK(FUNCTION_NAME);
503 g_profiler->add("Server::AsyncRunStep (num)", 1);
507 MutexAutoLock lock1(m_step_dtime_mutex);
508 dtime = m_step_dtime;
512 // Send blocks to clients
516 if((dtime < 0.001) && (initial_step == false))
519 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
521 //infostream<<"Server steps "<<dtime<<std::endl;
522 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
525 MutexAutoLock lock1(m_step_dtime_mutex);
526 m_step_dtime -= dtime;
533 m_uptime.set(m_uptime.get() + dtime);
539 Update time of day and overall game time
541 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
544 Send to clients at constant intervals
547 m_time_of_day_send_timer -= dtime;
548 if(m_time_of_day_send_timer < 0.0) {
549 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
550 u16 time = m_env->getTimeOfDay();
551 float time_speed = g_settings->getFloat("time_speed");
552 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
556 MutexAutoLock lock(m_env_mutex);
557 // Figure out and report maximum lag to environment
558 float max_lag = m_env->getMaxLagEstimate();
559 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
561 if(dtime > 0.1 && dtime > max_lag * 2.0)
562 infostream<<"Server: Maximum lag peaked to "<<dtime
566 m_env->reportMaxLagEstimate(max_lag);
568 ScopeProfiler sp(g_profiler, "SEnv step");
569 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
573 static const float map_timer_and_unload_dtime = 2.92;
574 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
576 MutexAutoLock lock(m_env_mutex);
577 // Run Map's timers and unload unused data
578 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
579 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
580 g_settings->getFloat("server_unload_unused_data_timeout"),
585 Listen to the admin chat, if available
588 if (!m_admin_chat->command_queue.empty()) {
589 MutexAutoLock lock(m_env_mutex);
590 while (!m_admin_chat->command_queue.empty()) {
591 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
592 handleChatInterfaceEvent(evt);
596 m_admin_chat->outgoing_queue.push_back(
597 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
604 /* Transform liquids */
605 m_liquid_transform_timer += dtime;
606 if(m_liquid_transform_timer >= m_liquid_transform_every)
608 m_liquid_transform_timer -= m_liquid_transform_every;
610 MutexAutoLock lock(m_env_mutex);
612 ScopeProfiler sp(g_profiler, "Server: liquid transform");
614 std::map<v3s16, MapBlock*> modified_blocks;
615 m_env->getMap().transformLiquids(modified_blocks);
620 core::map<v3s16, MapBlock*> lighting_modified_blocks;
621 ServerMap &map = ((ServerMap&)m_env->getMap());
622 map.updateLighting(modified_blocks, lighting_modified_blocks);
624 // Add blocks modified by lighting to modified_blocks
625 for(core::map<v3s16, MapBlock*>::Iterator
626 i = lighting_modified_blocks.getIterator();
627 i.atEnd() == false; i++)
629 MapBlock *block = i.getNode()->getValue();
630 modified_blocks.insert(block->getPos(), block);
634 Set the modified blocks unsent for all the clients
636 if(!modified_blocks.empty())
638 SetBlocksNotSent(modified_blocks);
641 m_clients.step(dtime);
643 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
645 // send masterserver announce
647 float &counter = m_masterserver_timer;
648 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
649 g_settings->getBool("server_announce"))
651 ServerList::sendAnnounce(counter ? "update" : "start",
652 m_bind_addr.getPort(),
653 m_clients.getPlayerNames(),
655 m_env->getGameTime(),
658 m_emerge->params.mg_name,
667 Check added and deleted active objects
670 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
671 MutexAutoLock envlock(m_env_mutex);
674 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
675 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
677 // Radius inside which objects are active
678 static const s16 radius =
679 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
681 // Radius inside which players are active
682 static const bool is_transfer_limited =
683 g_settings->exists("unlimited_player_transfer_distance") &&
684 !g_settings->getBool("unlimited_player_transfer_distance");
685 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
686 s16 player_radius = player_transfer_dist;
687 if (player_radius == 0 && is_transfer_limited)
688 player_radius = radius;
690 for (std::map<u16, RemoteClient*>::iterator
692 i != clients.end(); ++i) {
693 RemoteClient *client = i->second;
695 // If definitions and textures have not been sent, don't
696 // send objects either
697 if (client->getState() < CS_DefinitionsSent)
700 Player *player = m_env->getPlayer(client->peer_id);
702 // This can happen if the client timeouts somehow
703 /*warningstream<<FUNCTION_NAME<<": Client "
705 <<" has no associated player"<<std::endl;*/
709 std::queue<u16> removed_objects;
710 std::queue<u16> added_objects;
711 m_env->getRemovedActiveObjects(player, radius, player_radius,
712 client->m_known_objects, removed_objects);
713 m_env->getAddedActiveObjects(player, radius, player_radius,
714 client->m_known_objects, added_objects);
716 // Ignore if nothing happened
717 if (removed_objects.empty() && added_objects.empty()) {
721 std::string data_buffer;
725 // Handle removed objects
726 writeU16((u8*)buf, removed_objects.size());
727 data_buffer.append(buf, 2);
728 while (!removed_objects.empty()) {
730 u16 id = removed_objects.front();
731 ServerActiveObject* obj = m_env->getActiveObject(id);
733 // Add to data buffer for sending
734 writeU16((u8*)buf, id);
735 data_buffer.append(buf, 2);
737 // Remove from known objects
738 client->m_known_objects.erase(id);
740 if(obj && obj->m_known_by_count > 0)
741 obj->m_known_by_count--;
742 removed_objects.pop();
745 // Handle added objects
746 writeU16((u8*)buf, added_objects.size());
747 data_buffer.append(buf, 2);
748 while (!added_objects.empty()) {
750 u16 id = added_objects.front();
751 ServerActiveObject* obj = m_env->getActiveObject(id);
754 u8 type = ACTIVEOBJECT_TYPE_INVALID;
756 warningstream<<FUNCTION_NAME
757 <<": NULL object"<<std::endl;
759 type = obj->getSendType();
761 // Add to data buffer for sending
762 writeU16((u8*)buf, id);
763 data_buffer.append(buf, 2);
764 writeU8((u8*)buf, type);
765 data_buffer.append(buf, 1);
768 data_buffer.append(serializeLongString(
769 obj->getClientInitializationData(client->net_proto_version)));
771 data_buffer.append(serializeLongString(""));
773 // Add to known objects
774 client->m_known_objects.insert(id);
777 obj->m_known_by_count++;
782 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
783 verbosestream << "Server: Sent object remove/add: "
784 << removed_objects.size() << " removed, "
785 << added_objects.size() << " added, "
786 << "packet size is " << pktSize << std::endl;
795 MutexAutoLock envlock(m_env_mutex);
796 ScopeProfiler sp(g_profiler, "Server: sending object messages");
799 // Value = data sent by object
800 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
802 // Get active object messages from environment
804 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
808 std::vector<ActiveObjectMessage>* message_list = NULL;
809 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
810 n = buffered_messages.find(aom.id);
811 if (n == buffered_messages.end()) {
812 message_list = new std::vector<ActiveObjectMessage>;
813 buffered_messages[aom.id] = message_list;
816 message_list = n->second;
818 message_list->push_back(aom);
822 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
823 // Route data to every client
824 for (std::map<u16, RemoteClient*>::iterator
826 i != clients.end(); ++i) {
827 RemoteClient *client = i->second;
828 std::string reliable_data;
829 std::string unreliable_data;
830 // Go through all objects in message buffer
831 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
832 j = buffered_messages.begin();
833 j != buffered_messages.end(); ++j) {
834 // If object is not known by client, skip it
836 if (client->m_known_objects.find(id) == client->m_known_objects.end())
839 // Get message list of object
840 std::vector<ActiveObjectMessage>* list = j->second;
841 // Go through every message
842 for (std::vector<ActiveObjectMessage>::iterator
843 k = list->begin(); k != list->end(); ++k) {
844 // Compose the full new data with header
845 ActiveObjectMessage aom = *k;
846 std::string new_data;
849 writeU16((u8*)&buf[0], aom.id);
850 new_data.append(buf, 2);
852 new_data += serializeString(aom.datastring);
853 // Add data to buffer
855 reliable_data += new_data;
857 unreliable_data += new_data;
861 reliable_data and unreliable_data are now ready.
864 if(reliable_data.size() > 0) {
865 SendActiveObjectMessages(client->peer_id, reliable_data);
868 if(unreliable_data.size() > 0) {
869 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
874 // Clear buffered_messages
875 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
876 i = buffered_messages.begin();
877 i != buffered_messages.end(); ++i) {
883 Send queued-for-sending map edit events.
886 // We will be accessing the environment
887 MutexAutoLock lock(m_env_mutex);
889 // Don't send too many at a time
892 // Single change sending is disabled if queue size is not small
893 bool disable_single_change_sending = false;
894 if(m_unsent_map_edit_queue.size() >= 4)
895 disable_single_change_sending = true;
897 int event_count = m_unsent_map_edit_queue.size();
899 // We'll log the amount of each
902 while(m_unsent_map_edit_queue.size() != 0)
904 MapEditEvent* event = m_unsent_map_edit_queue.front();
905 m_unsent_map_edit_queue.pop();
907 // Players far away from the change are stored here.
908 // Instead of sending the changes, MapBlocks are set not sent
910 std::vector<u16> far_players;
912 switch (event->type) {
915 prof.add("MEET_ADDNODE", 1);
916 sendAddNode(event->p, event->n, event->already_known_by_peer,
917 &far_players, disable_single_change_sending ? 5 : 30,
918 event->type == MEET_ADDNODE);
920 case MEET_REMOVENODE:
921 prof.add("MEET_REMOVENODE", 1);
922 sendRemoveNode(event->p, event->already_known_by_peer,
923 &far_players, disable_single_change_sending ? 5 : 30);
925 case MEET_BLOCK_NODE_METADATA_CHANGED:
926 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
927 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
928 setBlockNotSent(event->p);
931 infostream << "Server: MEET_OTHER" << std::endl;
932 prof.add("MEET_OTHER", 1);
933 for(std::set<v3s16>::iterator
934 i = event->modified_blocks.begin();
935 i != event->modified_blocks.end(); ++i) {
940 prof.add("unknown", 1);
941 warningstream << "Server: Unknown MapEditEvent "
942 << ((u32)event->type) << std::endl;
947 Set blocks not sent to far players
949 if(!far_players.empty()) {
950 // Convert list format to that wanted by SetBlocksNotSent
951 std::map<v3s16, MapBlock*> modified_blocks2;
952 for(std::set<v3s16>::iterator
953 i = event->modified_blocks.begin();
954 i != event->modified_blocks.end(); ++i) {
955 modified_blocks2[*i] =
956 m_env->getMap().getBlockNoCreateNoEx(*i);
959 // Set blocks not sent
960 for(std::vector<u16>::iterator
961 i = far_players.begin();
962 i != far_players.end(); ++i) {
963 if(RemoteClient *client = getClient(*i))
964 client->SetBlocksNotSent(modified_blocks2);
970 /*// Don't send too many at a time
972 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
976 if(event_count >= 5){
977 infostream<<"Server: MapEditEvents:"<<std::endl;
978 prof.print(infostream);
979 } else if(event_count != 0){
980 verbosestream<<"Server: MapEditEvents:"<<std::endl;
981 prof.print(verbosestream);
987 Trigger emergethread (it somehow gets to a non-triggered but
988 bysy state sometimes)
991 float &counter = m_emergethread_trigger_timer;
993 if (counter >= 2.0) {
996 m_emerge->startThreads();
1000 // Save map, players and auth stuff
1002 float &counter = m_savemap_timer;
1004 static const float save_interval =
1005 g_settings->getFloat("server_map_save_interval");
1006 if (counter >= save_interval) {
1008 MutexAutoLock lock(m_env_mutex);
1010 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1013 if (m_banmanager->isModified()) {
1014 m_banmanager->save();
1017 // Save changed parts of map
1018 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1021 m_env->saveLoadedPlayers();
1023 // Save environment metadata
1029 void Server::Receive()
1031 DSTACK(FUNCTION_NAME);
1032 SharedBuffer<u8> data;
1036 m_con.Receive(&pkt);
1037 peer_id = pkt.getPeerId();
1040 catch(con::InvalidIncomingDataException &e) {
1041 infostream<<"Server::Receive(): "
1042 "InvalidIncomingDataException: what()="
1043 <<e.what()<<std::endl;
1045 catch(SerializationError &e) {
1046 infostream<<"Server::Receive(): "
1047 "SerializationError: what()="
1048 <<e.what()<<std::endl;
1050 catch(ClientStateError &e) {
1051 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1052 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1053 L"Try reconnecting or updating your client");
1055 catch(con::PeerNotFoundException &e) {
1060 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1062 std::string playername = "";
1063 PlayerSAO *playersao = NULL;
1066 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1067 if (client != NULL) {
1068 playername = client->getName();
1069 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1071 } catch (std::exception &e) {
1077 RemotePlayer *player =
1078 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1080 // If failed, cancel
1081 if ((playersao == NULL) || (player == NULL)) {
1082 if (player && player->peer_id != 0) {
1083 actionstream << "Server: Failed to emerge player \"" << playername
1084 << "\" (player allocated to an another client)" << std::endl;
1085 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1086 L"name. If your client closed unexpectedly, try again in "
1089 errorstream << "Server: " << playername << ": Failed to emerge player"
1091 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1097 Send complete position information
1099 SendMovePlayer(peer_id);
1102 SendPlayerPrivileges(peer_id);
1104 // Send inventory formspec
1105 SendPlayerInventoryFormspec(peer_id);
1108 SendInventory(playersao);
1111 SendPlayerHPOrDie(playersao);
1114 SendPlayerBreath(peer_id);
1116 // Show death screen if necessary
1117 if(player->isDead())
1118 SendDeathscreen(peer_id, false, v3f(0,0,0));
1120 // Note things in chat if not in simple singleplayer mode
1121 if(!m_simple_singleplayer_mode) {
1122 // Send information about server to player in chat
1123 SendChatMessage(peer_id, getStatusString());
1125 // Send information about joining in chat
1127 std::string name = "unknown";
1128 Player *player = m_env->getPlayer(peer_id);
1130 name = player->getName();
1132 std::wstring message;
1134 message += narrow_to_wide(name);
1135 message += L" joined the game.";
1136 SendChatMessage(PEER_ID_INEXISTENT,message);
1138 m_admin_chat->outgoing_queue.push_back(
1139 new ChatEventNick(CET_NICK_ADD, name));
1142 Address addr = getPeerAddress(player->peer_id);
1143 std::string ip_str = addr.serializeString();
1144 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1149 std::vector<std::string> names = m_clients.getPlayerNames();
1151 actionstream<<player->getName() <<" joins game. List of players: ";
1153 for (std::vector<std::string>::iterator i = names.begin();
1154 i != names.end(); ++i) {
1155 actionstream << *i << " ";
1158 actionstream << player->getName() <<std::endl;
1163 inline void Server::handleCommand(NetworkPacket* pkt)
1165 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1166 (this->*opHandle.handler)(pkt);
1169 void Server::ProcessData(NetworkPacket *pkt)
1171 DSTACK(FUNCTION_NAME);
1172 // Environment is locked first.
1173 MutexAutoLock envlock(m_env_mutex);
1175 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1176 u32 peer_id = pkt->getPeerId();
1179 Address address = getPeerAddress(peer_id);
1180 std::string addr_s = address.serializeString();
1182 if(m_banmanager->isIpBanned(addr_s)) {
1183 std::string ban_name = m_banmanager->getBanName(addr_s);
1184 infostream << "Server: A banned client tried to connect from "
1185 << addr_s << "; banned name was "
1186 << ban_name << std::endl;
1187 // This actually doesn't seem to transfer to the client
1188 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1189 + utf8_to_wide(ban_name));
1193 catch(con::PeerNotFoundException &e) {
1195 * no peer for this packet found
1196 * most common reason is peer timeout, e.g. peer didn't
1197 * respond for some time, your server was overloaded or
1200 infostream << "Server::ProcessData(): Canceling: peer "
1201 << peer_id << " not found" << std::endl;
1206 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1208 // Command must be handled into ToServerCommandHandler
1209 if (command >= TOSERVER_NUM_MSG_TYPES) {
1210 infostream << "Server: Ignoring unknown command "
1211 << command << std::endl;
1215 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1220 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1222 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1223 errorstream << "Server::ProcessData(): Cancelling: Peer"
1224 " serialization format invalid or not initialized."
1225 " Skipping incoming command=" << command << std::endl;
1229 /* Handle commands related to client startup */
1230 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1235 if (m_clients.getClientState(peer_id) < CS_Active) {
1236 if (command == TOSERVER_PLAYERPOS) return;
1238 errorstream << "Got packet command: " << command << " for peer id "
1239 << peer_id << " but client isn't active yet. Dropping packet "
1245 } catch (SendFailedException &e) {
1246 errorstream << "Server::ProcessData(): SendFailedException: "
1247 << "what=" << e.what()
1249 } catch (PacketError &e) {
1250 actionstream << "Server::ProcessData(): PacketError: "
1251 << "what=" << e.what()
1256 void Server::setTimeOfDay(u32 time)
1258 m_env->setTimeOfDay(time);
1259 m_time_of_day_send_timer = 0;
1262 void Server::onMapEditEvent(MapEditEvent *event)
1264 if(m_ignore_map_edit_events)
1266 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1268 MapEditEvent *e = event->clone();
1269 m_unsent_map_edit_queue.push(e);
1272 Inventory* Server::getInventory(const InventoryLocation &loc)
1275 case InventoryLocation::UNDEFINED:
1276 case InventoryLocation::CURRENT_PLAYER:
1278 case InventoryLocation::PLAYER:
1280 Player *player = m_env->getPlayer(loc.name.c_str());
1283 PlayerSAO *playersao = player->getPlayerSAO();
1286 return playersao->getInventory();
1289 case InventoryLocation::NODEMETA:
1291 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1294 return meta->getInventory();
1297 case InventoryLocation::DETACHED:
1299 if(m_detached_inventories.count(loc.name) == 0)
1301 return m_detached_inventories[loc.name];
1305 sanity_check(false); // abort
1310 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1313 case InventoryLocation::UNDEFINED:
1315 case InventoryLocation::PLAYER:
1320 Player *player = m_env->getPlayer(loc.name.c_str());
1323 PlayerSAO *playersao = player->getPlayerSAO();
1327 SendInventory(playersao);
1330 case InventoryLocation::NODEMETA:
1332 v3s16 blockpos = getNodeBlockPos(loc.p);
1334 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1336 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1338 setBlockNotSent(blockpos);
1341 case InventoryLocation::DETACHED:
1343 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1347 sanity_check(false); // abort
1352 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1354 std::vector<u16> clients = m_clients.getClientIDs();
1356 // Set the modified blocks unsent for all the clients
1357 for (std::vector<u16>::iterator i = clients.begin();
1358 i != clients.end(); ++i) {
1359 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1360 client->SetBlocksNotSent(block);
1365 void Server::peerAdded(con::Peer *peer)
1367 DSTACK(FUNCTION_NAME);
1368 verbosestream<<"Server::peerAdded(): peer->id="
1369 <<peer->id<<std::endl;
1372 c.type = con::PEER_ADDED;
1373 c.peer_id = peer->id;
1375 m_peer_change_queue.push(c);
1378 void Server::deletingPeer(con::Peer *peer, bool timeout)
1380 DSTACK(FUNCTION_NAME);
1381 verbosestream<<"Server::deletingPeer(): peer->id="
1382 <<peer->id<<", timeout="<<timeout<<std::endl;
1384 m_clients.event(peer->id, CSE_Disconnect);
1386 c.type = con::PEER_REMOVED;
1387 c.peer_id = peer->id;
1388 c.timeout = timeout;
1389 m_peer_change_queue.push(c);
1392 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1394 *retval = m_con.getPeerStat(peer_id,type);
1395 if (*retval == -1) return false;
1399 bool Server::getClientInfo(
1408 std::string* vers_string
1411 *state = m_clients.getClientState(peer_id);
1413 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1415 if (client == NULL) {
1420 *uptime = client->uptime();
1421 *ser_vers = client->serialization_version;
1422 *prot_vers = client->net_proto_version;
1424 *major = client->getMajor();
1425 *minor = client->getMinor();
1426 *patch = client->getPatch();
1427 *vers_string = client->getPatch();
1434 void Server::handlePeerChanges()
1436 while(m_peer_change_queue.size() > 0)
1438 con::PeerChange c = m_peer_change_queue.front();
1439 m_peer_change_queue.pop();
1441 verbosestream<<"Server: Handling peer change: "
1442 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1447 case con::PEER_ADDED:
1448 m_clients.CreateClient(c.peer_id);
1451 case con::PEER_REMOVED:
1452 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1456 FATAL_ERROR("Invalid peer change event received!");
1462 void Server::printToConsoleOnly(const std::string &text)
1465 m_admin_chat->outgoing_queue.push_back(
1466 new ChatEventChat("", utf8_to_wide(text)));
1468 std::cout << text << std::endl;
1472 void Server::Send(NetworkPacket* pkt)
1474 m_clients.send(pkt->getPeerId(),
1475 clientCommandFactoryTable[pkt->getCommand()].channel,
1477 clientCommandFactoryTable[pkt->getCommand()].reliable);
1480 void Server::SendMovement(u16 peer_id)
1482 DSTACK(FUNCTION_NAME);
1483 std::ostringstream os(std::ios_base::binary);
1485 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1487 pkt << g_settings->getFloat("movement_acceleration_default");
1488 pkt << g_settings->getFloat("movement_acceleration_air");
1489 pkt << g_settings->getFloat("movement_acceleration_fast");
1490 pkt << g_settings->getFloat("movement_speed_walk");
1491 pkt << g_settings->getFloat("movement_speed_crouch");
1492 pkt << g_settings->getFloat("movement_speed_fast");
1493 pkt << g_settings->getFloat("movement_speed_climb");
1494 pkt << g_settings->getFloat("movement_speed_jump");
1495 pkt << g_settings->getFloat("movement_liquid_fluidity");
1496 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1497 pkt << g_settings->getFloat("movement_liquid_sink");
1498 pkt << g_settings->getFloat("movement_gravity");
1503 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1505 if (!g_settings->getBool("enable_damage"))
1508 u16 peer_id = playersao->getPeerID();
1509 bool is_alive = playersao->getHP() > 0;
1512 SendPlayerHP(peer_id);
1517 void Server::SendHP(u16 peer_id, u8 hp)
1519 DSTACK(FUNCTION_NAME);
1521 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1526 void Server::SendBreath(u16 peer_id, u16 breath)
1528 DSTACK(FUNCTION_NAME);
1530 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1531 pkt << (u16) breath;
1535 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1536 const std::string &custom_reason, bool reconnect)
1538 assert(reason < SERVER_ACCESSDENIED_MAX);
1540 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1542 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1543 pkt << custom_reason;
1544 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1545 reason == SERVER_ACCESSDENIED_CRASH)
1546 pkt << custom_reason << (u8)reconnect;
1550 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1559 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1560 v3f camera_point_target)
1562 DSTACK(FUNCTION_NAME);
1564 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1565 pkt << set_camera_point_target << camera_point_target;
1569 void Server::SendItemDef(u16 peer_id,
1570 IItemDefManager *itemdef, u16 protocol_version)
1572 DSTACK(FUNCTION_NAME);
1574 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1578 u32 length of the next item
1579 zlib-compressed serialized ItemDefManager
1581 std::ostringstream tmp_os(std::ios::binary);
1582 itemdef->serialize(tmp_os, protocol_version);
1583 std::ostringstream tmp_os2(std::ios::binary);
1584 compressZlib(tmp_os.str(), tmp_os2);
1585 pkt.putLongString(tmp_os2.str());
1588 verbosestream << "Server: Sending item definitions to id(" << peer_id
1589 << "): size=" << pkt.getSize() << std::endl;
1594 void Server::SendNodeDef(u16 peer_id,
1595 INodeDefManager *nodedef, u16 protocol_version)
1597 DSTACK(FUNCTION_NAME);
1599 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1603 u32 length of the next item
1604 zlib-compressed serialized NodeDefManager
1606 std::ostringstream tmp_os(std::ios::binary);
1607 nodedef->serialize(tmp_os, protocol_version);
1608 std::ostringstream tmp_os2(std::ios::binary);
1609 compressZlib(tmp_os.str(), tmp_os2);
1611 pkt.putLongString(tmp_os2.str());
1614 verbosestream << "Server: Sending node definitions to id(" << peer_id
1615 << "): size=" << pkt.getSize() << std::endl;
1621 Non-static send methods
1624 void Server::SendInventory(PlayerSAO* playerSAO)
1626 DSTACK(FUNCTION_NAME);
1628 UpdateCrafting(playerSAO->getPlayer());
1634 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1636 std::ostringstream os;
1637 playerSAO->getInventory()->serialize(os);
1639 std::string s = os.str();
1641 pkt.putRawString(s.c_str(), s.size());
1645 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1647 DSTACK(FUNCTION_NAME);
1649 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1652 if (peer_id != PEER_ID_INEXISTENT) {
1656 m_clients.sendToAll(0, &pkt, true);
1660 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1661 const std::string &formname)
1663 DSTACK(FUNCTION_NAME);
1665 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1667 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1673 // Spawns a particle on peer with peer_id
1674 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1675 float expirationtime, float size, bool collisiondetection,
1676 bool vertical, std::string texture)
1678 DSTACK(FUNCTION_NAME);
1680 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1682 pkt << pos << velocity << acceleration << expirationtime
1683 << size << collisiondetection;
1684 pkt.putLongString(texture);
1687 if (peer_id != PEER_ID_INEXISTENT) {
1691 m_clients.sendToAll(0, &pkt, true);
1695 // Adds a ParticleSpawner on peer with peer_id
1696 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1697 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1698 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1700 DSTACK(FUNCTION_NAME);
1702 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1704 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1705 << minacc << maxacc << minexptime << maxexptime << minsize
1706 << maxsize << collisiondetection;
1708 pkt.putLongString(texture);
1710 pkt << id << vertical;
1712 if (peer_id != PEER_ID_INEXISTENT) {
1716 m_clients.sendToAll(0, &pkt, true);
1720 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1722 DSTACK(FUNCTION_NAME);
1724 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1726 // Ugly error in this packet
1729 if (peer_id != PEER_ID_INEXISTENT) {
1733 m_clients.sendToAll(0, &pkt, true);
1738 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1740 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1742 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1743 << form->text << form->number << form->item << form->dir
1744 << form->align << form->offset << form->world_pos << form->size;
1749 void Server::SendHUDRemove(u16 peer_id, u32 id)
1751 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1756 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1758 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1759 pkt << id << (u8) stat;
1763 case HUD_STAT_SCALE:
1764 case HUD_STAT_ALIGN:
1765 case HUD_STAT_OFFSET:
1766 pkt << *(v2f *) value;
1770 pkt << *(std::string *) value;
1772 case HUD_STAT_WORLD_POS:
1773 pkt << *(v3f *) value;
1776 pkt << *(v2s32 *) value;
1778 case HUD_STAT_NUMBER:
1782 pkt << *(u32 *) value;
1789 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1791 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1793 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1795 pkt << flags << mask;
1800 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1802 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1803 pkt << param << value;
1807 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1808 const std::string &type, const std::vector<std::string> ¶ms)
1810 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1811 pkt << bgcolor << type << (u16) params.size();
1813 for(size_t i=0; i<params.size(); i++)
1819 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1822 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1825 pkt << do_override << (u16) (ratio * 65535);
1830 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1832 DSTACK(FUNCTION_NAME);
1834 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1835 pkt << time << time_speed;
1837 if (peer_id == PEER_ID_INEXISTENT) {
1838 m_clients.sendToAll(0, &pkt, true);
1845 void Server::SendPlayerHP(u16 peer_id)
1847 DSTACK(FUNCTION_NAME);
1848 PlayerSAO *playersao = getPlayerSAO(peer_id);
1849 // In some rare case if the player is disconnected
1850 // while Lua call l_punch, for example, this can be NULL
1854 SendHP(peer_id, playersao->getHP());
1855 m_script->player_event(playersao,"health_changed");
1857 // Send to other clients
1858 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1859 ActiveObjectMessage aom(playersao->getId(), true, str);
1860 playersao->m_messages_out.push(aom);
1863 void Server::SendPlayerBreath(u16 peer_id)
1865 DSTACK(FUNCTION_NAME);
1866 PlayerSAO *playersao = getPlayerSAO(peer_id);
1869 m_script->player_event(playersao, "breath_changed");
1870 SendBreath(peer_id, playersao->getBreath());
1873 void Server::SendMovePlayer(u16 peer_id)
1875 DSTACK(FUNCTION_NAME);
1876 Player *player = m_env->getPlayer(peer_id);
1879 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1880 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1883 v3f pos = player->getPosition();
1884 f32 pitch = player->getPitch();
1885 f32 yaw = player->getYaw();
1886 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1887 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1888 << " pitch=" << pitch
1896 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1898 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1901 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1902 << animation_frames[3] << animation_speed;
1907 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1909 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1910 pkt << first << third;
1913 void Server::SendPlayerPrivileges(u16 peer_id)
1915 Player *player = m_env->getPlayer(peer_id);
1917 if(player->peer_id == PEER_ID_INEXISTENT)
1920 std::set<std::string> privs;
1921 m_script->getAuth(player->getName(), NULL, &privs);
1923 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1924 pkt << (u16) privs.size();
1926 for(std::set<std::string>::const_iterator i = privs.begin();
1927 i != privs.end(); ++i) {
1934 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1936 Player *player = m_env->getPlayer(peer_id);
1938 if(player->peer_id == PEER_ID_INEXISTENT)
1941 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1942 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1946 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1948 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1949 pkt.putRawString(datas.c_str(), datas.size());
1951 return pkt.getSize();
1954 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1956 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1957 datas.size(), peer_id);
1959 pkt.putRawString(datas.c_str(), datas.size());
1961 m_clients.send(pkt.getPeerId(),
1962 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1967 s32 Server::playSound(const SimpleSoundSpec &spec,
1968 const ServerSoundParams ¶ms)
1970 // Find out initial position of sound
1971 bool pos_exists = false;
1972 v3f pos = params.getPos(m_env, &pos_exists);
1973 // If position is not found while it should be, cancel sound
1974 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1977 // Filter destination clients
1978 std::vector<u16> dst_clients;
1979 if(params.to_player != "")
1981 Player *player = m_env->getPlayer(params.to_player.c_str());
1983 infostream<<"Server::playSound: Player \""<<params.to_player
1984 <<"\" not found"<<std::endl;
1987 if(player->peer_id == PEER_ID_INEXISTENT){
1988 infostream<<"Server::playSound: Player \""<<params.to_player
1989 <<"\" not connected"<<std::endl;
1992 dst_clients.push_back(player->peer_id);
1995 std::vector<u16> clients = m_clients.getClientIDs();
1997 for(std::vector<u16>::iterator
1998 i = clients.begin(); i != clients.end(); ++i) {
1999 Player *player = m_env->getPlayer(*i);
2004 if(player->getPosition().getDistanceFrom(pos) >
2005 params.max_hear_distance)
2008 dst_clients.push_back(*i);
2012 if(dst_clients.empty())
2016 s32 id = m_next_sound_id++;
2017 // The sound will exist as a reference in m_playing_sounds
2018 m_playing_sounds[id] = ServerPlayingSound();
2019 ServerPlayingSound &psound = m_playing_sounds[id];
2020 psound.params = params;
2022 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2023 pkt << id << spec.name << (float) (spec.gain * params.gain)
2024 << (u8) params.type << pos << params.object << params.loop;
2026 for(std::vector<u16>::iterator i = dst_clients.begin();
2027 i != dst_clients.end(); ++i) {
2028 psound.clients.insert(*i);
2029 m_clients.send(*i, 0, &pkt, true);
2033 void Server::stopSound(s32 handle)
2035 // Get sound reference
2036 std::map<s32, ServerPlayingSound>::iterator i =
2037 m_playing_sounds.find(handle);
2038 if(i == m_playing_sounds.end())
2040 ServerPlayingSound &psound = i->second;
2042 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2045 for(std::set<u16>::iterator i = psound.clients.begin();
2046 i != psound.clients.end(); ++i) {
2048 m_clients.send(*i, 0, &pkt, true);
2050 // Remove sound reference
2051 m_playing_sounds.erase(i);
2054 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2055 std::vector<u16> *far_players, float far_d_nodes)
2057 float maxd = far_d_nodes*BS;
2058 v3f p_f = intToFloat(p, BS);
2060 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2063 std::vector<u16> clients = m_clients.getClientIDs();
2064 for(std::vector<u16>::iterator i = clients.begin();
2065 i != clients.end(); ++i) {
2068 if(Player *player = m_env->getPlayer(*i)) {
2069 // If player is far away, only set modified blocks not sent
2070 v3f player_pos = player->getPosition();
2071 if(player_pos.getDistanceFrom(p_f) > maxd) {
2072 far_players->push_back(*i);
2079 m_clients.send(*i, 0, &pkt, true);
2083 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2084 std::vector<u16> *far_players, float far_d_nodes,
2085 bool remove_metadata)
2087 float maxd = far_d_nodes*BS;
2088 v3f p_f = intToFloat(p, BS);
2090 std::vector<u16> clients = m_clients.getClientIDs();
2091 for(std::vector<u16>::iterator i = clients.begin();
2092 i != clients.end(); ++i) {
2096 if(Player *player = m_env->getPlayer(*i)) {
2097 // If player is far away, only set modified blocks not sent
2098 v3f player_pos = player->getPosition();
2099 if(player_pos.getDistanceFrom(p_f) > maxd) {
2100 far_players->push_back(*i);
2106 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2108 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2110 pkt << p << n.param0 << n.param1 << n.param2
2111 << (u8) (remove_metadata ? 0 : 1);
2113 if (!remove_metadata) {
2114 if (client->net_proto_version <= 21) {
2115 // Old clients always clear metadata; fix it
2116 // by sending the full block again.
2117 client->SetBlockNotSent(getNodeBlockPos(p));
2124 if (pkt.getSize() > 0)
2125 m_clients.send(*i, 0, &pkt, true);
2129 void Server::setBlockNotSent(v3s16 p)
2131 std::vector<u16> clients = m_clients.getClientIDs();
2133 for(std::vector<u16>::iterator i = clients.begin();
2134 i != clients.end(); ++i) {
2135 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2136 client->SetBlockNotSent(p);
2141 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2143 DSTACK(FUNCTION_NAME);
2145 v3s16 p = block->getPos();
2148 Create a packet with the block in the right format
2151 std::ostringstream os(std::ios_base::binary);
2152 block->serialize(os, ver, false);
2153 block->serializeNetworkSpecific(os, net_proto_version);
2154 std::string s = os.str();
2156 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2159 pkt.putRawString(s.c_str(), s.size());
2163 void Server::SendBlocks(float dtime)
2165 DSTACK(FUNCTION_NAME);
2167 MutexAutoLock envlock(m_env_mutex);
2168 //TODO check if one big lock could be faster then multiple small ones
2170 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2172 std::vector<PrioritySortedBlockTransfer> queue;
2174 s32 total_sending = 0;
2177 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2179 std::vector<u16> clients = m_clients.getClientIDs();
2182 for(std::vector<u16>::iterator i = clients.begin();
2183 i != clients.end(); ++i) {
2184 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2189 total_sending += client->SendingCount();
2190 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2196 // Lowest priority number comes first.
2197 // Lowest is most important.
2198 std::sort(queue.begin(), queue.end());
2201 for(u32 i=0; i<queue.size(); i++)
2203 //TODO: Calculate limit dynamically
2204 if(total_sending >= g_settings->getS32
2205 ("max_simultaneous_block_sends_server_total"))
2208 PrioritySortedBlockTransfer q = queue[i];
2210 MapBlock *block = NULL;
2213 block = m_env->getMap().getBlockNoCreate(q.pos);
2215 catch(InvalidPositionException &e)
2220 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2225 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2227 client->SentBlock(q.pos);
2233 void Server::fillMediaCache()
2235 DSTACK(FUNCTION_NAME);
2237 infostream<<"Server: Calculating media file checksums"<<std::endl;
2239 // Collect all media file paths
2240 std::vector<std::string> paths;
2241 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2242 i != m_mods.end(); ++i) {
2243 const ModSpec &mod = *i;
2244 paths.push_back(mod.path + DIR_DELIM + "textures");
2245 paths.push_back(mod.path + DIR_DELIM + "sounds");
2246 paths.push_back(mod.path + DIR_DELIM + "media");
2247 paths.push_back(mod.path + DIR_DELIM + "models");
2249 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2251 // Collect media file information from paths into cache
2252 for(std::vector<std::string>::iterator i = paths.begin();
2253 i != paths.end(); ++i) {
2254 std::string mediapath = *i;
2255 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2256 for (u32 j = 0; j < dirlist.size(); j++) {
2257 if (dirlist[j].dir) // Ignode dirs
2259 std::string filename = dirlist[j].name;
2260 // If name contains illegal characters, ignore the file
2261 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2262 infostream<<"Server: ignoring illegal file name: \""
2263 << filename << "\"" << std::endl;
2266 // If name is not in a supported format, ignore it
2267 const char *supported_ext[] = {
2268 ".png", ".jpg", ".bmp", ".tga",
2269 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2271 ".x", ".b3d", ".md2", ".obj",
2274 if (removeStringEnd(filename, supported_ext) == ""){
2275 infostream << "Server: ignoring unsupported file extension: \""
2276 << filename << "\"" << std::endl;
2279 // Ok, attempt to load the file and add to cache
2280 std::string filepath = mediapath + DIR_DELIM + filename;
2282 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2284 errorstream << "Server::fillMediaCache(): Could not open \""
2285 << filename << "\" for reading" << std::endl;
2288 std::ostringstream tmp_os(std::ios_base::binary);
2292 fis.read(buf, 1024);
2293 std::streamsize len = fis.gcount();
2294 tmp_os.write(buf, len);
2303 errorstream<<"Server::fillMediaCache(): Failed to read \""
2304 << filename << "\"" << std::endl;
2307 if(tmp_os.str().length() == 0) {
2308 errorstream << "Server::fillMediaCache(): Empty file \""
2309 << filepath << "\"" << std::endl;
2314 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2316 unsigned char *digest = sha1.getDigest();
2317 std::string sha1_base64 = base64_encode(digest, 20);
2318 std::string sha1_hex = hex_encode((char*)digest, 20);
2322 m_media[filename] = MediaInfo(filepath, sha1_base64);
2323 verbosestream << "Server: " << sha1_hex << " is " << filename
2329 void Server::sendMediaAnnouncement(u16 peer_id)
2331 DSTACK(FUNCTION_NAME);
2333 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2337 std::ostringstream os(std::ios_base::binary);
2339 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2340 pkt << (u16) m_media.size();
2342 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2343 i != m_media.end(); ++i) {
2344 pkt << i->first << i->second.sha1_digest;
2347 pkt << g_settings->get("remote_media");
2351 struct SendableMedia
2357 SendableMedia(const std::string &name_="", const std::string &path_="",
2358 const std::string &data_=""):
2365 void Server::sendRequestedMedia(u16 peer_id,
2366 const std::vector<std::string> &tosend)
2368 DSTACK(FUNCTION_NAME);
2370 verbosestream<<"Server::sendRequestedMedia(): "
2371 <<"Sending files to client"<<std::endl;
2375 // Put 5kB in one bunch (this is not accurate)
2376 u32 bytes_per_bunch = 5000;
2378 std::vector< std::vector<SendableMedia> > file_bunches;
2379 file_bunches.push_back(std::vector<SendableMedia>());
2381 u32 file_size_bunch_total = 0;
2383 for(std::vector<std::string>::const_iterator i = tosend.begin();
2384 i != tosend.end(); ++i) {
2385 const std::string &name = *i;
2387 if(m_media.find(name) == m_media.end()) {
2388 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2389 <<"unknown file \""<<(name)<<"\""<<std::endl;
2393 //TODO get path + name
2394 std::string tpath = m_media[name].path;
2397 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2398 if(fis.good() == false){
2399 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2400 <<tpath<<"\" for reading"<<std::endl;
2403 std::ostringstream tmp_os(std::ios_base::binary);
2407 fis.read(buf, 1024);
2408 std::streamsize len = fis.gcount();
2409 tmp_os.write(buf, len);
2410 file_size_bunch_total += len;
2419 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2420 <<name<<"\""<<std::endl;
2423 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2424 <<tname<<"\""<<std::endl;*/
2426 file_bunches[file_bunches.size()-1].push_back(
2427 SendableMedia(name, tpath, tmp_os.str()));
2429 // Start next bunch if got enough data
2430 if(file_size_bunch_total >= bytes_per_bunch) {
2431 file_bunches.push_back(std::vector<SendableMedia>());
2432 file_size_bunch_total = 0;
2437 /* Create and send packets */
2439 u16 num_bunches = file_bunches.size();
2440 for(u16 i = 0; i < num_bunches; i++) {
2443 u16 total number of texture bunches
2444 u16 index of this bunch
2445 u32 number of files in this bunch
2454 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2455 pkt << num_bunches << i << (u32) file_bunches[i].size();
2457 for(std::vector<SendableMedia>::iterator
2458 j = file_bunches[i].begin();
2459 j != file_bunches[i].end(); ++j) {
2461 pkt.putLongString(j->data);
2464 verbosestream << "Server::sendRequestedMedia(): bunch "
2465 << i << "/" << num_bunches
2466 << " files=" << file_bunches[i].size()
2467 << " size=" << pkt.getSize() << std::endl;
2472 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2474 if(m_detached_inventories.count(name) == 0) {
2475 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2478 Inventory *inv = m_detached_inventories[name];
2479 std::ostringstream os(std::ios_base::binary);
2481 os << serializeString(name);
2485 std::string s = os.str();
2487 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2488 pkt.putRawString(s.c_str(), s.size());
2490 if (peer_id != PEER_ID_INEXISTENT) {
2494 m_clients.sendToAll(0, &pkt, true);
2498 void Server::sendDetachedInventories(u16 peer_id)
2500 DSTACK(FUNCTION_NAME);
2502 for(std::map<std::string, Inventory*>::iterator
2503 i = m_detached_inventories.begin();
2504 i != m_detached_inventories.end(); ++i) {
2505 const std::string &name = i->first;
2506 //Inventory *inv = i->second;
2507 sendDetachedInventory(name, peer_id);
2515 void Server::DiePlayer(u16 peer_id)
2517 DSTACK(FUNCTION_NAME);
2518 PlayerSAO *playersao = getPlayerSAO(peer_id);
2519 // In some rare cases this can be NULL -- if the player is disconnected
2520 // when a Lua function modifies l_punch, for example
2524 infostream << "Server::DiePlayer(): Player "
2525 << playersao->getPlayer()->getName()
2526 << " dies" << std::endl;
2528 playersao->setHP(0);
2530 // Trigger scripted stuff
2531 m_script->on_dieplayer(playersao);
2533 SendPlayerHP(peer_id);
2534 SendDeathscreen(peer_id, false, v3f(0,0,0));
2537 void Server::RespawnPlayer(u16 peer_id)
2539 DSTACK(FUNCTION_NAME);
2541 PlayerSAO *playersao = getPlayerSAO(peer_id);
2544 infostream << "Server::RespawnPlayer(): Player "
2545 << playersao->getPlayer()->getName()
2546 << " respawns" << std::endl;
2548 playersao->setHP(PLAYER_MAX_HP);
2549 playersao->setBreath(PLAYER_MAX_BREATH);
2551 SendPlayerHP(peer_id);
2552 SendPlayerBreath(peer_id);
2554 bool repositioned = m_script->on_respawnplayer(playersao);
2556 v3f pos = findSpawnPos();
2557 // setPos will send the new position to client
2558 playersao->setPos(pos);
2563 void Server::DenySudoAccess(u16 peer_id)
2565 DSTACK(FUNCTION_NAME);
2567 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2572 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2573 const std::string &str_reason, bool reconnect)
2575 if (proto_ver >= 25) {
2576 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2578 std::wstring wreason = utf8_to_wide(
2579 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2580 accessDeniedStrings[(u8)reason]);
2581 SendAccessDenied_Legacy(peer_id, wreason);
2584 m_clients.event(peer_id, CSE_SetDenied);
2585 m_con.DisconnectPeer(peer_id);
2589 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2591 DSTACK(FUNCTION_NAME);
2593 SendAccessDenied(peer_id, reason, custom_reason);
2594 m_clients.event(peer_id, CSE_SetDenied);
2595 m_con.DisconnectPeer(peer_id);
2598 // 13/03/15: remove this function when protocol version 25 will become
2599 // the minimum version for MT users, maybe in 1 year
2600 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2602 DSTACK(FUNCTION_NAME);
2604 SendAccessDenied_Legacy(peer_id, reason);
2605 m_clients.event(peer_id, CSE_SetDenied);
2606 m_con.DisconnectPeer(peer_id);
2609 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2611 DSTACK(FUNCTION_NAME);
2614 RemoteClient* client = getClient(peer_id, CS_Invalid);
2616 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2618 // Right now, the auth mechs don't change between login and sudo mode.
2619 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2620 client->allowed_sudo_mechs = sudo_auth_mechs;
2622 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2623 << g_settings->getFloat("dedicated_server_step")
2627 m_clients.event(peer_id, CSE_AuthAccept);
2629 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2631 // We only support SRP right now
2632 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2634 resp_pkt << sudo_auth_mechs;
2636 m_clients.event(peer_id, CSE_SudoSuccess);
2640 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2642 DSTACK(FUNCTION_NAME);
2643 std::wstring message;
2646 Clear references to playing sounds
2648 for(std::map<s32, ServerPlayingSound>::iterator
2649 i = m_playing_sounds.begin();
2650 i != m_playing_sounds.end();)
2652 ServerPlayingSound &psound = i->second;
2653 psound.clients.erase(peer_id);
2654 if(psound.clients.empty())
2655 m_playing_sounds.erase(i++);
2660 Player *player = m_env->getPlayer(peer_id);
2662 // Collect information about leaving in chat
2664 if(player != NULL && reason != CDR_DENY)
2666 std::wstring name = narrow_to_wide(player->getName());
2669 message += L" left the game.";
2670 if(reason == CDR_TIMEOUT)
2671 message += L" (timed out)";
2675 /* Run scripts and remove from environment */
2679 PlayerSAO *playersao = player->getPlayerSAO();
2682 m_script->on_leaveplayer(playersao);
2684 playersao->disconnected();
2692 if(player != NULL && reason != CDR_DENY) {
2693 std::ostringstream os(std::ios_base::binary);
2694 std::vector<u16> clients = m_clients.getClientIDs();
2696 for(std::vector<u16>::iterator i = clients.begin();
2697 i != clients.end(); ++i) {
2699 Player *player = m_env->getPlayer(*i);
2703 // Get name of player
2704 os << player->getName() << " ";
2707 std::string name = player->getName();
2708 actionstream << name << " "
2709 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2710 << " List of players: " << os.str() << std::endl;
2712 m_admin_chat->outgoing_queue.push_back(
2713 new ChatEventNick(CET_NICK_REMOVE, name));
2717 MutexAutoLock env_lock(m_env_mutex);
2718 m_clients.DeleteClient(peer_id);
2722 // Send leave chat message to all remaining clients
2723 if(message.length() != 0)
2724 SendChatMessage(PEER_ID_INEXISTENT,message);
2727 void Server::UpdateCrafting(Player* player)
2729 DSTACK(FUNCTION_NAME);
2731 // Get a preview for crafting
2733 InventoryLocation loc;
2734 loc.setPlayer(player->getName());
2735 std::vector<ItemStack> output_replacements;
2736 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2737 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2739 // Put the new preview in
2740 InventoryList *plist = player->inventory.getList("craftpreview");
2741 sanity_check(plist);
2742 sanity_check(plist->getSize() >= 1);
2743 plist->changeItem(0, preview);
2746 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2748 if (evt->type == CET_NICK_ADD) {
2749 // The terminal informed us of its nick choice
2750 m_admin_nick = ((ChatEventNick *)evt)->nick;
2751 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2752 errorstream << "You haven't set up an account." << std::endl
2753 << "Please log in using the client as '"
2754 << m_admin_nick << "' with a secure password." << std::endl
2755 << "Until then, you can't execute admin tasks via the console," << std::endl
2756 << "and everybody can claim the user account instead of you," << std::endl
2757 << "giving them full control over this server." << std::endl;
2760 assert(evt->type == CET_CHAT);
2761 handleAdminChat((ChatEventChat *)evt);
2765 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2766 const std::wstring &wmessage, bool check_shout_priv,
2767 u16 peer_id_to_avoid_sending)
2769 // If something goes wrong, this player is to blame
2770 RollbackScopeActor rollback_scope(m_rollback,
2771 std::string("player:") + name);
2775 // Whether to send line to the player that sent the message, or to all players
2776 bool broadcast_line = true;
2779 bool ate = m_script->on_chat_message(name,
2780 wide_to_utf8(wmessage));
2781 // If script ate the message, don't proceed
2785 // Commands are implemented in Lua, so only catch invalid
2786 // commands that were not "eaten" and send an error back
2787 if (wmessage[0] == L'/') {
2788 std::wstring wcmd = wmessage.substr(1);
2789 broadcast_line = false;
2790 if (wcmd.length() == 0)
2791 line += L"-!- Empty command";
2793 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2795 if (check_shout_priv && !checkPriv(name, "shout")) {
2796 line += L"-!- You don't have permission to shout.";
2797 broadcast_line = false;
2807 Tell calling method to send the message to sender
2809 if (!broadcast_line) {
2813 Send the message to others
2815 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2817 std::vector<u16> clients = m_clients.getClientIDs();
2819 for (u16 i = 0; i < clients.size(); i++) {
2820 u16 cid = clients[i];
2821 if (cid != peer_id_to_avoid_sending)
2822 SendChatMessage(cid, line);
2828 void Server::handleAdminChat(const ChatEventChat *evt)
2830 std::string name = evt->nick;
2831 std::wstring wname = utf8_to_wide(name);
2832 std::wstring wmessage = evt->evt_msg;
2834 std::wstring answer = handleChat(name, wname, wmessage);
2836 // If asked to send answer to sender
2837 if (!answer.empty()) {
2838 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2842 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2844 RemoteClient *client = getClientNoEx(peer_id,state_min);
2846 throw ClientNotFoundException("Client not found");
2850 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2852 return m_clients.getClientNoEx(peer_id, state_min);
2855 std::string Server::getPlayerName(u16 peer_id)
2857 Player *player = m_env->getPlayer(peer_id);
2859 return "[id="+itos(peer_id)+"]";
2860 return player->getName();
2863 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2865 Player *player = m_env->getPlayer(peer_id);
2868 return player->getPlayerSAO();
2871 std::wstring Server::getStatusString()
2873 std::wostringstream os(std::ios_base::binary);
2876 os<<L"version="<<narrow_to_wide(g_version_string);
2878 os<<L", uptime="<<m_uptime.get();
2880 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2881 // Information about clients
2884 std::vector<u16> clients = m_clients.getClientIDs();
2885 for(std::vector<u16>::iterator i = clients.begin();
2886 i != clients.end(); ++i) {
2888 Player *player = m_env->getPlayer(*i);
2889 // Get name of player
2890 std::wstring name = L"unknown";
2892 name = narrow_to_wide(player->getName());
2893 // Add name to information string
2901 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2902 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2903 if(g_settings->get("motd") != "")
2904 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2908 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2910 std::set<std::string> privs;
2911 m_script->getAuth(name, NULL, &privs);
2915 bool Server::checkPriv(const std::string &name, const std::string &priv)
2917 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2918 return (privs.count(priv) != 0);
2921 void Server::reportPrivsModified(const std::string &name)
2924 std::vector<u16> clients = m_clients.getClientIDs();
2925 for(std::vector<u16>::iterator i = clients.begin();
2926 i != clients.end(); ++i) {
2927 Player *player = m_env->getPlayer(*i);
2928 reportPrivsModified(player->getName());
2931 Player *player = m_env->getPlayer(name.c_str());
2934 SendPlayerPrivileges(player->peer_id);
2935 PlayerSAO *sao = player->getPlayerSAO();
2938 sao->updatePrivileges(
2939 getPlayerEffectivePrivs(name),
2944 void Server::reportInventoryFormspecModified(const std::string &name)
2946 Player *player = m_env->getPlayer(name.c_str());
2949 SendPlayerInventoryFormspec(player->peer_id);
2952 void Server::setIpBanned(const std::string &ip, const std::string &name)
2954 m_banmanager->add(ip, name);
2957 void Server::unsetIpBanned(const std::string &ip_or_name)
2959 m_banmanager->remove(ip_or_name);
2962 std::string Server::getBanDescription(const std::string &ip_or_name)
2964 return m_banmanager->getBanDescription(ip_or_name);
2967 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2969 // m_env will be NULL if the server is initializing
2973 if (m_admin_nick == name && !m_admin_nick.empty()) {
2974 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2977 Player *player = m_env->getPlayer(name);
2982 if (player->peer_id == PEER_ID_INEXISTENT)
2985 SendChatMessage(player->peer_id, msg);
2988 bool Server::showFormspec(const char *playername, const std::string &formspec,
2989 const std::string &formname)
2991 // m_env will be NULL if the server is initializing
2995 Player *player = m_env->getPlayer(playername);
2999 SendShowFormspecMessage(player->peer_id, formspec, formname);
3003 u32 Server::hudAdd(Player *player, HudElement *form)
3008 u32 id = player->addHud(form);
3010 SendHUDAdd(player->peer_id, id, form);
3015 bool Server::hudRemove(Player *player, u32 id) {
3019 HudElement* todel = player->removeHud(id);
3026 SendHUDRemove(player->peer_id, id);
3030 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3035 SendHUDChange(player->peer_id, id, stat, data);
3039 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3044 SendHUDSetFlags(player->peer_id, flags, mask);
3045 player->hud_flags &= ~mask;
3046 player->hud_flags |= flags;
3048 PlayerSAO* playersao = player->getPlayerSAO();
3050 if (playersao == NULL)
3053 m_script->player_event(playersao, "hud_changed");
3057 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3061 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3064 player->setHotbarItemcount(hotbar_itemcount);
3065 std::ostringstream os(std::ios::binary);
3066 writeS32(os, hotbar_itemcount);
3067 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3071 s32 Server::hudGetHotbarItemcount(Player *player)
3075 return player->getHotbarItemcount();
3078 void Server::hudSetHotbarImage(Player *player, std::string name)
3083 player->setHotbarImage(name);
3084 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3087 std::string Server::hudGetHotbarImage(Player *player)
3091 return player->getHotbarImage();
3094 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3099 player->setHotbarSelectedImage(name);
3100 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3103 std::string Server::hudGetHotbarSelectedImage(Player *player)
3108 return player->getHotbarSelectedImage();
3111 bool Server::setLocalPlayerAnimations(Player *player,
3112 v2s32 animation_frames[4], f32 frame_speed)
3117 player->setLocalAnimations(animation_frames, frame_speed);
3118 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3122 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3127 player->eye_offset_first = first;
3128 player->eye_offset_third = third;
3129 SendEyeOffset(player->peer_id, first, third);
3133 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3134 const std::string &type, const std::vector<std::string> ¶ms)
3139 player->setSky(bgcolor, type, params);
3140 SendSetSky(player->peer_id, bgcolor, type, params);
3144 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3150 player->overrideDayNightRatio(do_override, ratio);
3151 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3155 void Server::notifyPlayers(const std::wstring &msg)
3157 SendChatMessage(PEER_ID_INEXISTENT,msg);
3160 void Server::spawnParticle(const std::string &playername, v3f pos,
3161 v3f velocity, v3f acceleration,
3162 float expirationtime, float size, bool
3163 collisiondetection, bool vertical, const std::string &texture)
3165 // m_env will be NULL if the server is initializing
3169 u16 peer_id = PEER_ID_INEXISTENT;
3170 if (playername != "") {
3171 Player* player = m_env->getPlayer(playername.c_str());
3174 peer_id = player->peer_id;
3177 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3178 expirationtime, size, collisiondetection, vertical, texture);
3181 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3182 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3183 float minexptime, float maxexptime, float minsize, float maxsize,
3184 bool collisiondetection, bool vertical, const std::string &texture,
3185 const std::string &playername)
3187 // m_env will be NULL if the server is initializing
3191 u16 peer_id = PEER_ID_INEXISTENT;
3192 if (playername != "") {
3193 Player* player = m_env->getPlayer(playername.c_str());
3196 peer_id = player->peer_id;
3199 u32 id = m_env->addParticleSpawner(spawntime);
3200 SendAddParticleSpawner(peer_id, amount, spawntime,
3201 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3202 minexptime, maxexptime, minsize, maxsize,
3203 collisiondetection, vertical, texture, id);
3208 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3210 // m_env will be NULL if the server is initializing
3212 throw ServerError("Can't delete particle spawners during initialisation!");
3214 u16 peer_id = PEER_ID_INEXISTENT;
3215 if (playername != "") {
3216 Player* player = m_env->getPlayer(playername.c_str());
3219 peer_id = player->peer_id;
3222 m_env->deleteParticleSpawner(id);
3223 SendDeleteParticleSpawner(peer_id, id);
3226 void Server::deleteParticleSpawnerAll(u32 id)
3228 m_env->deleteParticleSpawner(id);
3229 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3232 Inventory* Server::createDetachedInventory(const std::string &name)
3234 if(m_detached_inventories.count(name) > 0){
3235 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3236 delete m_detached_inventories[name];
3238 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3240 Inventory *inv = new Inventory(m_itemdef);
3242 m_detached_inventories[name] = inv;
3243 //TODO find a better way to do this
3244 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3248 // actions: time-reversed list
3249 // Return value: success/failure
3250 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3251 std::list<std::string> *log)
3253 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3254 ServerMap *map = (ServerMap*)(&m_env->getMap());
3256 // Fail if no actions to handle
3257 if(actions.empty()){
3258 log->push_back("Nothing to do.");
3265 for(std::list<RollbackAction>::const_iterator
3266 i = actions.begin();
3267 i != actions.end(); ++i)
3269 const RollbackAction &action = *i;
3271 bool success = action.applyRevert(map, this, this);
3274 std::ostringstream os;
3275 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3276 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3278 log->push_back(os.str());
3280 std::ostringstream os;
3281 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3282 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3284 log->push_back(os.str());
3288 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3289 <<" failed"<<std::endl;
3291 // Call it done if less than half failed
3292 return num_failed <= num_tried/2;
3295 // IGameDef interface
3297 IItemDefManager *Server::getItemDefManager()
3302 INodeDefManager *Server::getNodeDefManager()
3307 ICraftDefManager *Server::getCraftDefManager()
3311 ITextureSource *Server::getTextureSource()
3315 IShaderSource *Server::getShaderSource()
3319 scene::ISceneManager *Server::getSceneManager()
3324 u16 Server::allocateUnknownNodeId(const std::string &name)
3326 return m_nodedef->allocateDummy(name);
3329 ISoundManager *Server::getSoundManager()
3331 return &dummySoundManager;
3334 MtEventManager *Server::getEventManager()
3339 IWritableItemDefManager *Server::getWritableItemDefManager()
3344 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3349 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3354 const ModSpec *Server::getModSpec(const std::string &modname) const
3356 std::vector<ModSpec>::const_iterator it;
3357 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3358 const ModSpec &mod = *it;
3359 if (mod.name == modname)
3365 void Server::getModNames(std::vector<std::string> &modlist)
3367 std::vector<ModSpec>::iterator it;
3368 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3369 modlist.push_back(it->name);
3372 std::string Server::getBuiltinLuaPath()
3374 return porting::path_share + DIR_DELIM + "builtin";
3377 v3f Server::findSpawnPos()
3379 ServerMap &map = m_env->getServerMap();
3381 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3382 return nodeposf * BS;
3385 bool is_good = false;
3387 // Try to find a good place a few times
3388 for(s32 i = 0; i < 4000 && !is_good; i++) {
3390 // We're going to try to throw the player to this position
3391 v2s16 nodepos2d = v2s16(
3392 -range + (myrand() % (range * 2)),
3393 -range + (myrand() % (range * 2)));
3395 // Get spawn level at point
3396 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3397 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3398 // the mapgen to signify an unsuitable spawn position
3399 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3402 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3405 for (s32 i = 0; i < 10; i++) {
3406 v3s16 blockpos = getNodeBlockPos(nodepos);
3407 map.emergeBlock(blockpos, true);
3408 content_t c = map.getNodeNoEx(nodepos).getContent();
3409 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3411 if (air_count >= 2) {
3412 nodeposf = intToFloat(nodepos, BS);
3413 // Don't spawn the player outside map boundaries
3414 if (objectpos_over_limit(nodeposf))
3427 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3429 bool newplayer = false;
3432 Try to get an existing player
3434 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3436 // If player is already connected, cancel
3437 if(player != NULL && player->peer_id != 0)
3439 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3444 If player with the wanted peer_id already exists, cancel.
3446 if(m_env->getPlayer(peer_id) != NULL)
3448 infostream<<"emergePlayer(): Player with wrong name but same"
3449 " peer_id already exists"<<std::endl;
3453 // Load player if it isn't already loaded
3455 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3458 // Create player if it doesn't exist
3461 player = new RemotePlayer(this, name);
3462 // Set player position
3463 infostream<<"Server: Finding spawn place for player \""
3464 <<name<<"\""<<std::endl;
3465 v3f pos = findSpawnPos();
3466 player->setPosition(pos);
3468 // Make sure the player is saved
3469 player->setModified(true);
3471 // Add player to environment
3472 m_env->addPlayer(player);
3474 // If the player exists, ensure that they respawn inside legal bounds
3475 // This fixes an assert crash when the player can't be added
3476 // to the environment
3477 if (objectpos_over_limit(player->getPosition())) {
3478 actionstream << "Respawn position for player \""
3479 << name << "\" outside limits, resetting" << std::endl;
3480 v3f pos = findSpawnPos();
3481 player->setPosition(pos);
3485 // Create a new player active object
3486 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3487 getPlayerEffectivePrivs(player->getName()),
3490 player->protocol_version = proto_version;
3492 /* Clean up old HUD elements from previous sessions */
3495 /* Add object to environment */
3496 m_env->addActiveObject(playersao);
3500 m_script->on_newplayer(playersao);
3506 void dedicated_server_loop(Server &server, bool &kill)
3508 DSTACK(FUNCTION_NAME);
3510 verbosestream<<"dedicated_server_loop()"<<std::endl;
3512 IntervalLimiter m_profiler_interval;
3514 static const float steplen = g_settings->getFloat("dedicated_server_step");
3515 static const float profiler_print_interval =
3516 g_settings->getFloat("profiler_print_interval");
3519 // This is kind of a hack but can be done like this
3520 // because server.step() is very light
3522 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3523 sleep_ms((int)(steplen*1000.0));
3525 server.step(steplen);
3527 if(server.getShutdownRequested() || kill)
3529 infostream<<"Dedicated server quitting"<<std::endl;
3531 if(g_settings->getBool("server_announce"))
3532 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3540 if (profiler_print_interval != 0) {
3541 if(m_profiler_interval.step(steplen, profiler_print_interval))
3543 infostream<<"Profiler:"<<std::endl;
3544 g_profiler->print(infostream);
3545 g_profiler->clear();