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);
2519 PlayerSAO *playersao = getPlayerSAO(peer_id);
2522 infostream << "Server::DiePlayer(): Player "
2523 << playersao->getPlayer()->getName()
2524 << " dies" << std::endl;
2526 playersao->setHP(0);
2528 // Trigger scripted stuff
2529 m_script->on_dieplayer(playersao);
2531 SendPlayerHP(peer_id);
2532 SendDeathscreen(peer_id, false, v3f(0,0,0));
2535 void Server::RespawnPlayer(u16 peer_id)
2537 DSTACK(FUNCTION_NAME);
2539 PlayerSAO *playersao = getPlayerSAO(peer_id);
2542 infostream << "Server::RespawnPlayer(): Player "
2543 << playersao->getPlayer()->getName()
2544 << " respawns" << std::endl;
2546 playersao->setHP(PLAYER_MAX_HP);
2547 playersao->setBreath(PLAYER_MAX_BREATH);
2549 SendPlayerHP(peer_id);
2550 SendPlayerBreath(peer_id);
2552 bool repositioned = m_script->on_respawnplayer(playersao);
2554 v3f pos = findSpawnPos();
2555 // setPos will send the new position to client
2556 playersao->setPos(pos);
2561 void Server::DenySudoAccess(u16 peer_id)
2563 DSTACK(FUNCTION_NAME);
2565 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2570 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2571 const std::string &str_reason, bool reconnect)
2573 if (proto_ver >= 25) {
2574 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2576 std::wstring wreason = utf8_to_wide(
2577 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2578 accessDeniedStrings[(u8)reason]);
2579 SendAccessDenied_Legacy(peer_id, wreason);
2582 m_clients.event(peer_id, CSE_SetDenied);
2583 m_con.DisconnectPeer(peer_id);
2587 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2589 DSTACK(FUNCTION_NAME);
2591 SendAccessDenied(peer_id, reason, custom_reason);
2592 m_clients.event(peer_id, CSE_SetDenied);
2593 m_con.DisconnectPeer(peer_id);
2596 // 13/03/15: remove this function when protocol version 25 will become
2597 // the minimum version for MT users, maybe in 1 year
2598 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2600 DSTACK(FUNCTION_NAME);
2602 SendAccessDenied_Legacy(peer_id, reason);
2603 m_clients.event(peer_id, CSE_SetDenied);
2604 m_con.DisconnectPeer(peer_id);
2607 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2609 DSTACK(FUNCTION_NAME);
2612 RemoteClient* client = getClient(peer_id, CS_Invalid);
2614 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2616 // Right now, the auth mechs don't change between login and sudo mode.
2617 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2618 client->allowed_sudo_mechs = sudo_auth_mechs;
2620 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2621 << g_settings->getFloat("dedicated_server_step")
2625 m_clients.event(peer_id, CSE_AuthAccept);
2627 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2629 // We only support SRP right now
2630 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2632 resp_pkt << sudo_auth_mechs;
2634 m_clients.event(peer_id, CSE_SudoSuccess);
2638 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2640 DSTACK(FUNCTION_NAME);
2641 std::wstring message;
2644 Clear references to playing sounds
2646 for(std::map<s32, ServerPlayingSound>::iterator
2647 i = m_playing_sounds.begin();
2648 i != m_playing_sounds.end();)
2650 ServerPlayingSound &psound = i->second;
2651 psound.clients.erase(peer_id);
2652 if(psound.clients.empty())
2653 m_playing_sounds.erase(i++);
2658 Player *player = m_env->getPlayer(peer_id);
2660 // Collect information about leaving in chat
2662 if(player != NULL && reason != CDR_DENY)
2664 std::wstring name = narrow_to_wide(player->getName());
2667 message += L" left the game.";
2668 if(reason == CDR_TIMEOUT)
2669 message += L" (timed out)";
2673 /* Run scripts and remove from environment */
2677 PlayerSAO *playersao = player->getPlayerSAO();
2680 m_script->on_leaveplayer(playersao);
2682 playersao->disconnected();
2690 if(player != NULL && reason != CDR_DENY) {
2691 std::ostringstream os(std::ios_base::binary);
2692 std::vector<u16> clients = m_clients.getClientIDs();
2694 for(std::vector<u16>::iterator i = clients.begin();
2695 i != clients.end(); ++i) {
2697 Player *player = m_env->getPlayer(*i);
2701 // Get name of player
2702 os << player->getName() << " ";
2705 std::string name = player->getName();
2706 actionstream << name << " "
2707 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2708 << " List of players: " << os.str() << std::endl;
2710 m_admin_chat->outgoing_queue.push_back(
2711 new ChatEventNick(CET_NICK_REMOVE, name));
2715 MutexAutoLock env_lock(m_env_mutex);
2716 m_clients.DeleteClient(peer_id);
2720 // Send leave chat message to all remaining clients
2721 if(message.length() != 0)
2722 SendChatMessage(PEER_ID_INEXISTENT,message);
2725 void Server::UpdateCrafting(Player* player)
2727 DSTACK(FUNCTION_NAME);
2729 // Get a preview for crafting
2731 InventoryLocation loc;
2732 loc.setPlayer(player->getName());
2733 std::vector<ItemStack> output_replacements;
2734 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2735 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2737 // Put the new preview in
2738 InventoryList *plist = player->inventory.getList("craftpreview");
2739 sanity_check(plist);
2740 sanity_check(plist->getSize() >= 1);
2741 plist->changeItem(0, preview);
2744 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2746 if (evt->type == CET_NICK_ADD) {
2747 // The terminal informed us of its nick choice
2748 m_admin_nick = ((ChatEventNick *)evt)->nick;
2749 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2750 errorstream << "You haven't set up an account." << std::endl
2751 << "Please log in using the client as '"
2752 << m_admin_nick << "' with a secure password." << std::endl
2753 << "Until then, you can't execute admin tasks via the console," << std::endl
2754 << "and everybody can claim the user account instead of you," << std::endl
2755 << "giving them full control over this server." << std::endl;
2758 assert(evt->type == CET_CHAT);
2759 handleAdminChat((ChatEventChat *)evt);
2763 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2764 const std::wstring &wmessage, bool check_shout_priv,
2765 u16 peer_id_to_avoid_sending)
2767 // If something goes wrong, this player is to blame
2768 RollbackScopeActor rollback_scope(m_rollback,
2769 std::string("player:") + name);
2773 // Whether to send line to the player that sent the message, or to all players
2774 bool broadcast_line = true;
2777 bool ate = m_script->on_chat_message(name,
2778 wide_to_utf8(wmessage));
2779 // If script ate the message, don't proceed
2783 // Commands are implemented in Lua, so only catch invalid
2784 // commands that were not "eaten" and send an error back
2785 if (wmessage[0] == L'/') {
2786 std::wstring wcmd = wmessage.substr(1);
2787 broadcast_line = false;
2788 if (wcmd.length() == 0)
2789 line += L"-!- Empty command";
2791 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2793 if (check_shout_priv && !checkPriv(name, "shout")) {
2794 line += L"-!- You don't have permission to shout.";
2795 broadcast_line = false;
2805 Tell calling method to send the message to sender
2807 if (!broadcast_line) {
2811 Send the message to others
2813 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2815 std::vector<u16> clients = m_clients.getClientIDs();
2817 for (u16 i = 0; i < clients.size(); i++) {
2818 u16 cid = clients[i];
2819 if (cid != peer_id_to_avoid_sending)
2820 SendChatMessage(cid, line);
2826 void Server::handleAdminChat(const ChatEventChat *evt)
2828 std::string name = evt->nick;
2829 std::wstring wname = utf8_to_wide(name);
2830 std::wstring wmessage = evt->evt_msg;
2832 std::wstring answer = handleChat(name, wname, wmessage);
2834 // If asked to send answer to sender
2835 if (!answer.empty()) {
2836 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2840 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2842 RemoteClient *client = getClientNoEx(peer_id,state_min);
2844 throw ClientNotFoundException("Client not found");
2848 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2850 return m_clients.getClientNoEx(peer_id, state_min);
2853 std::string Server::getPlayerName(u16 peer_id)
2855 Player *player = m_env->getPlayer(peer_id);
2857 return "[id="+itos(peer_id)+"]";
2858 return player->getName();
2861 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2863 Player *player = m_env->getPlayer(peer_id);
2866 return player->getPlayerSAO();
2869 std::wstring Server::getStatusString()
2871 std::wostringstream os(std::ios_base::binary);
2874 os<<L"version="<<narrow_to_wide(g_version_string);
2876 os<<L", uptime="<<m_uptime.get();
2878 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2879 // Information about clients
2882 std::vector<u16> clients = m_clients.getClientIDs();
2883 for(std::vector<u16>::iterator i = clients.begin();
2884 i != clients.end(); ++i) {
2886 Player *player = m_env->getPlayer(*i);
2887 // Get name of player
2888 std::wstring name = L"unknown";
2890 name = narrow_to_wide(player->getName());
2891 // Add name to information string
2899 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2900 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2901 if(g_settings->get("motd") != "")
2902 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2906 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2908 std::set<std::string> privs;
2909 m_script->getAuth(name, NULL, &privs);
2913 bool Server::checkPriv(const std::string &name, const std::string &priv)
2915 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2916 return (privs.count(priv) != 0);
2919 void Server::reportPrivsModified(const std::string &name)
2922 std::vector<u16> clients = m_clients.getClientIDs();
2923 for(std::vector<u16>::iterator i = clients.begin();
2924 i != clients.end(); ++i) {
2925 Player *player = m_env->getPlayer(*i);
2926 reportPrivsModified(player->getName());
2929 Player *player = m_env->getPlayer(name.c_str());
2932 SendPlayerPrivileges(player->peer_id);
2933 PlayerSAO *sao = player->getPlayerSAO();
2936 sao->updatePrivileges(
2937 getPlayerEffectivePrivs(name),
2942 void Server::reportInventoryFormspecModified(const std::string &name)
2944 Player *player = m_env->getPlayer(name.c_str());
2947 SendPlayerInventoryFormspec(player->peer_id);
2950 void Server::setIpBanned(const std::string &ip, const std::string &name)
2952 m_banmanager->add(ip, name);
2955 void Server::unsetIpBanned(const std::string &ip_or_name)
2957 m_banmanager->remove(ip_or_name);
2960 std::string Server::getBanDescription(const std::string &ip_or_name)
2962 return m_banmanager->getBanDescription(ip_or_name);
2965 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2967 // m_env will be NULL if the server is initializing
2971 if (m_admin_nick == name && !m_admin_nick.empty()) {
2972 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2975 Player *player = m_env->getPlayer(name);
2980 if (player->peer_id == PEER_ID_INEXISTENT)
2983 SendChatMessage(player->peer_id, msg);
2986 bool Server::showFormspec(const char *playername, const std::string &formspec,
2987 const std::string &formname)
2989 // m_env will be NULL if the server is initializing
2993 Player *player = m_env->getPlayer(playername);
2997 SendShowFormspecMessage(player->peer_id, formspec, formname);
3001 u32 Server::hudAdd(Player *player, HudElement *form)
3006 u32 id = player->addHud(form);
3008 SendHUDAdd(player->peer_id, id, form);
3013 bool Server::hudRemove(Player *player, u32 id) {
3017 HudElement* todel = player->removeHud(id);
3024 SendHUDRemove(player->peer_id, id);
3028 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3033 SendHUDChange(player->peer_id, id, stat, data);
3037 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3042 SendHUDSetFlags(player->peer_id, flags, mask);
3043 player->hud_flags &= ~mask;
3044 player->hud_flags |= flags;
3046 PlayerSAO* playersao = player->getPlayerSAO();
3048 if (playersao == NULL)
3051 m_script->player_event(playersao, "hud_changed");
3055 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3059 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3062 player->setHotbarItemcount(hotbar_itemcount);
3063 std::ostringstream os(std::ios::binary);
3064 writeS32(os, hotbar_itemcount);
3065 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3069 s32 Server::hudGetHotbarItemcount(Player *player)
3073 return player->getHotbarItemcount();
3076 void Server::hudSetHotbarImage(Player *player, std::string name)
3081 player->setHotbarImage(name);
3082 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3085 std::string Server::hudGetHotbarImage(Player *player)
3089 return player->getHotbarImage();
3092 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3097 player->setHotbarSelectedImage(name);
3098 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3101 std::string Server::hudGetHotbarSelectedImage(Player *player)
3106 return player->getHotbarSelectedImage();
3109 bool Server::setLocalPlayerAnimations(Player *player,
3110 v2s32 animation_frames[4], f32 frame_speed)
3115 player->setLocalAnimations(animation_frames, frame_speed);
3116 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3120 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3125 player->eye_offset_first = first;
3126 player->eye_offset_third = third;
3127 SendEyeOffset(player->peer_id, first, third);
3131 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3132 const std::string &type, const std::vector<std::string> ¶ms)
3137 player->setSky(bgcolor, type, params);
3138 SendSetSky(player->peer_id, bgcolor, type, params);
3142 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3148 player->overrideDayNightRatio(do_override, ratio);
3149 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3153 void Server::notifyPlayers(const std::wstring &msg)
3155 SendChatMessage(PEER_ID_INEXISTENT,msg);
3158 void Server::spawnParticle(const std::string &playername, v3f pos,
3159 v3f velocity, v3f acceleration,
3160 float expirationtime, float size, bool
3161 collisiondetection, bool vertical, const std::string &texture)
3163 // m_env will be NULL if the server is initializing
3167 u16 peer_id = PEER_ID_INEXISTENT;
3168 if (playername != "") {
3169 Player* player = m_env->getPlayer(playername.c_str());
3172 peer_id = player->peer_id;
3175 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3176 expirationtime, size, collisiondetection, vertical, texture);
3179 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3180 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3181 float minexptime, float maxexptime, float minsize, float maxsize,
3182 bool collisiondetection, bool vertical, const std::string &texture,
3183 const std::string &playername)
3185 // m_env will be NULL if the server is initializing
3189 u16 peer_id = PEER_ID_INEXISTENT;
3190 if (playername != "") {
3191 Player* player = m_env->getPlayer(playername.c_str());
3194 peer_id = player->peer_id;
3198 for(;;) // look for unused particlespawner id
3201 if (std::find(m_particlespawner_ids.begin(),
3202 m_particlespawner_ids.end(), id)
3203 == m_particlespawner_ids.end())
3205 m_particlespawner_ids.push_back(id);
3210 SendAddParticleSpawner(peer_id, amount, spawntime,
3211 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3212 minexptime, maxexptime, minsize, maxsize,
3213 collisiondetection, vertical, texture, id);
3218 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3220 // m_env will be NULL if the server is initializing
3222 throw ServerError("Can't delete particle spawners during initialisation!");
3224 u16 peer_id = PEER_ID_INEXISTENT;
3225 if (playername != "") {
3226 Player* player = m_env->getPlayer(playername.c_str());
3229 peer_id = player->peer_id;
3232 m_particlespawner_ids.erase(
3233 std::remove(m_particlespawner_ids.begin(),
3234 m_particlespawner_ids.end(), id),
3235 m_particlespawner_ids.end());
3236 SendDeleteParticleSpawner(peer_id, id);
3239 Inventory* Server::createDetachedInventory(const std::string &name)
3241 if(m_detached_inventories.count(name) > 0){
3242 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3243 delete m_detached_inventories[name];
3245 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3247 Inventory *inv = new Inventory(m_itemdef);
3249 m_detached_inventories[name] = inv;
3250 //TODO find a better way to do this
3251 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3255 // actions: time-reversed list
3256 // Return value: success/failure
3257 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3258 std::list<std::string> *log)
3260 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3261 ServerMap *map = (ServerMap*)(&m_env->getMap());
3263 // Fail if no actions to handle
3264 if(actions.empty()){
3265 log->push_back("Nothing to do.");
3272 for(std::list<RollbackAction>::const_iterator
3273 i = actions.begin();
3274 i != actions.end(); ++i)
3276 const RollbackAction &action = *i;
3278 bool success = action.applyRevert(map, this, this);
3281 std::ostringstream os;
3282 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3283 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3285 log->push_back(os.str());
3287 std::ostringstream os;
3288 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3289 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3291 log->push_back(os.str());
3295 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3296 <<" failed"<<std::endl;
3298 // Call it done if less than half failed
3299 return num_failed <= num_tried/2;
3302 // IGameDef interface
3304 IItemDefManager *Server::getItemDefManager()
3309 INodeDefManager *Server::getNodeDefManager()
3314 ICraftDefManager *Server::getCraftDefManager()
3318 ITextureSource *Server::getTextureSource()
3322 IShaderSource *Server::getShaderSource()
3326 scene::ISceneManager *Server::getSceneManager()
3331 u16 Server::allocateUnknownNodeId(const std::string &name)
3333 return m_nodedef->allocateDummy(name);
3336 ISoundManager *Server::getSoundManager()
3338 return &dummySoundManager;
3341 MtEventManager *Server::getEventManager()
3346 IWritableItemDefManager *Server::getWritableItemDefManager()
3351 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3356 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3361 const ModSpec *Server::getModSpec(const std::string &modname) const
3363 std::vector<ModSpec>::const_iterator it;
3364 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3365 const ModSpec &mod = *it;
3366 if (mod.name == modname)
3372 void Server::getModNames(std::vector<std::string> &modlist)
3374 std::vector<ModSpec>::iterator it;
3375 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3376 modlist.push_back(it->name);
3379 std::string Server::getBuiltinLuaPath()
3381 return porting::path_share + DIR_DELIM + "builtin";
3384 v3f Server::findSpawnPos()
3386 ServerMap &map = m_env->getServerMap();
3388 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3389 return nodeposf * BS;
3392 bool is_good = false;
3394 // Try to find a good place a few times
3395 for(s32 i = 0; i < 4000 && !is_good; i++) {
3397 // We're going to try to throw the player to this position
3398 v2s16 nodepos2d = v2s16(
3399 -range + (myrand() % (range * 2)),
3400 -range + (myrand() % (range * 2)));
3402 // Get spawn level at point
3403 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3404 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3405 // the mapgen to signify an unsuitable spawn position
3406 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3409 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3412 for (s32 i = 0; i < 10; i++) {
3413 v3s16 blockpos = getNodeBlockPos(nodepos);
3414 map.emergeBlock(blockpos, true);
3415 content_t c = map.getNodeNoEx(nodepos).getContent();
3416 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3418 if (air_count >= 2) {
3419 nodeposf = intToFloat(nodepos, BS);
3420 // Don't spawn the player outside map boundaries
3421 if (objectpos_over_limit(nodeposf))
3434 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3436 bool newplayer = false;
3439 Try to get an existing player
3441 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3443 // If player is already connected, cancel
3444 if(player != NULL && player->peer_id != 0)
3446 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3451 If player with the wanted peer_id already exists, cancel.
3453 if(m_env->getPlayer(peer_id) != NULL)
3455 infostream<<"emergePlayer(): Player with wrong name but same"
3456 " peer_id already exists"<<std::endl;
3460 // Load player if it isn't already loaded
3462 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3465 // Create player if it doesn't exist
3468 player = new RemotePlayer(this, name);
3469 // Set player position
3470 infostream<<"Server: Finding spawn place for player \""
3471 <<name<<"\""<<std::endl;
3472 v3f pos = findSpawnPos();
3473 player->setPosition(pos);
3475 // Make sure the player is saved
3476 player->setModified(true);
3478 // Add player to environment
3479 m_env->addPlayer(player);
3481 // If the player exists, ensure that they respawn inside legal bounds
3482 // This fixes an assert crash when the player can't be added
3483 // to the environment
3484 if (objectpos_over_limit(player->getPosition())) {
3485 actionstream << "Respawn position for player \""
3486 << name << "\" outside limits, resetting" << std::endl;
3487 v3f pos = findSpawnPos();
3488 player->setPosition(pos);
3492 // Create a new player active object
3493 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3494 getPlayerEffectivePrivs(player->getName()),
3497 player->protocol_version = proto_version;
3499 /* Clean up old HUD elements from previous sessions */
3502 /* Add object to environment */
3503 m_env->addActiveObject(playersao);
3507 m_script->on_newplayer(playersao);
3513 void dedicated_server_loop(Server &server, bool &kill)
3515 DSTACK(FUNCTION_NAME);
3517 verbosestream<<"dedicated_server_loop()"<<std::endl;
3519 IntervalLimiter m_profiler_interval;
3521 static const float steplen = g_settings->getFloat("dedicated_server_step");
3522 static const float profiler_print_interval =
3523 g_settings->getFloat("profiler_print_interval");
3526 // This is kind of a hack but can be done like this
3527 // because server.step() is very light
3529 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3530 sleep_ms((int)(steplen*1000.0));
3532 server.step(steplen);
3534 if(server.getShutdownRequested() || kill)
3536 infostream<<"Dedicated server quitting"<<std::endl;
3538 if(g_settings->getBool("server_announce"))
3539 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3547 if (profiler_print_interval != 0) {
3548 if(m_profiler_interval.step(steplen, profiler_print_interval))
3550 infostream<<"Profiler:"<<std::endl;
3551 g_profiler->print(infostream);
3552 g_profiler->clear();