3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_async_fatal_error(""),
166 m_enable_rollback_recording(false),
169 m_itemdef(createItemDefManager()),
170 m_nodedef(createNodeDefManager()),
171 m_craftdef(createCraftDefManager()),
172 m_event(new EventManager()),
174 m_time_of_day_send_timer(0),
177 m_shutdown_requested(false),
178 m_shutdown_ask_reconnect(false),
180 m_ignore_map_edit_events(false),
181 m_ignore_map_edit_events_peer_id(0),
185 m_liquid_transform_timer = 0.0;
186 m_liquid_transform_every = 1.0;
187 m_print_info_timer = 0.0;
188 m_masterserver_timer = 0.0;
189 m_objectdata_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if(!modconf.isConsistent()) {
229 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
230 it != unsatisfied_mods.end(); ++it) {
232 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
233 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
234 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
235 errorstream << " \"" << *dep_it << "\"";
236 errorstream << std::endl;
240 Settings worldmt_settings;
241 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
242 worldmt_settings.readConfigFile(worldmt.c_str());
243 std::vector<std::string> names = worldmt_settings.getNames();
244 std::set<std::string> load_mod_names;
245 for(std::vector<std::string>::iterator it = names.begin();
246 it != names.end(); ++it) {
247 std::string name = *it;
248 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
249 load_mod_names.insert(name.substr(9));
251 // complain about mods declared to be loaded, but not found
252 for(std::vector<ModSpec>::iterator it = m_mods.begin();
253 it != m_mods.end(); ++it)
254 load_mod_names.erase((*it).name);
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
257 load_mod_names.erase((*it).name);
258 if(!load_mod_names.empty()) {
259 errorstream << "The following mods could not be found:";
260 for(std::set<std::string>::iterator it = load_mod_names.begin();
261 it != load_mod_names.end(); ++it)
262 errorstream << " \"" << (*it) << "\"";
263 errorstream << std::endl;
267 MutexAutoLock envlock(m_env_mutex);
269 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
270 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
272 // Initialize scripting
273 infostream<<"Server: Initializing Lua"<<std::endl;
275 m_script = new GameScripting(this);
277 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
279 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
282 infostream << "Server: Loading mods: ";
283 for(std::vector<ModSpec>::iterator i = m_mods.begin();
284 i != m_mods.end(); ++i) {
285 const ModSpec &mod = *i;
286 infostream << mod.name << " ";
288 infostream << std::endl;
289 // Load and run "mod" scripts
290 for (std::vector<ModSpec>::iterator it = m_mods.begin();
291 it != m_mods.end(); ++it) {
292 const ModSpec &mod = *it;
293 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
294 throw ModError("Error loading mod \"" + mod.name +
295 "\": Mod name does not follow naming conventions: "
296 "Only chararacters [a-z0-9_] are allowed.");
298 std::string script_path = mod.path + DIR_DELIM + "init.lua";
299 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
300 << script_path << "\"]" << std::endl;
301 m_script->loadMod(script_path, mod.name);
304 // Read Textures and calculate sha1 sums
307 // Apply item aliases in the node definition manager
308 m_nodedef->updateAliases(m_itemdef);
310 // Apply texture overrides from texturepack/override.txt
311 std::string texture_path = g_settings->get("texture_path");
312 if (texture_path != "" && fs::IsDir(texture_path))
313 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
315 m_nodedef->setNodeRegistrationStatus(true);
317 // Perform pending node name resolutions
318 m_nodedef->runNodeResolveCallbacks();
320 // unmap node names for connected nodeboxes
321 m_nodedef->mapNodeboxConnections();
323 // init the recipe hashes to speed up crafting
324 m_craftdef->initHashes(this);
326 // Initialize Environment
327 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
329 m_clients.setEnv(m_env);
331 if (!servermap->settings_mgr.makeMapgenParams())
332 FATAL_ERROR("Couldn't create any mapgen type");
334 // Initialize mapgens
335 m_emerge->initMapgens(servermap->getMapgenParams());
337 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
338 if (m_enable_rollback_recording) {
339 // Create rollback manager
340 m_rollback = new RollbackManager(m_path_world, this);
343 // Give environment reference to scripting api
344 m_script->initializeEnvironment(m_env);
346 // Register us to receive map edit events
347 servermap->addEventReceiver(this);
349 // If file exists, load environment metadata
350 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
351 infostream << "Server: Loading environment metadata" << std::endl;
354 m_env->loadDefaultMeta();
357 // Add some test ActiveBlockModifiers to environment
358 add_legacy_abms(m_env, m_nodedef);
360 m_liquid_transform_every = g_settings->getFloat("liquid_update");
361 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
366 infostream<<"Server destructing"<<std::endl;
368 // Send shutdown message
369 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
372 MutexAutoLock envlock(m_env_mutex);
374 // Execute script shutdown hooks
375 m_script->on_shutdown();
377 infostream << "Server: Saving players" << std::endl;
378 m_env->saveLoadedPlayers();
380 infostream << "Server: Kicking players" << std::endl;
381 std::string kick_msg;
382 bool reconnect = false;
383 if (getShutdownRequested()) {
384 reconnect = m_shutdown_ask_reconnect;
385 kick_msg = m_shutdown_msg;
387 if (kick_msg == "") {
388 kick_msg = g_settings->get("kick_msg_shutdown");
390 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
391 kick_msg, reconnect);
393 infostream << "Server: Saving environment metadata" << std::endl;
401 // stop all emerge threads before deleting players that may have
402 // requested blocks to be emerged
403 m_emerge->stopThreads();
405 // Delete things in the reverse order of creation
415 // Deinitialize scripting
416 infostream<<"Server: Deinitializing scripting"<<std::endl;
419 // Delete detached inventories
420 for (std::map<std::string, Inventory*>::iterator
421 i = m_detached_inventories.begin();
422 i != m_detached_inventories.end(); ++i) {
427 void Server::start(Address bind_addr)
429 DSTACK(FUNCTION_NAME);
431 m_bind_addr = bind_addr;
433 infostream<<"Starting server on "
434 << bind_addr.serializeString() <<"..."<<std::endl;
436 // Stop thread if already running
439 // Initialize connection
440 m_con.SetTimeoutMs(30);
441 m_con.Serve(bind_addr);
446 // ASCII art for the win!
448 <<" .__ __ __ "<<std::endl
449 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
450 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
451 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
452 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
453 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
454 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
455 actionstream<<"Server for gameid=\""<<m_gamespec.id
456 <<"\" listening on "<<bind_addr.serializeString()<<":"
457 <<bind_addr.getPort() << "."<<std::endl;
462 DSTACK(FUNCTION_NAME);
464 infostream<<"Server: Stopping and waiting threads"<<std::endl;
466 // Stop threads (set run=false first so both start stopping)
468 //m_emergethread.setRun(false);
470 //m_emergethread.stop();
472 infostream<<"Server: Threads stopped"<<std::endl;
475 void Server::step(float dtime)
477 DSTACK(FUNCTION_NAME);
482 MutexAutoLock lock(m_step_dtime_mutex);
483 m_step_dtime += dtime;
485 // Throw if fatal error occurred in thread
486 std::string async_err = m_async_fatal_error.get();
487 if (!async_err.empty()) {
488 if (!m_simple_singleplayer_mode) {
489 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
490 g_settings->get("kick_msg_crash"),
491 g_settings->getBool("ask_reconnect_on_crash"));
493 throw ServerError(async_err);
497 void Server::AsyncRunStep(bool initial_step)
499 DSTACK(FUNCTION_NAME);
501 g_profiler->add("Server::AsyncRunStep (num)", 1);
505 MutexAutoLock lock1(m_step_dtime_mutex);
506 dtime = m_step_dtime;
510 // Send blocks to clients
514 if((dtime < 0.001) && (initial_step == false))
517 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
519 //infostream<<"Server steps "<<dtime<<std::endl;
520 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
523 MutexAutoLock lock1(m_step_dtime_mutex);
524 m_step_dtime -= dtime;
531 m_uptime.set(m_uptime.get() + dtime);
537 Update time of day and overall game time
539 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
542 Send to clients at constant intervals
545 m_time_of_day_send_timer -= dtime;
546 if(m_time_of_day_send_timer < 0.0) {
547 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
548 u16 time = m_env->getTimeOfDay();
549 float time_speed = g_settings->getFloat("time_speed");
550 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
554 MutexAutoLock lock(m_env_mutex);
555 // Figure out and report maximum lag to environment
556 float max_lag = m_env->getMaxLagEstimate();
557 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
559 if(dtime > 0.1 && dtime > max_lag * 2.0)
560 infostream<<"Server: Maximum lag peaked to "<<dtime
564 m_env->reportMaxLagEstimate(max_lag);
566 ScopeProfiler sp(g_profiler, "SEnv step");
567 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
571 static const float map_timer_and_unload_dtime = 2.92;
572 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
574 MutexAutoLock lock(m_env_mutex);
575 // Run Map's timers and unload unused data
576 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
577 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
578 g_settings->getFloat("server_unload_unused_data_timeout"),
583 Listen to the admin chat, if available
586 if (!m_admin_chat->command_queue.empty()) {
587 MutexAutoLock lock(m_env_mutex);
588 while (!m_admin_chat->command_queue.empty()) {
589 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
590 handleChatInterfaceEvent(evt);
594 m_admin_chat->outgoing_queue.push_back(
595 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
602 /* Transform liquids */
603 m_liquid_transform_timer += dtime;
604 if(m_liquid_transform_timer >= m_liquid_transform_every)
606 m_liquid_transform_timer -= m_liquid_transform_every;
608 MutexAutoLock lock(m_env_mutex);
610 ScopeProfiler sp(g_profiler, "Server: liquid transform");
612 std::map<v3s16, MapBlock*> modified_blocks;
613 m_env->getMap().transformLiquids(modified_blocks);
618 core::map<v3s16, MapBlock*> lighting_modified_blocks;
619 ServerMap &map = ((ServerMap&)m_env->getMap());
620 map.updateLighting(modified_blocks, lighting_modified_blocks);
622 // Add blocks modified by lighting to modified_blocks
623 for(core::map<v3s16, MapBlock*>::Iterator
624 i = lighting_modified_blocks.getIterator();
625 i.atEnd() == false; i++)
627 MapBlock *block = i.getNode()->getValue();
628 modified_blocks.insert(block->getPos(), block);
632 Set the modified blocks unsent for all the clients
634 if(!modified_blocks.empty())
636 SetBlocksNotSent(modified_blocks);
639 m_clients.step(dtime);
641 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
643 // send masterserver announce
645 float &counter = m_masterserver_timer;
646 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
647 g_settings->getBool("server_announce"))
649 ServerList::sendAnnounce(counter ? "update" : "start",
650 m_bind_addr.getPort(),
651 m_clients.getPlayerNames(),
653 m_env->getGameTime(),
656 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
665 Check added and deleted active objects
668 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
669 MutexAutoLock envlock(m_env_mutex);
672 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
673 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
675 // Radius inside which objects are active
676 static const s16 radius =
677 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
679 // Radius inside which players are active
680 static const bool is_transfer_limited =
681 g_settings->exists("unlimited_player_transfer_distance") &&
682 !g_settings->getBool("unlimited_player_transfer_distance");
683 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
684 s16 player_radius = player_transfer_dist;
685 if (player_radius == 0 && is_transfer_limited)
686 player_radius = radius;
688 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
689 i != clients.end(); ++i) {
690 RemoteClient *client = i->second;
692 // If definitions and textures have not been sent, don't
693 // send objects either
694 if (client->getState() < CS_DefinitionsSent)
697 Player *player = m_env->getPlayer(client->peer_id);
698 if (player == NULL) {
699 // This can happen if the client timeouts somehow
700 /*warningstream<<FUNCTION_NAME<<": Client "
702 <<" has no associated player"<<std::endl;*/
706 std::queue<u16> removed_objects;
707 std::queue<u16> added_objects;
708 m_env->getRemovedActiveObjects(player, radius, player_radius,
709 client->m_known_objects, removed_objects);
710 m_env->getAddedActiveObjects(player, radius, player_radius,
711 client->m_known_objects, added_objects);
713 // Ignore if nothing happened
714 if (removed_objects.empty() && added_objects.empty()) {
718 std::string data_buffer;
722 // Handle removed objects
723 writeU16((u8*)buf, removed_objects.size());
724 data_buffer.append(buf, 2);
725 while (!removed_objects.empty()) {
727 u16 id = removed_objects.front();
728 ServerActiveObject* obj = m_env->getActiveObject(id);
730 // Add to data buffer for sending
731 writeU16((u8*)buf, id);
732 data_buffer.append(buf, 2);
734 // Remove from known objects
735 client->m_known_objects.erase(id);
737 if(obj && obj->m_known_by_count > 0)
738 obj->m_known_by_count--;
739 removed_objects.pop();
742 // Handle added objects
743 writeU16((u8*)buf, added_objects.size());
744 data_buffer.append(buf, 2);
745 while (!added_objects.empty()) {
747 u16 id = added_objects.front();
748 ServerActiveObject* obj = m_env->getActiveObject(id);
751 u8 type = ACTIVEOBJECT_TYPE_INVALID;
753 warningstream<<FUNCTION_NAME
754 <<": NULL object"<<std::endl;
756 type = obj->getSendType();
758 // Add to data buffer for sending
759 writeU16((u8*)buf, id);
760 data_buffer.append(buf, 2);
761 writeU8((u8*)buf, type);
762 data_buffer.append(buf, 1);
765 data_buffer.append(serializeLongString(
766 obj->getClientInitializationData(client->net_proto_version)));
768 data_buffer.append(serializeLongString(""));
770 // Add to known objects
771 client->m_known_objects.insert(id);
774 obj->m_known_by_count++;
779 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
780 verbosestream << "Server: Sent object remove/add: "
781 << removed_objects.size() << " removed, "
782 << added_objects.size() << " added, "
783 << "packet size is " << pktSize << std::endl;
792 MutexAutoLock envlock(m_env_mutex);
793 ScopeProfiler sp(g_profiler, "Server: sending object messages");
796 // Value = data sent by object
797 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
799 // Get active object messages from environment
801 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
805 std::vector<ActiveObjectMessage>* message_list = NULL;
806 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
807 n = buffered_messages.find(aom.id);
808 if (n == buffered_messages.end()) {
809 message_list = new std::vector<ActiveObjectMessage>;
810 buffered_messages[aom.id] = message_list;
813 message_list = n->second;
815 message_list->push_back(aom);
819 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
820 // Route data to every client
821 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
822 i != clients.end(); ++i) {
823 RemoteClient *client = i->second;
824 std::string reliable_data;
825 std::string unreliable_data;
826 // Go through all objects in message buffer
827 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
828 j = buffered_messages.begin();
829 j != buffered_messages.end(); ++j) {
830 // If object is not known by client, skip it
832 if (client->m_known_objects.find(id) == client->m_known_objects.end())
835 // Get message list of object
836 std::vector<ActiveObjectMessage>* list = j->second;
837 // Go through every message
838 for (std::vector<ActiveObjectMessage>::iterator
839 k = list->begin(); k != list->end(); ++k) {
840 // Compose the full new data with header
841 ActiveObjectMessage aom = *k;
842 std::string new_data;
845 writeU16((u8*)&buf[0], aom.id);
846 new_data.append(buf, 2);
848 new_data += serializeString(aom.datastring);
849 // Add data to buffer
851 reliable_data += new_data;
853 unreliable_data += new_data;
857 reliable_data and unreliable_data are now ready.
860 if(reliable_data.size() > 0) {
861 SendActiveObjectMessages(client->peer_id, reliable_data);
864 if(unreliable_data.size() > 0) {
865 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
870 // Clear buffered_messages
871 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
872 i = buffered_messages.begin();
873 i != buffered_messages.end(); ++i) {
879 Send queued-for-sending map edit events.
882 // We will be accessing the environment
883 MutexAutoLock lock(m_env_mutex);
885 // Don't send too many at a time
888 // Single change sending is disabled if queue size is not small
889 bool disable_single_change_sending = false;
890 if(m_unsent_map_edit_queue.size() >= 4)
891 disable_single_change_sending = true;
893 int event_count = m_unsent_map_edit_queue.size();
895 // We'll log the amount of each
898 while(m_unsent_map_edit_queue.size() != 0)
900 MapEditEvent* event = m_unsent_map_edit_queue.front();
901 m_unsent_map_edit_queue.pop();
903 // Players far away from the change are stored here.
904 // Instead of sending the changes, MapBlocks are set not sent
906 std::vector<u16> far_players;
908 switch (event->type) {
911 prof.add("MEET_ADDNODE", 1);
912 sendAddNode(event->p, event->n, event->already_known_by_peer,
913 &far_players, disable_single_change_sending ? 5 : 30,
914 event->type == MEET_ADDNODE);
916 case MEET_REMOVENODE:
917 prof.add("MEET_REMOVENODE", 1);
918 sendRemoveNode(event->p, event->already_known_by_peer,
919 &far_players, disable_single_change_sending ? 5 : 30);
921 case MEET_BLOCK_NODE_METADATA_CHANGED:
922 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
923 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
924 setBlockNotSent(event->p);
927 infostream << "Server: MEET_OTHER" << std::endl;
928 prof.add("MEET_OTHER", 1);
929 for(std::set<v3s16>::iterator
930 i = event->modified_blocks.begin();
931 i != event->modified_blocks.end(); ++i) {
936 prof.add("unknown", 1);
937 warningstream << "Server: Unknown MapEditEvent "
938 << ((u32)event->type) << std::endl;
943 Set blocks not sent to far players
945 if(!far_players.empty()) {
946 // Convert list format to that wanted by SetBlocksNotSent
947 std::map<v3s16, MapBlock*> modified_blocks2;
948 for(std::set<v3s16>::iterator
949 i = event->modified_blocks.begin();
950 i != event->modified_blocks.end(); ++i) {
951 modified_blocks2[*i] =
952 m_env->getMap().getBlockNoCreateNoEx(*i);
955 // Set blocks not sent
956 for(std::vector<u16>::iterator
957 i = far_players.begin();
958 i != far_players.end(); ++i) {
959 if(RemoteClient *client = getClient(*i))
960 client->SetBlocksNotSent(modified_blocks2);
966 /*// Don't send too many at a time
968 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
972 if(event_count >= 5){
973 infostream<<"Server: MapEditEvents:"<<std::endl;
974 prof.print(infostream);
975 } else if(event_count != 0){
976 verbosestream<<"Server: MapEditEvents:"<<std::endl;
977 prof.print(verbosestream);
983 Trigger emergethread (it somehow gets to a non-triggered but
984 bysy state sometimes)
987 float &counter = m_emergethread_trigger_timer;
989 if (counter >= 2.0) {
992 m_emerge->startThreads();
996 // Save map, players and auth stuff
998 float &counter = m_savemap_timer;
1000 static const float save_interval =
1001 g_settings->getFloat("server_map_save_interval");
1002 if (counter >= save_interval) {
1004 MutexAutoLock lock(m_env_mutex);
1006 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1009 if (m_banmanager->isModified()) {
1010 m_banmanager->save();
1013 // Save changed parts of map
1014 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1017 m_env->saveLoadedPlayers();
1019 // Save environment metadata
1025 void Server::Receive()
1027 DSTACK(FUNCTION_NAME);
1028 SharedBuffer<u8> data;
1032 m_con.Receive(&pkt);
1033 peer_id = pkt.getPeerId();
1036 catch(con::InvalidIncomingDataException &e) {
1037 infostream<<"Server::Receive(): "
1038 "InvalidIncomingDataException: what()="
1039 <<e.what()<<std::endl;
1041 catch(SerializationError &e) {
1042 infostream<<"Server::Receive(): "
1043 "SerializationError: what()="
1044 <<e.what()<<std::endl;
1046 catch(ClientStateError &e) {
1047 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1048 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1049 L"Try reconnecting or updating your client");
1051 catch(con::PeerNotFoundException &e) {
1056 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1058 std::string playername = "";
1059 PlayerSAO *playersao = NULL;
1062 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1063 if (client != NULL) {
1064 playername = client->getName();
1065 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1067 } catch (std::exception &e) {
1073 RemotePlayer *player =
1074 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1076 // If failed, cancel
1077 if ((playersao == NULL) || (player == NULL)) {
1078 if (player && player->peer_id != 0) {
1079 actionstream << "Server: Failed to emerge player \"" << playername
1080 << "\" (player allocated to an another client)" << std::endl;
1081 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1082 L"name. If your client closed unexpectedly, try again in "
1085 errorstream << "Server: " << playername << ": Failed to emerge player"
1087 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1093 Send complete position information
1095 SendMovePlayer(peer_id);
1098 SendPlayerPrivileges(peer_id);
1100 // Send inventory formspec
1101 SendPlayerInventoryFormspec(peer_id);
1104 SendInventory(playersao);
1107 SendPlayerHPOrDie(playersao);
1110 SendPlayerBreath(peer_id);
1112 // Show death screen if necessary
1113 if(player->isDead())
1114 SendDeathscreen(peer_id, false, v3f(0,0,0));
1116 // Note things in chat if not in simple singleplayer mode
1117 if(!m_simple_singleplayer_mode) {
1118 // Send information about server to player in chat
1119 SendChatMessage(peer_id, getStatusString());
1121 Address addr = getPeerAddress(player->peer_id);
1122 std::string ip_str = addr.serializeString();
1123 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1128 std::vector<std::string> names = m_clients.getPlayerNames();
1130 actionstream<<player->getName() <<" joins game. List of players: ";
1132 for (std::vector<std::string>::iterator i = names.begin();
1133 i != names.end(); ++i) {
1134 actionstream << *i << " ";
1137 actionstream << player->getName() <<std::endl;
1142 inline void Server::handleCommand(NetworkPacket* pkt)
1144 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1145 (this->*opHandle.handler)(pkt);
1148 void Server::ProcessData(NetworkPacket *pkt)
1150 DSTACK(FUNCTION_NAME);
1151 // Environment is locked first.
1152 MutexAutoLock envlock(m_env_mutex);
1154 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1155 u32 peer_id = pkt->getPeerId();
1158 Address address = getPeerAddress(peer_id);
1159 std::string addr_s = address.serializeString();
1161 if(m_banmanager->isIpBanned(addr_s)) {
1162 std::string ban_name = m_banmanager->getBanName(addr_s);
1163 infostream << "Server: A banned client tried to connect from "
1164 << addr_s << "; banned name was "
1165 << ban_name << std::endl;
1166 // This actually doesn't seem to transfer to the client
1167 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1168 + utf8_to_wide(ban_name));
1172 catch(con::PeerNotFoundException &e) {
1174 * no peer for this packet found
1175 * most common reason is peer timeout, e.g. peer didn't
1176 * respond for some time, your server was overloaded or
1179 infostream << "Server::ProcessData(): Canceling: peer "
1180 << peer_id << " not found" << std::endl;
1185 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1187 // Command must be handled into ToServerCommandHandler
1188 if (command >= TOSERVER_NUM_MSG_TYPES) {
1189 infostream << "Server: Ignoring unknown command "
1190 << command << std::endl;
1194 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1199 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1201 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1202 errorstream << "Server::ProcessData(): Cancelling: Peer"
1203 " serialization format invalid or not initialized."
1204 " Skipping incoming command=" << command << std::endl;
1208 /* Handle commands related to client startup */
1209 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1214 if (m_clients.getClientState(peer_id) < CS_Active) {
1215 if (command == TOSERVER_PLAYERPOS) return;
1217 errorstream << "Got packet command: " << command << " for peer id "
1218 << peer_id << " but client isn't active yet. Dropping packet "
1224 } catch (SendFailedException &e) {
1225 errorstream << "Server::ProcessData(): SendFailedException: "
1226 << "what=" << e.what()
1228 } catch (PacketError &e) {
1229 actionstream << "Server::ProcessData(): PacketError: "
1230 << "what=" << e.what()
1235 void Server::setTimeOfDay(u32 time)
1237 m_env->setTimeOfDay(time);
1238 m_time_of_day_send_timer = 0;
1241 void Server::onMapEditEvent(MapEditEvent *event)
1243 if(m_ignore_map_edit_events)
1245 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1247 MapEditEvent *e = event->clone();
1248 m_unsent_map_edit_queue.push(e);
1251 Inventory* Server::getInventory(const InventoryLocation &loc)
1254 case InventoryLocation::UNDEFINED:
1255 case InventoryLocation::CURRENT_PLAYER:
1257 case InventoryLocation::PLAYER:
1259 Player *player = m_env->getPlayer(loc.name.c_str());
1262 PlayerSAO *playersao = player->getPlayerSAO();
1265 return playersao->getInventory();
1268 case InventoryLocation::NODEMETA:
1270 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1273 return meta->getInventory();
1276 case InventoryLocation::DETACHED:
1278 if(m_detached_inventories.count(loc.name) == 0)
1280 return m_detached_inventories[loc.name];
1284 sanity_check(false); // abort
1289 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1292 case InventoryLocation::UNDEFINED:
1294 case InventoryLocation::PLAYER:
1299 Player *player = m_env->getPlayer(loc.name.c_str());
1302 PlayerSAO *playersao = player->getPlayerSAO();
1306 SendInventory(playersao);
1309 case InventoryLocation::NODEMETA:
1311 v3s16 blockpos = getNodeBlockPos(loc.p);
1313 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1315 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1317 setBlockNotSent(blockpos);
1320 case InventoryLocation::DETACHED:
1322 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1326 sanity_check(false); // abort
1331 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1333 std::vector<u16> clients = m_clients.getClientIDs();
1335 // Set the modified blocks unsent for all the clients
1336 for (std::vector<u16>::iterator i = clients.begin();
1337 i != clients.end(); ++i) {
1338 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1339 client->SetBlocksNotSent(block);
1344 void Server::peerAdded(con::Peer *peer)
1346 DSTACK(FUNCTION_NAME);
1347 verbosestream<<"Server::peerAdded(): peer->id="
1348 <<peer->id<<std::endl;
1351 c.type = con::PEER_ADDED;
1352 c.peer_id = peer->id;
1354 m_peer_change_queue.push(c);
1357 void Server::deletingPeer(con::Peer *peer, bool timeout)
1359 DSTACK(FUNCTION_NAME);
1360 verbosestream<<"Server::deletingPeer(): peer->id="
1361 <<peer->id<<", timeout="<<timeout<<std::endl;
1363 m_clients.event(peer->id, CSE_Disconnect);
1365 c.type = con::PEER_REMOVED;
1366 c.peer_id = peer->id;
1367 c.timeout = timeout;
1368 m_peer_change_queue.push(c);
1371 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1373 *retval = m_con.getPeerStat(peer_id,type);
1374 if (*retval == -1) return false;
1378 bool Server::getClientInfo(
1387 std::string* vers_string
1390 *state = m_clients.getClientState(peer_id);
1392 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1394 if (client == NULL) {
1399 *uptime = client->uptime();
1400 *ser_vers = client->serialization_version;
1401 *prot_vers = client->net_proto_version;
1403 *major = client->getMajor();
1404 *minor = client->getMinor();
1405 *patch = client->getPatch();
1406 *vers_string = client->getPatch();
1413 void Server::handlePeerChanges()
1415 while(m_peer_change_queue.size() > 0)
1417 con::PeerChange c = m_peer_change_queue.front();
1418 m_peer_change_queue.pop();
1420 verbosestream<<"Server: Handling peer change: "
1421 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1426 case con::PEER_ADDED:
1427 m_clients.CreateClient(c.peer_id);
1430 case con::PEER_REMOVED:
1431 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1435 FATAL_ERROR("Invalid peer change event received!");
1441 void Server::printToConsoleOnly(const std::string &text)
1444 m_admin_chat->outgoing_queue.push_back(
1445 new ChatEventChat("", utf8_to_wide(text)));
1447 std::cout << text << std::endl;
1451 void Server::Send(NetworkPacket* pkt)
1453 m_clients.send(pkt->getPeerId(),
1454 clientCommandFactoryTable[pkt->getCommand()].channel,
1456 clientCommandFactoryTable[pkt->getCommand()].reliable);
1459 void Server::SendMovement(u16 peer_id)
1461 DSTACK(FUNCTION_NAME);
1462 std::ostringstream os(std::ios_base::binary);
1464 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1466 pkt << g_settings->getFloat("movement_acceleration_default");
1467 pkt << g_settings->getFloat("movement_acceleration_air");
1468 pkt << g_settings->getFloat("movement_acceleration_fast");
1469 pkt << g_settings->getFloat("movement_speed_walk");
1470 pkt << g_settings->getFloat("movement_speed_crouch");
1471 pkt << g_settings->getFloat("movement_speed_fast");
1472 pkt << g_settings->getFloat("movement_speed_climb");
1473 pkt << g_settings->getFloat("movement_speed_jump");
1474 pkt << g_settings->getFloat("movement_liquid_fluidity");
1475 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1476 pkt << g_settings->getFloat("movement_liquid_sink");
1477 pkt << g_settings->getFloat("movement_gravity");
1482 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1484 if (!g_settings->getBool("enable_damage"))
1487 u16 peer_id = playersao->getPeerID();
1488 bool is_alive = playersao->getHP() > 0;
1491 SendPlayerHP(peer_id);
1496 void Server::SendHP(u16 peer_id, u8 hp)
1498 DSTACK(FUNCTION_NAME);
1500 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1505 void Server::SendBreath(u16 peer_id, u16 breath)
1507 DSTACK(FUNCTION_NAME);
1509 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1510 pkt << (u16) breath;
1514 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1515 const std::string &custom_reason, bool reconnect)
1517 assert(reason < SERVER_ACCESSDENIED_MAX);
1519 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1521 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1522 pkt << custom_reason;
1523 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1524 reason == SERVER_ACCESSDENIED_CRASH)
1525 pkt << custom_reason << (u8)reconnect;
1529 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1531 DSTACK(FUNCTION_NAME);
1533 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1538 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1539 v3f camera_point_target)
1541 DSTACK(FUNCTION_NAME);
1543 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1544 pkt << set_camera_point_target << camera_point_target;
1548 void Server::SendItemDef(u16 peer_id,
1549 IItemDefManager *itemdef, u16 protocol_version)
1551 DSTACK(FUNCTION_NAME);
1553 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1557 u32 length of the next item
1558 zlib-compressed serialized ItemDefManager
1560 std::ostringstream tmp_os(std::ios::binary);
1561 itemdef->serialize(tmp_os, protocol_version);
1562 std::ostringstream tmp_os2(std::ios::binary);
1563 compressZlib(tmp_os.str(), tmp_os2);
1564 pkt.putLongString(tmp_os2.str());
1567 verbosestream << "Server: Sending item definitions to id(" << peer_id
1568 << "): size=" << pkt.getSize() << std::endl;
1573 void Server::SendNodeDef(u16 peer_id,
1574 INodeDefManager *nodedef, u16 protocol_version)
1576 DSTACK(FUNCTION_NAME);
1578 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1582 u32 length of the next item
1583 zlib-compressed serialized NodeDefManager
1585 std::ostringstream tmp_os(std::ios::binary);
1586 nodedef->serialize(tmp_os, protocol_version);
1587 std::ostringstream tmp_os2(std::ios::binary);
1588 compressZlib(tmp_os.str(), tmp_os2);
1590 pkt.putLongString(tmp_os2.str());
1593 verbosestream << "Server: Sending node definitions to id(" << peer_id
1594 << "): size=" << pkt.getSize() << std::endl;
1600 Non-static send methods
1603 void Server::SendInventory(PlayerSAO* playerSAO)
1605 DSTACK(FUNCTION_NAME);
1607 UpdateCrafting(playerSAO->getPlayer());
1613 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1615 std::ostringstream os;
1616 playerSAO->getInventory()->serialize(os);
1618 std::string s = os.str();
1620 pkt.putRawString(s.c_str(), s.size());
1624 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1626 DSTACK(FUNCTION_NAME);
1628 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1631 if (peer_id != PEER_ID_INEXISTENT) {
1635 m_clients.sendToAll(0, &pkt, true);
1639 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1640 const std::string &formname)
1642 DSTACK(FUNCTION_NAME);
1644 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1646 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1652 // Spawns a particle on peer with peer_id
1653 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1654 float expirationtime, float size, bool collisiondetection,
1655 bool collision_removal,
1656 bool vertical, const std::string &texture)
1658 DSTACK(FUNCTION_NAME);
1660 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1662 pkt << pos << velocity << acceleration << expirationtime
1663 << size << collisiondetection;
1664 pkt.putLongString(texture);
1666 pkt << collision_removal;
1668 if (peer_id != PEER_ID_INEXISTENT) {
1672 m_clients.sendToAll(0, &pkt, true);
1676 // Adds a ParticleSpawner on peer with peer_id
1677 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1678 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1679 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1680 bool vertical, const std::string &texture, u32 id)
1682 DSTACK(FUNCTION_NAME);
1684 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1686 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1687 << minacc << maxacc << minexptime << maxexptime << minsize
1688 << maxsize << collisiondetection;
1690 pkt.putLongString(texture);
1692 pkt << id << vertical;
1693 pkt << collision_removal;
1695 if (peer_id != PEER_ID_INEXISTENT) {
1699 m_clients.sendToAll(0, &pkt, true);
1703 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1705 DSTACK(FUNCTION_NAME);
1707 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1709 // Ugly error in this packet
1712 if (peer_id != PEER_ID_INEXISTENT) {
1716 m_clients.sendToAll(0, &pkt, true);
1721 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1723 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1725 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1726 << form->text << form->number << form->item << form->dir
1727 << form->align << form->offset << form->world_pos << form->size;
1732 void Server::SendHUDRemove(u16 peer_id, u32 id)
1734 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1739 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1741 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1742 pkt << id << (u8) stat;
1746 case HUD_STAT_SCALE:
1747 case HUD_STAT_ALIGN:
1748 case HUD_STAT_OFFSET:
1749 pkt << *(v2f *) value;
1753 pkt << *(std::string *) value;
1755 case HUD_STAT_WORLD_POS:
1756 pkt << *(v3f *) value;
1759 pkt << *(v2s32 *) value;
1761 case HUD_STAT_NUMBER:
1765 pkt << *(u32 *) value;
1772 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1774 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1776 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1778 pkt << flags << mask;
1783 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1785 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1786 pkt << param << value;
1790 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1791 const std::string &type, const std::vector<std::string> ¶ms)
1793 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1794 pkt << bgcolor << type << (u16) params.size();
1796 for(size_t i=0; i<params.size(); i++)
1802 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1805 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1808 pkt << do_override << (u16) (ratio * 65535);
1813 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1815 DSTACK(FUNCTION_NAME);
1817 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1818 pkt << time << time_speed;
1820 if (peer_id == PEER_ID_INEXISTENT) {
1821 m_clients.sendToAll(0, &pkt, true);
1828 void Server::SendPlayerHP(u16 peer_id)
1830 DSTACK(FUNCTION_NAME);
1831 PlayerSAO *playersao = getPlayerSAO(peer_id);
1832 // In some rare case if the player is disconnected
1833 // while Lua call l_punch, for example, this can be NULL
1837 SendHP(peer_id, playersao->getHP());
1838 m_script->player_event(playersao,"health_changed");
1840 // Send to other clients
1841 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1842 ActiveObjectMessage aom(playersao->getId(), true, str);
1843 playersao->m_messages_out.push(aom);
1846 void Server::SendPlayerBreath(u16 peer_id)
1848 DSTACK(FUNCTION_NAME);
1849 PlayerSAO *playersao = getPlayerSAO(peer_id);
1852 m_script->player_event(playersao, "breath_changed");
1853 SendBreath(peer_id, playersao->getBreath());
1856 void Server::SendMovePlayer(u16 peer_id)
1858 DSTACK(FUNCTION_NAME);
1859 Player *player = m_env->getPlayer(peer_id);
1862 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1863 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1866 v3f pos = player->getPosition();
1867 f32 pitch = player->getPitch();
1868 f32 yaw = player->getYaw();
1869 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1870 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1871 << " pitch=" << pitch
1879 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1881 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1884 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1885 << animation_frames[3] << animation_speed;
1890 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1892 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1893 pkt << first << third;
1896 void Server::SendPlayerPrivileges(u16 peer_id)
1898 Player *player = m_env->getPlayer(peer_id);
1900 if(player->peer_id == PEER_ID_INEXISTENT)
1903 std::set<std::string> privs;
1904 m_script->getAuth(player->getName(), NULL, &privs);
1906 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1907 pkt << (u16) privs.size();
1909 for(std::set<std::string>::const_iterator i = privs.begin();
1910 i != privs.end(); ++i) {
1917 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1919 Player *player = m_env->getPlayer(peer_id);
1921 if(player->peer_id == PEER_ID_INEXISTENT)
1924 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1925 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1929 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1931 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1932 pkt.putRawString(datas.c_str(), datas.size());
1934 return pkt.getSize();
1937 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1939 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1940 datas.size(), peer_id);
1942 pkt.putRawString(datas.c_str(), datas.size());
1944 m_clients.send(pkt.getPeerId(),
1945 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1950 s32 Server::playSound(const SimpleSoundSpec &spec,
1951 const ServerSoundParams ¶ms)
1953 // Find out initial position of sound
1954 bool pos_exists = false;
1955 v3f pos = params.getPos(m_env, &pos_exists);
1956 // If position is not found while it should be, cancel sound
1957 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1960 // Filter destination clients
1961 std::vector<u16> dst_clients;
1962 if(params.to_player != "")
1964 Player *player = m_env->getPlayer(params.to_player.c_str());
1966 infostream<<"Server::playSound: Player \""<<params.to_player
1967 <<"\" not found"<<std::endl;
1970 if(player->peer_id == PEER_ID_INEXISTENT){
1971 infostream<<"Server::playSound: Player \""<<params.to_player
1972 <<"\" not connected"<<std::endl;
1975 dst_clients.push_back(player->peer_id);
1978 std::vector<u16> clients = m_clients.getClientIDs();
1980 for(std::vector<u16>::iterator
1981 i = clients.begin(); i != clients.end(); ++i) {
1982 Player *player = m_env->getPlayer(*i);
1987 if(player->getPosition().getDistanceFrom(pos) >
1988 params.max_hear_distance)
1991 dst_clients.push_back(*i);
1995 if(dst_clients.empty())
1999 s32 id = m_next_sound_id++;
2000 // The sound will exist as a reference in m_playing_sounds
2001 m_playing_sounds[id] = ServerPlayingSound();
2002 ServerPlayingSound &psound = m_playing_sounds[id];
2003 psound.params = params;
2005 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2006 pkt << id << spec.name << (float) (spec.gain * params.gain)
2007 << (u8) params.type << pos << params.object << params.loop;
2009 for(std::vector<u16>::iterator i = dst_clients.begin();
2010 i != dst_clients.end(); ++i) {
2011 psound.clients.insert(*i);
2012 m_clients.send(*i, 0, &pkt, true);
2016 void Server::stopSound(s32 handle)
2018 // Get sound reference
2019 std::map<s32, ServerPlayingSound>::iterator i =
2020 m_playing_sounds.find(handle);
2021 if(i == m_playing_sounds.end())
2023 ServerPlayingSound &psound = i->second;
2025 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2028 for(std::set<u16>::iterator i = psound.clients.begin();
2029 i != psound.clients.end(); ++i) {
2031 m_clients.send(*i, 0, &pkt, true);
2033 // Remove sound reference
2034 m_playing_sounds.erase(i);
2037 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2038 std::vector<u16> *far_players, float far_d_nodes)
2040 float maxd = far_d_nodes*BS;
2041 v3f p_f = intToFloat(p, BS);
2043 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2046 std::vector<u16> clients = m_clients.getClientIDs();
2047 for(std::vector<u16>::iterator i = clients.begin();
2048 i != clients.end(); ++i) {
2051 if(Player *player = m_env->getPlayer(*i)) {
2052 // If player is far away, only set modified blocks not sent
2053 v3f player_pos = player->getPosition();
2054 if(player_pos.getDistanceFrom(p_f) > maxd) {
2055 far_players->push_back(*i);
2062 m_clients.send(*i, 0, &pkt, true);
2066 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2067 std::vector<u16> *far_players, float far_d_nodes,
2068 bool remove_metadata)
2070 float maxd = far_d_nodes*BS;
2071 v3f p_f = intToFloat(p, BS);
2073 std::vector<u16> clients = m_clients.getClientIDs();
2074 for(std::vector<u16>::iterator i = clients.begin();
2075 i != clients.end(); ++i) {
2079 if(Player *player = m_env->getPlayer(*i)) {
2080 // If player is far away, only set modified blocks not sent
2081 v3f player_pos = player->getPosition();
2082 if(player_pos.getDistanceFrom(p_f) > maxd) {
2083 far_players->push_back(*i);
2089 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2091 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2093 pkt << p << n.param0 << n.param1 << n.param2
2094 << (u8) (remove_metadata ? 0 : 1);
2096 if (!remove_metadata) {
2097 if (client->net_proto_version <= 21) {
2098 // Old clients always clear metadata; fix it
2099 // by sending the full block again.
2100 client->SetBlockNotSent(getNodeBlockPos(p));
2107 if (pkt.getSize() > 0)
2108 m_clients.send(*i, 0, &pkt, true);
2112 void Server::setBlockNotSent(v3s16 p)
2114 std::vector<u16> clients = m_clients.getClientIDs();
2116 for(std::vector<u16>::iterator i = clients.begin();
2117 i != clients.end(); ++i) {
2118 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2119 client->SetBlockNotSent(p);
2124 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2126 DSTACK(FUNCTION_NAME);
2128 v3s16 p = block->getPos();
2131 Create a packet with the block in the right format
2134 std::ostringstream os(std::ios_base::binary);
2135 block->serialize(os, ver, false);
2136 block->serializeNetworkSpecific(os, net_proto_version);
2137 std::string s = os.str();
2139 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2142 pkt.putRawString(s.c_str(), s.size());
2146 void Server::SendBlocks(float dtime)
2148 DSTACK(FUNCTION_NAME);
2150 MutexAutoLock envlock(m_env_mutex);
2151 //TODO check if one big lock could be faster then multiple small ones
2153 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2155 std::vector<PrioritySortedBlockTransfer> queue;
2157 s32 total_sending = 0;
2160 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2162 std::vector<u16> clients = m_clients.getClientIDs();
2165 for(std::vector<u16>::iterator i = clients.begin();
2166 i != clients.end(); ++i) {
2167 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2172 total_sending += client->SendingCount();
2173 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2179 // Lowest priority number comes first.
2180 // Lowest is most important.
2181 std::sort(queue.begin(), queue.end());
2184 for(u32 i=0; i<queue.size(); i++)
2186 //TODO: Calculate limit dynamically
2187 if(total_sending >= g_settings->getS32
2188 ("max_simultaneous_block_sends_server_total"))
2191 PrioritySortedBlockTransfer q = queue[i];
2193 MapBlock *block = NULL;
2196 block = m_env->getMap().getBlockNoCreate(q.pos);
2198 catch(InvalidPositionException &e)
2203 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2208 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2210 client->SentBlock(q.pos);
2216 void Server::fillMediaCache()
2218 DSTACK(FUNCTION_NAME);
2220 infostream<<"Server: Calculating media file checksums"<<std::endl;
2222 // Collect all media file paths
2223 std::vector<std::string> paths;
2224 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2225 i != m_mods.end(); ++i) {
2226 const ModSpec &mod = *i;
2227 paths.push_back(mod.path + DIR_DELIM + "textures");
2228 paths.push_back(mod.path + DIR_DELIM + "sounds");
2229 paths.push_back(mod.path + DIR_DELIM + "media");
2230 paths.push_back(mod.path + DIR_DELIM + "models");
2232 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2234 // Collect media file information from paths into cache
2235 for(std::vector<std::string>::iterator i = paths.begin();
2236 i != paths.end(); ++i) {
2237 std::string mediapath = *i;
2238 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2239 for (u32 j = 0; j < dirlist.size(); j++) {
2240 if (dirlist[j].dir) // Ignode dirs
2242 std::string filename = dirlist[j].name;
2243 // If name contains illegal characters, ignore the file
2244 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2245 infostream<<"Server: ignoring illegal file name: \""
2246 << filename << "\"" << std::endl;
2249 // If name is not in a supported format, ignore it
2250 const char *supported_ext[] = {
2251 ".png", ".jpg", ".bmp", ".tga",
2252 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2254 ".x", ".b3d", ".md2", ".obj",
2257 if (removeStringEnd(filename, supported_ext) == ""){
2258 infostream << "Server: ignoring unsupported file extension: \""
2259 << filename << "\"" << std::endl;
2262 // Ok, attempt to load the file and add to cache
2263 std::string filepath = mediapath + DIR_DELIM + filename;
2265 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2267 errorstream << "Server::fillMediaCache(): Could not open \""
2268 << filename << "\" for reading" << std::endl;
2271 std::ostringstream tmp_os(std::ios_base::binary);
2275 fis.read(buf, 1024);
2276 std::streamsize len = fis.gcount();
2277 tmp_os.write(buf, len);
2286 errorstream<<"Server::fillMediaCache(): Failed to read \""
2287 << filename << "\"" << std::endl;
2290 if(tmp_os.str().length() == 0) {
2291 errorstream << "Server::fillMediaCache(): Empty file \""
2292 << filepath << "\"" << std::endl;
2297 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2299 unsigned char *digest = sha1.getDigest();
2300 std::string sha1_base64 = base64_encode(digest, 20);
2301 std::string sha1_hex = hex_encode((char*)digest, 20);
2305 m_media[filename] = MediaInfo(filepath, sha1_base64);
2306 verbosestream << "Server: " << sha1_hex << " is " << filename
2312 void Server::sendMediaAnnouncement(u16 peer_id)
2314 DSTACK(FUNCTION_NAME);
2316 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2320 std::ostringstream os(std::ios_base::binary);
2322 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2323 pkt << (u16) m_media.size();
2325 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2326 i != m_media.end(); ++i) {
2327 pkt << i->first << i->second.sha1_digest;
2330 pkt << g_settings->get("remote_media");
2334 struct SendableMedia
2340 SendableMedia(const std::string &name_="", const std::string &path_="",
2341 const std::string &data_=""):
2348 void Server::sendRequestedMedia(u16 peer_id,
2349 const std::vector<std::string> &tosend)
2351 DSTACK(FUNCTION_NAME);
2353 verbosestream<<"Server::sendRequestedMedia(): "
2354 <<"Sending files to client"<<std::endl;
2358 // Put 5kB in one bunch (this is not accurate)
2359 u32 bytes_per_bunch = 5000;
2361 std::vector< std::vector<SendableMedia> > file_bunches;
2362 file_bunches.push_back(std::vector<SendableMedia>());
2364 u32 file_size_bunch_total = 0;
2366 for(std::vector<std::string>::const_iterator i = tosend.begin();
2367 i != tosend.end(); ++i) {
2368 const std::string &name = *i;
2370 if(m_media.find(name) == m_media.end()) {
2371 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2372 <<"unknown file \""<<(name)<<"\""<<std::endl;
2376 //TODO get path + name
2377 std::string tpath = m_media[name].path;
2380 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2381 if(fis.good() == false){
2382 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2383 <<tpath<<"\" for reading"<<std::endl;
2386 std::ostringstream tmp_os(std::ios_base::binary);
2390 fis.read(buf, 1024);
2391 std::streamsize len = fis.gcount();
2392 tmp_os.write(buf, len);
2393 file_size_bunch_total += len;
2402 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2403 <<name<<"\""<<std::endl;
2406 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2407 <<tname<<"\""<<std::endl;*/
2409 file_bunches[file_bunches.size()-1].push_back(
2410 SendableMedia(name, tpath, tmp_os.str()));
2412 // Start next bunch if got enough data
2413 if(file_size_bunch_total >= bytes_per_bunch) {
2414 file_bunches.push_back(std::vector<SendableMedia>());
2415 file_size_bunch_total = 0;
2420 /* Create and send packets */
2422 u16 num_bunches = file_bunches.size();
2423 for(u16 i = 0; i < num_bunches; i++) {
2426 u16 total number of texture bunches
2427 u16 index of this bunch
2428 u32 number of files in this bunch
2437 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2438 pkt << num_bunches << i << (u32) file_bunches[i].size();
2440 for(std::vector<SendableMedia>::iterator
2441 j = file_bunches[i].begin();
2442 j != file_bunches[i].end(); ++j) {
2444 pkt.putLongString(j->data);
2447 verbosestream << "Server::sendRequestedMedia(): bunch "
2448 << i << "/" << num_bunches
2449 << " files=" << file_bunches[i].size()
2450 << " size=" << pkt.getSize() << std::endl;
2455 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2457 if(m_detached_inventories.count(name) == 0) {
2458 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2461 Inventory *inv = m_detached_inventories[name];
2462 std::ostringstream os(std::ios_base::binary);
2464 os << serializeString(name);
2468 std::string s = os.str();
2470 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2471 pkt.putRawString(s.c_str(), s.size());
2473 if (peer_id != PEER_ID_INEXISTENT) {
2477 m_clients.sendToAll(0, &pkt, true);
2481 void Server::sendDetachedInventories(u16 peer_id)
2483 DSTACK(FUNCTION_NAME);
2485 for(std::map<std::string, Inventory*>::iterator
2486 i = m_detached_inventories.begin();
2487 i != m_detached_inventories.end(); ++i) {
2488 const std::string &name = i->first;
2489 //Inventory *inv = i->second;
2490 sendDetachedInventory(name, peer_id);
2498 void Server::DiePlayer(u16 peer_id)
2500 DSTACK(FUNCTION_NAME);
2501 PlayerSAO *playersao = getPlayerSAO(peer_id);
2502 // In some rare cases this can be NULL -- if the player is disconnected
2503 // when a Lua function modifies l_punch, for example
2507 infostream << "Server::DiePlayer(): Player "
2508 << playersao->getPlayer()->getName()
2509 << " dies" << std::endl;
2511 playersao->setHP(0);
2513 // Trigger scripted stuff
2514 m_script->on_dieplayer(playersao);
2516 SendPlayerHP(peer_id);
2517 SendDeathscreen(peer_id, false, v3f(0,0,0));
2520 void Server::RespawnPlayer(u16 peer_id)
2522 DSTACK(FUNCTION_NAME);
2524 PlayerSAO *playersao = getPlayerSAO(peer_id);
2527 infostream << "Server::RespawnPlayer(): Player "
2528 << playersao->getPlayer()->getName()
2529 << " respawns" << std::endl;
2531 playersao->setHP(PLAYER_MAX_HP);
2532 playersao->setBreath(PLAYER_MAX_BREATH);
2534 SendPlayerHP(peer_id);
2535 SendPlayerBreath(peer_id);
2537 bool repositioned = m_script->on_respawnplayer(playersao);
2539 v3f pos = findSpawnPos();
2540 // setPos will send the new position to client
2541 playersao->setPos(pos);
2546 void Server::DenySudoAccess(u16 peer_id)
2548 DSTACK(FUNCTION_NAME);
2550 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2555 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2556 const std::string &str_reason, bool reconnect)
2558 if (proto_ver >= 25) {
2559 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2561 std::wstring wreason = utf8_to_wide(
2562 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2563 accessDeniedStrings[(u8)reason]);
2564 SendAccessDenied_Legacy(peer_id, wreason);
2567 m_clients.event(peer_id, CSE_SetDenied);
2568 m_con.DisconnectPeer(peer_id);
2572 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2574 DSTACK(FUNCTION_NAME);
2576 SendAccessDenied(peer_id, reason, custom_reason);
2577 m_clients.event(peer_id, CSE_SetDenied);
2578 m_con.DisconnectPeer(peer_id);
2581 // 13/03/15: remove this function when protocol version 25 will become
2582 // the minimum version for MT users, maybe in 1 year
2583 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2585 DSTACK(FUNCTION_NAME);
2587 SendAccessDenied_Legacy(peer_id, reason);
2588 m_clients.event(peer_id, CSE_SetDenied);
2589 m_con.DisconnectPeer(peer_id);
2592 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2594 DSTACK(FUNCTION_NAME);
2597 RemoteClient* client = getClient(peer_id, CS_Invalid);
2599 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2601 // Right now, the auth mechs don't change between login and sudo mode.
2602 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2603 client->allowed_sudo_mechs = sudo_auth_mechs;
2605 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2606 << g_settings->getFloat("dedicated_server_step")
2610 m_clients.event(peer_id, CSE_AuthAccept);
2612 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2614 // We only support SRP right now
2615 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2617 resp_pkt << sudo_auth_mechs;
2619 m_clients.event(peer_id, CSE_SudoSuccess);
2623 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2625 DSTACK(FUNCTION_NAME);
2626 std::wstring message;
2629 Clear references to playing sounds
2631 for(std::map<s32, ServerPlayingSound>::iterator
2632 i = m_playing_sounds.begin();
2633 i != m_playing_sounds.end();)
2635 ServerPlayingSound &psound = i->second;
2636 psound.clients.erase(peer_id);
2637 if(psound.clients.empty())
2638 m_playing_sounds.erase(i++);
2643 Player *player = m_env->getPlayer(peer_id);
2645 /* Run scripts and remove from environment */
2649 PlayerSAO *playersao = player->getPlayerSAO();
2652 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2654 playersao->disconnected();
2662 if(player != NULL && reason != CDR_DENY) {
2663 std::ostringstream os(std::ios_base::binary);
2664 std::vector<u16> clients = m_clients.getClientIDs();
2666 for(std::vector<u16>::iterator i = clients.begin();
2667 i != clients.end(); ++i) {
2669 Player *player = m_env->getPlayer(*i);
2673 // Get name of player
2674 os << player->getName() << " ";
2677 std::string name = player->getName();
2678 actionstream << name << " "
2679 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2680 << " List of players: " << os.str() << std::endl;
2682 m_admin_chat->outgoing_queue.push_back(
2683 new ChatEventNick(CET_NICK_REMOVE, name));
2687 MutexAutoLock env_lock(m_env_mutex);
2688 m_clients.DeleteClient(peer_id);
2692 // Send leave chat message to all remaining clients
2693 if(message.length() != 0)
2694 SendChatMessage(PEER_ID_INEXISTENT,message);
2697 void Server::UpdateCrafting(Player* player)
2699 DSTACK(FUNCTION_NAME);
2701 // Get a preview for crafting
2703 InventoryLocation loc;
2704 loc.setPlayer(player->getName());
2705 std::vector<ItemStack> output_replacements;
2706 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2707 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2709 // Put the new preview in
2710 InventoryList *plist = player->inventory.getList("craftpreview");
2711 sanity_check(plist);
2712 sanity_check(plist->getSize() >= 1);
2713 plist->changeItem(0, preview);
2716 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2718 if (evt->type == CET_NICK_ADD) {
2719 // The terminal informed us of its nick choice
2720 m_admin_nick = ((ChatEventNick *)evt)->nick;
2721 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2722 errorstream << "You haven't set up an account." << std::endl
2723 << "Please log in using the client as '"
2724 << m_admin_nick << "' with a secure password." << std::endl
2725 << "Until then, you can't execute admin tasks via the console," << std::endl
2726 << "and everybody can claim the user account instead of you," << std::endl
2727 << "giving them full control over this server." << std::endl;
2730 assert(evt->type == CET_CHAT);
2731 handleAdminChat((ChatEventChat *)evt);
2735 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2736 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2738 // If something goes wrong, this player is to blame
2739 RollbackScopeActor rollback_scope(m_rollback,
2740 std::string("player:") + name);
2744 // Whether to send line to the player that sent the message, or to all players
2745 bool broadcast_line = true;
2748 bool ate = m_script->on_chat_message(name,
2749 wide_to_utf8(wmessage));
2750 // If script ate the message, don't proceed
2755 switch (player->canSendChatMessage()) {
2756 case RPLAYER_CHATRESULT_FLOODING: {
2757 std::wstringstream ws;
2758 ws << L"You cannot send more messages. You are limited to "
2759 << g_settings->getFloat("chat_message_limit_per_10sec")
2760 << " messages per 10 seconds.";
2763 case RPLAYER_CHATRESULT_KICK:
2764 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2766 case RPLAYER_CHATRESULT_OK: break;
2767 default: FATAL_ERROR("Unhandled chat filtering result found.");
2771 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2772 return L"Your message exceed the maximum chat message limit set on the server. "
2773 "It was refused. Send a shorter message";
2776 // Commands are implemented in Lua, so only catch invalid
2777 // commands that were not "eaten" and send an error back
2778 if (wmessage[0] == L'/') {
2779 std::wstring wcmd = wmessage.substr(1);
2780 broadcast_line = false;
2781 if (wcmd.length() == 0)
2782 line += L"-!- Empty command";
2784 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2786 if (check_shout_priv && !checkPriv(name, "shout")) {
2787 line += L"-!- You don't have permission to shout.";
2788 broadcast_line = false;
2798 Tell calling method to send the message to sender
2800 if (!broadcast_line) {
2804 Send the message to others
2806 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2808 std::vector<u16> clients = m_clients.getClientIDs();
2810 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2811 for (u16 i = 0; i < clients.size(); i++) {
2812 u16 cid = clients[i];
2813 if (cid != peer_id_to_avoid_sending)
2814 SendChatMessage(cid, line);
2820 void Server::handleAdminChat(const ChatEventChat *evt)
2822 std::string name = evt->nick;
2823 std::wstring wname = utf8_to_wide(name);
2824 std::wstring wmessage = evt->evt_msg;
2826 std::wstring answer = handleChat(name, wname, wmessage);
2828 // If asked to send answer to sender
2829 if (!answer.empty()) {
2830 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2834 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2836 RemoteClient *client = getClientNoEx(peer_id,state_min);
2838 throw ClientNotFoundException("Client not found");
2842 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2844 return m_clients.getClientNoEx(peer_id, state_min);
2847 std::string Server::getPlayerName(u16 peer_id)
2849 Player *player = m_env->getPlayer(peer_id);
2851 return "[id="+itos(peer_id)+"]";
2852 return player->getName();
2855 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2857 Player *player = m_env->getPlayer(peer_id);
2860 return player->getPlayerSAO();
2863 std::wstring Server::getStatusString()
2865 std::wostringstream os(std::ios_base::binary);
2868 os<<L"version="<<narrow_to_wide(g_version_string);
2870 os<<L", uptime="<<m_uptime.get();
2872 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2873 // Information about clients
2876 std::vector<u16> clients = m_clients.getClientIDs();
2877 for(std::vector<u16>::iterator i = clients.begin();
2878 i != clients.end(); ++i) {
2880 Player *player = m_env->getPlayer(*i);
2881 // Get name of player
2882 std::wstring name = L"unknown";
2884 name = narrow_to_wide(player->getName());
2885 // Add name to information string
2893 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2894 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2895 if(g_settings->get("motd") != "")
2896 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2900 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2902 std::set<std::string> privs;
2903 m_script->getAuth(name, NULL, &privs);
2907 bool Server::checkPriv(const std::string &name, const std::string &priv)
2909 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2910 return (privs.count(priv) != 0);
2913 void Server::reportPrivsModified(const std::string &name)
2916 std::vector<u16> clients = m_clients.getClientIDs();
2917 for(std::vector<u16>::iterator i = clients.begin();
2918 i != clients.end(); ++i) {
2919 Player *player = m_env->getPlayer(*i);
2920 reportPrivsModified(player->getName());
2923 Player *player = m_env->getPlayer(name.c_str());
2926 SendPlayerPrivileges(player->peer_id);
2927 PlayerSAO *sao = player->getPlayerSAO();
2930 sao->updatePrivileges(
2931 getPlayerEffectivePrivs(name),
2936 void Server::reportInventoryFormspecModified(const std::string &name)
2938 Player *player = m_env->getPlayer(name.c_str());
2941 SendPlayerInventoryFormspec(player->peer_id);
2944 void Server::setIpBanned(const std::string &ip, const std::string &name)
2946 m_banmanager->add(ip, name);
2949 void Server::unsetIpBanned(const std::string &ip_or_name)
2951 m_banmanager->remove(ip_or_name);
2954 std::string Server::getBanDescription(const std::string &ip_or_name)
2956 return m_banmanager->getBanDescription(ip_or_name);
2959 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2961 // m_env will be NULL if the server is initializing
2965 if (m_admin_nick == name && !m_admin_nick.empty()) {
2966 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2969 Player *player = m_env->getPlayer(name);
2974 if (player->peer_id == PEER_ID_INEXISTENT)
2977 SendChatMessage(player->peer_id, msg);
2980 bool Server::showFormspec(const char *playername, const std::string &formspec,
2981 const std::string &formname)
2983 // m_env will be NULL if the server is initializing
2987 Player *player = m_env->getPlayer(playername);
2991 SendShowFormspecMessage(player->peer_id, formspec, formname);
2995 u32 Server::hudAdd(Player *player, HudElement *form)
3000 u32 id = player->addHud(form);
3002 SendHUDAdd(player->peer_id, id, form);
3007 bool Server::hudRemove(Player *player, u32 id) {
3011 HudElement* todel = player->removeHud(id);
3018 SendHUDRemove(player->peer_id, id);
3022 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3027 SendHUDChange(player->peer_id, id, stat, data);
3031 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3036 SendHUDSetFlags(player->peer_id, flags, mask);
3037 player->hud_flags &= ~mask;
3038 player->hud_flags |= flags;
3040 PlayerSAO* playersao = player->getPlayerSAO();
3042 if (playersao == NULL)
3045 m_script->player_event(playersao, "hud_changed");
3049 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3053 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3056 player->setHotbarItemcount(hotbar_itemcount);
3057 std::ostringstream os(std::ios::binary);
3058 writeS32(os, hotbar_itemcount);
3059 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3063 s32 Server::hudGetHotbarItemcount(Player *player)
3067 return player->getHotbarItemcount();
3070 void Server::hudSetHotbarImage(Player *player, std::string name)
3075 player->setHotbarImage(name);
3076 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3079 std::string Server::hudGetHotbarImage(Player *player)
3083 return player->getHotbarImage();
3086 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3091 player->setHotbarSelectedImage(name);
3092 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3095 std::string Server::hudGetHotbarSelectedImage(Player *player)
3100 return player->getHotbarSelectedImage();
3103 bool Server::setLocalPlayerAnimations(Player *player,
3104 v2s32 animation_frames[4], f32 frame_speed)
3109 player->setLocalAnimations(animation_frames, frame_speed);
3110 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3114 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3119 player->eye_offset_first = first;
3120 player->eye_offset_third = third;
3121 SendEyeOffset(player->peer_id, first, third);
3125 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3126 const std::string &type, const std::vector<std::string> ¶ms)
3131 player->setSky(bgcolor, type, params);
3132 SendSetSky(player->peer_id, bgcolor, type, params);
3136 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3142 player->overrideDayNightRatio(do_override, ratio);
3143 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3147 void Server::notifyPlayers(const std::wstring &msg)
3149 SendChatMessage(PEER_ID_INEXISTENT,msg);
3152 void Server::spawnParticle(const std::string &playername, v3f pos,
3153 v3f velocity, v3f acceleration,
3154 float expirationtime, float size, bool
3155 collisiondetection, bool collision_removal,
3156 bool vertical, const std::string &texture)
3158 // m_env will be NULL if the server is initializing
3162 u16 peer_id = PEER_ID_INEXISTENT;
3163 if (playername != "") {
3164 Player* player = m_env->getPlayer(playername.c_str());
3167 peer_id = player->peer_id;
3170 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3171 expirationtime, size, collisiondetection,
3172 collision_removal, vertical, texture);
3175 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3176 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3177 float minexptime, float maxexptime, float minsize, float maxsize,
3178 bool collisiondetection, bool collision_removal,
3179 bool vertical, const std::string &texture,
3180 const std::string &playername)
3182 // m_env will be NULL if the server is initializing
3186 u16 peer_id = PEER_ID_INEXISTENT;
3187 if (playername != "") {
3188 Player* player = m_env->getPlayer(playername.c_str());
3191 peer_id = player->peer_id;
3194 u32 id = m_env->addParticleSpawner(spawntime);
3195 SendAddParticleSpawner(peer_id, amount, spawntime,
3196 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3197 minexptime, maxexptime, minsize, maxsize,
3198 collisiondetection, collision_removal, vertical, texture, id);
3203 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3205 // m_env will be NULL if the server is initializing
3207 throw ServerError("Can't delete particle spawners during initialisation!");
3209 u16 peer_id = PEER_ID_INEXISTENT;
3210 if (playername != "") {
3211 Player* player = m_env->getPlayer(playername.c_str());
3214 peer_id = player->peer_id;
3217 m_env->deleteParticleSpawner(id);
3218 SendDeleteParticleSpawner(peer_id, id);
3221 void Server::deleteParticleSpawnerAll(u32 id)
3223 m_env->deleteParticleSpawner(id);
3224 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3227 Inventory* Server::createDetachedInventory(const std::string &name)
3229 if(m_detached_inventories.count(name) > 0){
3230 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3231 delete m_detached_inventories[name];
3233 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3235 Inventory *inv = new Inventory(m_itemdef);
3237 m_detached_inventories[name] = inv;
3238 //TODO find a better way to do this
3239 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3243 // actions: time-reversed list
3244 // Return value: success/failure
3245 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3246 std::list<std::string> *log)
3248 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3249 ServerMap *map = (ServerMap*)(&m_env->getMap());
3251 // Fail if no actions to handle
3252 if(actions.empty()){
3253 log->push_back("Nothing to do.");
3260 for(std::list<RollbackAction>::const_iterator
3261 i = actions.begin();
3262 i != actions.end(); ++i)
3264 const RollbackAction &action = *i;
3266 bool success = action.applyRevert(map, this, this);
3269 std::ostringstream os;
3270 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3271 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3273 log->push_back(os.str());
3275 std::ostringstream os;
3276 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3277 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3279 log->push_back(os.str());
3283 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3284 <<" failed"<<std::endl;
3286 // Call it done if less than half failed
3287 return num_failed <= num_tried/2;
3290 // IGameDef interface
3292 IItemDefManager *Server::getItemDefManager()
3297 INodeDefManager *Server::getNodeDefManager()
3302 ICraftDefManager *Server::getCraftDefManager()
3306 ITextureSource *Server::getTextureSource()
3310 IShaderSource *Server::getShaderSource()
3314 scene::ISceneManager *Server::getSceneManager()
3319 u16 Server::allocateUnknownNodeId(const std::string &name)
3321 return m_nodedef->allocateDummy(name);
3324 ISoundManager *Server::getSoundManager()
3326 return &dummySoundManager;
3329 MtEventManager *Server::getEventManager()
3334 IWritableItemDefManager *Server::getWritableItemDefManager()
3339 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3344 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3349 const ModSpec *Server::getModSpec(const std::string &modname) const
3351 std::vector<ModSpec>::const_iterator it;
3352 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3353 const ModSpec &mod = *it;
3354 if (mod.name == modname)
3360 void Server::getModNames(std::vector<std::string> &modlist)
3362 std::vector<ModSpec>::iterator it;
3363 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3364 modlist.push_back(it->name);
3367 std::string Server::getBuiltinLuaPath()
3369 return porting::path_share + DIR_DELIM + "builtin";
3372 v3f Server::findSpawnPos()
3374 ServerMap &map = m_env->getServerMap();
3376 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3377 return nodeposf * BS;
3380 bool is_good = false;
3382 // Try to find a good place a few times
3383 for(s32 i = 0; i < 4000 && !is_good; i++) {
3385 // We're going to try to throw the player to this position
3386 v2s16 nodepos2d = v2s16(
3387 -range + (myrand() % (range * 2)),
3388 -range + (myrand() % (range * 2)));
3390 // Get spawn level at point
3391 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3392 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3393 // the mapgen to signify an unsuitable spawn position
3394 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3397 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3400 for (s32 i = 0; i < 10; i++) {
3401 v3s16 blockpos = getNodeBlockPos(nodepos);
3402 map.emergeBlock(blockpos, true);
3403 content_t c = map.getNodeNoEx(nodepos).getContent();
3404 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3406 if (air_count >= 2) {
3407 nodeposf = intToFloat(nodepos, BS);
3408 // Don't spawn the player outside map boundaries
3409 if (objectpos_over_limit(nodeposf))
3422 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3424 bool newplayer = false;
3427 Try to get an existing player
3429 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3431 // If player is already connected, cancel
3432 if(player != NULL && player->peer_id != 0)
3434 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3439 If player with the wanted peer_id already exists, cancel.
3441 if(m_env->getPlayer(peer_id) != NULL)
3443 infostream<<"emergePlayer(): Player with wrong name but same"
3444 " peer_id already exists"<<std::endl;
3448 // Load player if it isn't already loaded
3450 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3453 // Create player if it doesn't exist
3456 player = new RemotePlayer(this, name);
3457 // Set player position
3458 infostream<<"Server: Finding spawn place for player \""
3459 <<name<<"\""<<std::endl;
3460 v3f pos = findSpawnPos();
3461 player->setPosition(pos);
3463 // Make sure the player is saved
3464 player->setModified(true);
3466 // Add player to environment
3467 m_env->addPlayer(player);
3469 // If the player exists, ensure that they respawn inside legal bounds
3470 // This fixes an assert crash when the player can't be added
3471 // to the environment
3472 if (objectpos_over_limit(player->getPosition())) {
3473 actionstream << "Respawn position for player \""
3474 << name << "\" outside limits, resetting" << std::endl;
3475 v3f pos = findSpawnPos();
3476 player->setPosition(pos);
3480 // Create a new player active object
3481 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3482 getPlayerEffectivePrivs(player->getName()),
3485 player->protocol_version = proto_version;
3487 /* Clean up old HUD elements from previous sessions */
3490 /* Add object to environment */
3491 m_env->addActiveObject(playersao);
3495 m_script->on_newplayer(playersao);
3501 void dedicated_server_loop(Server &server, bool &kill)
3503 DSTACK(FUNCTION_NAME);
3505 verbosestream<<"dedicated_server_loop()"<<std::endl;
3507 IntervalLimiter m_profiler_interval;
3509 static const float steplen = g_settings->getFloat("dedicated_server_step");
3510 static const float profiler_print_interval =
3511 g_settings->getFloat("profiler_print_interval");
3514 // This is kind of a hack but can be done like this
3515 // because server.step() is very light
3517 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3518 sleep_ms((int)(steplen*1000.0));
3520 server.step(steplen);
3522 if(server.getShutdownRequested() || kill)
3524 infostream<<"Dedicated server quitting"<<std::endl;
3526 if(g_settings->getBool("server_announce"))
3527 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3535 if (profiler_print_interval != 0) {
3536 if(m_profiler_interval.step(steplen, profiler_print_interval))
3538 infostream<<"Profiler:"<<std::endl;
3539 g_profiler->print(infostream);
3540 g_profiler->clear();