3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_async_fatal_error(""),
166 m_enable_rollback_recording(false),
169 m_itemdef(createItemDefManager()),
170 m_nodedef(createNodeDefManager()),
171 m_craftdef(createCraftDefManager()),
172 m_event(new EventManager()),
174 m_time_of_day_send_timer(0),
177 m_shutdown_requested(false),
178 m_shutdown_ask_reconnect(false),
180 m_ignore_map_edit_events(false),
181 m_ignore_map_edit_events_peer_id(0),
185 m_liquid_transform_timer = 0.0;
186 m_liquid_transform_every = 1.0;
187 m_print_info_timer = 0.0;
188 m_masterserver_timer = 0.0;
189 m_objectdata_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if(!modconf.isConsistent()) {
229 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
230 it != unsatisfied_mods.end(); ++it) {
232 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
233 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
234 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
235 errorstream << " \"" << *dep_it << "\"";
236 errorstream << std::endl;
240 Settings worldmt_settings;
241 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
242 worldmt_settings.readConfigFile(worldmt.c_str());
243 std::vector<std::string> names = worldmt_settings.getNames();
244 std::set<std::string> load_mod_names;
245 for(std::vector<std::string>::iterator it = names.begin();
246 it != names.end(); ++it) {
247 std::string name = *it;
248 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
249 load_mod_names.insert(name.substr(9));
251 // complain about mods declared to be loaded, but not found
252 for(std::vector<ModSpec>::iterator it = m_mods.begin();
253 it != m_mods.end(); ++it)
254 load_mod_names.erase((*it).name);
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
257 load_mod_names.erase((*it).name);
258 if(!load_mod_names.empty()) {
259 errorstream << "The following mods could not be found:";
260 for(std::set<std::string>::iterator it = load_mod_names.begin();
261 it != load_mod_names.end(); ++it)
262 errorstream << " \"" << (*it) << "\"";
263 errorstream << std::endl;
267 MutexAutoLock envlock(m_env_mutex);
269 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
270 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
272 // Initialize scripting
273 infostream<<"Server: Initializing Lua"<<std::endl;
275 m_script = new GameScripting(this);
277 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
279 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
282 infostream << "Server: Loading mods: ";
283 for(std::vector<ModSpec>::iterator i = m_mods.begin();
284 i != m_mods.end(); ++i) {
285 const ModSpec &mod = *i;
286 infostream << mod.name << " ";
288 infostream << std::endl;
289 // Load and run "mod" scripts
290 for (std::vector<ModSpec>::iterator it = m_mods.begin();
291 it != m_mods.end(); ++it) {
292 const ModSpec &mod = *it;
293 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
294 throw ModError("Error loading mod \"" + mod.name +
295 "\": Mod name does not follow naming conventions: "
296 "Only chararacters [a-z0-9_] are allowed.");
298 std::string script_path = mod.path + DIR_DELIM + "init.lua";
299 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
300 << script_path << "\"]" << std::endl;
301 m_script->loadMod(script_path, mod.name);
304 // Read Textures and calculate sha1 sums
307 // Apply item aliases in the node definition manager
308 m_nodedef->updateAliases(m_itemdef);
310 // Apply texture overrides from texturepack/override.txt
311 std::string texture_path = g_settings->get("texture_path");
312 if (texture_path != "" && fs::IsDir(texture_path))
313 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
315 m_nodedef->setNodeRegistrationStatus(true);
317 // Perform pending node name resolutions
318 m_nodedef->runNodeResolveCallbacks();
320 // unmap node names for connected nodeboxes
321 m_nodedef->mapNodeboxConnections();
323 // init the recipe hashes to speed up crafting
324 m_craftdef->initHashes(this);
326 // Initialize Environment
327 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
329 m_clients.setEnv(m_env);
331 if (!servermap->settings_mgr.makeMapgenParams())
332 FATAL_ERROR("Couldn't create any mapgen type");
334 // Initialize mapgens
335 m_emerge->initMapgens(servermap->getMapgenParams());
337 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
338 if (m_enable_rollback_recording) {
339 // Create rollback manager
340 m_rollback = new RollbackManager(m_path_world, this);
343 // Give environment reference to scripting api
344 m_script->initializeEnvironment(m_env);
346 // Register us to receive map edit events
347 servermap->addEventReceiver(this);
349 // If file exists, load environment metadata
350 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
351 infostream << "Server: Loading environment metadata" << std::endl;
354 m_env->loadDefaultMeta();
357 // Add some test ActiveBlockModifiers to environment
358 add_legacy_abms(m_env, m_nodedef);
360 m_liquid_transform_every = g_settings->getFloat("liquid_update");
361 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
366 infostream<<"Server destructing"<<std::endl;
368 // Send shutdown message
369 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
372 MutexAutoLock envlock(m_env_mutex);
374 // Execute script shutdown hooks
375 m_script->on_shutdown();
377 infostream << "Server: Saving players" << std::endl;
378 m_env->saveLoadedPlayers();
380 infostream << "Server: Kicking players" << std::endl;
381 std::string kick_msg;
382 bool reconnect = false;
383 if (getShutdownRequested()) {
384 reconnect = m_shutdown_ask_reconnect;
385 kick_msg = m_shutdown_msg;
387 if (kick_msg == "") {
388 kick_msg = g_settings->get("kick_msg_shutdown");
390 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
391 kick_msg, reconnect);
393 infostream << "Server: Saving environment metadata" << std::endl;
401 // stop all emerge threads before deleting players that may have
402 // requested blocks to be emerged
403 m_emerge->stopThreads();
405 // Delete things in the reverse order of creation
415 // Deinitialize scripting
416 infostream<<"Server: Deinitializing scripting"<<std::endl;
419 // Delete detached inventories
420 for (std::map<std::string, Inventory*>::iterator
421 i = m_detached_inventories.begin();
422 i != m_detached_inventories.end(); ++i) {
427 void Server::start(Address bind_addr)
429 DSTACK(FUNCTION_NAME);
431 m_bind_addr = bind_addr;
433 infostream<<"Starting server on "
434 << bind_addr.serializeString() <<"..."<<std::endl;
436 // Stop thread if already running
439 // Initialize connection
440 m_con.SetTimeoutMs(30);
441 m_con.Serve(bind_addr);
446 // ASCII art for the win!
448 <<" .__ __ __ "<<std::endl
449 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
450 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
451 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
452 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
453 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
454 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
455 actionstream<<"Server for gameid=\""<<m_gamespec.id
456 <<"\" listening on "<<bind_addr.serializeString()<<":"
457 <<bind_addr.getPort() << "."<<std::endl;
462 DSTACK(FUNCTION_NAME);
464 infostream<<"Server: Stopping and waiting threads"<<std::endl;
466 // Stop threads (set run=false first so both start stopping)
468 //m_emergethread.setRun(false);
470 //m_emergethread.stop();
472 infostream<<"Server: Threads stopped"<<std::endl;
475 void Server::step(float dtime)
477 DSTACK(FUNCTION_NAME);
482 MutexAutoLock lock(m_step_dtime_mutex);
483 m_step_dtime += dtime;
485 // Throw if fatal error occurred in thread
486 std::string async_err = m_async_fatal_error.get();
487 if (!async_err.empty()) {
488 if (!m_simple_singleplayer_mode) {
489 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
490 g_settings->get("kick_msg_crash"),
491 g_settings->getBool("ask_reconnect_on_crash"));
493 throw ServerError(async_err);
497 void Server::AsyncRunStep(bool initial_step)
499 DSTACK(FUNCTION_NAME);
501 g_profiler->add("Server::AsyncRunStep (num)", 1);
505 MutexAutoLock lock1(m_step_dtime_mutex);
506 dtime = m_step_dtime;
510 // Send blocks to clients
514 if((dtime < 0.001) && (initial_step == false))
517 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
519 //infostream<<"Server steps "<<dtime<<std::endl;
520 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
523 MutexAutoLock lock1(m_step_dtime_mutex);
524 m_step_dtime -= dtime;
531 m_uptime.set(m_uptime.get() + dtime);
537 Update time of day and overall game time
539 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
542 Send to clients at constant intervals
545 m_time_of_day_send_timer -= dtime;
546 if(m_time_of_day_send_timer < 0.0) {
547 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
548 u16 time = m_env->getTimeOfDay();
549 float time_speed = g_settings->getFloat("time_speed");
550 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
554 MutexAutoLock lock(m_env_mutex);
555 // Figure out and report maximum lag to environment
556 float max_lag = m_env->getMaxLagEstimate();
557 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
559 if(dtime > 0.1 && dtime > max_lag * 2.0)
560 infostream<<"Server: Maximum lag peaked to "<<dtime
564 m_env->reportMaxLagEstimate(max_lag);
566 ScopeProfiler sp(g_profiler, "SEnv step");
567 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
571 static const float map_timer_and_unload_dtime = 2.92;
572 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
574 MutexAutoLock lock(m_env_mutex);
575 // Run Map's timers and unload unused data
576 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
577 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
578 g_settings->getFloat("server_unload_unused_data_timeout"),
583 Listen to the admin chat, if available
586 if (!m_admin_chat->command_queue.empty()) {
587 MutexAutoLock lock(m_env_mutex);
588 while (!m_admin_chat->command_queue.empty()) {
589 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
590 handleChatInterfaceEvent(evt);
594 m_admin_chat->outgoing_queue.push_back(
595 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
602 /* Transform liquids */
603 m_liquid_transform_timer += dtime;
604 if(m_liquid_transform_timer >= m_liquid_transform_every)
606 m_liquid_transform_timer -= m_liquid_transform_every;
608 MutexAutoLock lock(m_env_mutex);
610 ScopeProfiler sp(g_profiler, "Server: liquid transform");
612 std::map<v3s16, MapBlock*> modified_blocks;
613 m_env->getMap().transformLiquids(modified_blocks);
618 core::map<v3s16, MapBlock*> lighting_modified_blocks;
619 ServerMap &map = ((ServerMap&)m_env->getMap());
620 map.updateLighting(modified_blocks, lighting_modified_blocks);
622 // Add blocks modified by lighting to modified_blocks
623 for(core::map<v3s16, MapBlock*>::Iterator
624 i = lighting_modified_blocks.getIterator();
625 i.atEnd() == false; i++)
627 MapBlock *block = i.getNode()->getValue();
628 modified_blocks.insert(block->getPos(), block);
632 Set the modified blocks unsent for all the clients
634 if(!modified_blocks.empty())
636 SetBlocksNotSent(modified_blocks);
639 m_clients.step(dtime);
641 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
643 // send masterserver announce
645 float &counter = m_masterserver_timer;
646 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
647 g_settings->getBool("server_announce"))
649 ServerList::sendAnnounce(counter ? "update" : "start",
650 m_bind_addr.getPort(),
651 m_clients.getPlayerNames(),
653 m_env->getGameTime(),
656 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
665 Check added and deleted active objects
668 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
669 MutexAutoLock envlock(m_env_mutex);
672 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
673 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
675 // Radius inside which objects are active
676 static const s16 radius =
677 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
679 // Radius inside which players are active
680 static const bool is_transfer_limited =
681 g_settings->exists("unlimited_player_transfer_distance") &&
682 !g_settings->getBool("unlimited_player_transfer_distance");
683 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
684 s16 player_radius = player_transfer_dist;
685 if (player_radius == 0 && is_transfer_limited)
686 player_radius = radius;
688 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
689 i != clients.end(); ++i) {
690 RemoteClient *client = i->second;
692 // If definitions and textures have not been sent, don't
693 // send objects either
694 if (client->getState() < CS_DefinitionsSent)
697 Player *player = m_env->getPlayer(client->peer_id);
698 if (player == NULL) {
699 // This can happen if the client timeouts somehow
700 /*warningstream<<FUNCTION_NAME<<": Client "
702 <<" has no associated player"<<std::endl;*/
706 std::queue<u16> removed_objects;
707 std::queue<u16> added_objects;
708 m_env->getRemovedActiveObjects(player, radius, player_radius,
709 client->m_known_objects, removed_objects);
710 m_env->getAddedActiveObjects(player, radius, player_radius,
711 client->m_known_objects, added_objects);
713 // Ignore if nothing happened
714 if (removed_objects.empty() && added_objects.empty()) {
718 std::string data_buffer;
722 // Handle removed objects
723 writeU16((u8*)buf, removed_objects.size());
724 data_buffer.append(buf, 2);
725 while (!removed_objects.empty()) {
727 u16 id = removed_objects.front();
728 ServerActiveObject* obj = m_env->getActiveObject(id);
730 // Add to data buffer for sending
731 writeU16((u8*)buf, id);
732 data_buffer.append(buf, 2);
734 // Remove from known objects
735 client->m_known_objects.erase(id);
737 if(obj && obj->m_known_by_count > 0)
738 obj->m_known_by_count--;
739 removed_objects.pop();
742 // Handle added objects
743 writeU16((u8*)buf, added_objects.size());
744 data_buffer.append(buf, 2);
745 while (!added_objects.empty()) {
747 u16 id = added_objects.front();
748 ServerActiveObject* obj = m_env->getActiveObject(id);
751 u8 type = ACTIVEOBJECT_TYPE_INVALID;
753 warningstream<<FUNCTION_NAME
754 <<": NULL object"<<std::endl;
756 type = obj->getSendType();
758 // Add to data buffer for sending
759 writeU16((u8*)buf, id);
760 data_buffer.append(buf, 2);
761 writeU8((u8*)buf, type);
762 data_buffer.append(buf, 1);
765 data_buffer.append(serializeLongString(
766 obj->getClientInitializationData(client->net_proto_version)));
768 data_buffer.append(serializeLongString(""));
770 // Add to known objects
771 client->m_known_objects.insert(id);
774 obj->m_known_by_count++;
779 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
780 verbosestream << "Server: Sent object remove/add: "
781 << removed_objects.size() << " removed, "
782 << added_objects.size() << " added, "
783 << "packet size is " << pktSize << std::endl;
792 MutexAutoLock envlock(m_env_mutex);
793 ScopeProfiler sp(g_profiler, "Server: sending object messages");
796 // Value = data sent by object
797 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
799 // Get active object messages from environment
801 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
805 std::vector<ActiveObjectMessage>* message_list = NULL;
806 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
807 n = buffered_messages.find(aom.id);
808 if (n == buffered_messages.end()) {
809 message_list = new std::vector<ActiveObjectMessage>;
810 buffered_messages[aom.id] = message_list;
813 message_list = n->second;
815 message_list->push_back(aom);
819 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
820 // Route data to every client
821 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
822 i != clients.end(); ++i) {
823 RemoteClient *client = i->second;
824 std::string reliable_data;
825 std::string unreliable_data;
826 // Go through all objects in message buffer
827 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
828 j = buffered_messages.begin();
829 j != buffered_messages.end(); ++j) {
830 // If object is not known by client, skip it
832 if (client->m_known_objects.find(id) == client->m_known_objects.end())
835 // Get message list of object
836 std::vector<ActiveObjectMessage>* list = j->second;
837 // Go through every message
838 for (std::vector<ActiveObjectMessage>::iterator
839 k = list->begin(); k != list->end(); ++k) {
840 // Compose the full new data with header
841 ActiveObjectMessage aom = *k;
842 std::string new_data;
845 writeU16((u8*)&buf[0], aom.id);
846 new_data.append(buf, 2);
848 new_data += serializeString(aom.datastring);
849 // Add data to buffer
851 reliable_data += new_data;
853 unreliable_data += new_data;
857 reliable_data and unreliable_data are now ready.
860 if(reliable_data.size() > 0) {
861 SendActiveObjectMessages(client->peer_id, reliable_data);
864 if(unreliable_data.size() > 0) {
865 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
870 // Clear buffered_messages
871 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
872 i = buffered_messages.begin();
873 i != buffered_messages.end(); ++i) {
879 Send queued-for-sending map edit events.
882 // We will be accessing the environment
883 MutexAutoLock lock(m_env_mutex);
885 // Don't send too many at a time
888 // Single change sending is disabled if queue size is not small
889 bool disable_single_change_sending = false;
890 if(m_unsent_map_edit_queue.size() >= 4)
891 disable_single_change_sending = true;
893 int event_count = m_unsent_map_edit_queue.size();
895 // We'll log the amount of each
898 while(m_unsent_map_edit_queue.size() != 0)
900 MapEditEvent* event = m_unsent_map_edit_queue.front();
901 m_unsent_map_edit_queue.pop();
903 // Players far away from the change are stored here.
904 // Instead of sending the changes, MapBlocks are set not sent
906 std::vector<u16> far_players;
908 switch (event->type) {
911 prof.add("MEET_ADDNODE", 1);
912 sendAddNode(event->p, event->n, event->already_known_by_peer,
913 &far_players, disable_single_change_sending ? 5 : 30,
914 event->type == MEET_ADDNODE);
916 case MEET_REMOVENODE:
917 prof.add("MEET_REMOVENODE", 1);
918 sendRemoveNode(event->p, event->already_known_by_peer,
919 &far_players, disable_single_change_sending ? 5 : 30);
921 case MEET_BLOCK_NODE_METADATA_CHANGED:
922 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
923 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
924 setBlockNotSent(event->p);
927 infostream << "Server: MEET_OTHER" << std::endl;
928 prof.add("MEET_OTHER", 1);
929 for(std::set<v3s16>::iterator
930 i = event->modified_blocks.begin();
931 i != event->modified_blocks.end(); ++i) {
936 prof.add("unknown", 1);
937 warningstream << "Server: Unknown MapEditEvent "
938 << ((u32)event->type) << std::endl;
943 Set blocks not sent to far players
945 if(!far_players.empty()) {
946 // Convert list format to that wanted by SetBlocksNotSent
947 std::map<v3s16, MapBlock*> modified_blocks2;
948 for(std::set<v3s16>::iterator
949 i = event->modified_blocks.begin();
950 i != event->modified_blocks.end(); ++i) {
951 modified_blocks2[*i] =
952 m_env->getMap().getBlockNoCreateNoEx(*i);
955 // Set blocks not sent
956 for(std::vector<u16>::iterator
957 i = far_players.begin();
958 i != far_players.end(); ++i) {
959 if(RemoteClient *client = getClient(*i))
960 client->SetBlocksNotSent(modified_blocks2);
966 /*// Don't send too many at a time
968 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
972 if(event_count >= 5){
973 infostream<<"Server: MapEditEvents:"<<std::endl;
974 prof.print(infostream);
975 } else if(event_count != 0){
976 verbosestream<<"Server: MapEditEvents:"<<std::endl;
977 prof.print(verbosestream);
983 Trigger emergethread (it somehow gets to a non-triggered but
984 bysy state sometimes)
987 float &counter = m_emergethread_trigger_timer;
989 if (counter >= 2.0) {
992 m_emerge->startThreads();
996 // Save map, players and auth stuff
998 float &counter = m_savemap_timer;
1000 static const float save_interval =
1001 g_settings->getFloat("server_map_save_interval");
1002 if (counter >= save_interval) {
1004 MutexAutoLock lock(m_env_mutex);
1006 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1009 if (m_banmanager->isModified()) {
1010 m_banmanager->save();
1013 // Save changed parts of map
1014 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1017 m_env->saveLoadedPlayers();
1019 // Save environment metadata
1025 void Server::Receive()
1027 DSTACK(FUNCTION_NAME);
1028 SharedBuffer<u8> data;
1032 m_con.Receive(&pkt);
1033 peer_id = pkt.getPeerId();
1036 catch(con::InvalidIncomingDataException &e) {
1037 infostream<<"Server::Receive(): "
1038 "InvalidIncomingDataException: what()="
1039 <<e.what()<<std::endl;
1041 catch(SerializationError &e) {
1042 infostream<<"Server::Receive(): "
1043 "SerializationError: what()="
1044 <<e.what()<<std::endl;
1046 catch(ClientStateError &e) {
1047 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1048 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1049 L"Try reconnecting or updating your client");
1051 catch(con::PeerNotFoundException &e) {
1056 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1058 std::string playername = "";
1059 PlayerSAO *playersao = NULL;
1062 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1063 if (client != NULL) {
1064 playername = client->getName();
1065 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1067 } catch (std::exception &e) {
1073 RemotePlayer *player =
1074 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1076 // If failed, cancel
1077 if ((playersao == NULL) || (player == NULL)) {
1078 if (player && player->peer_id != 0) {
1079 actionstream << "Server: Failed to emerge player \"" << playername
1080 << "\" (player allocated to an another client)" << std::endl;
1081 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1082 L"name. If your client closed unexpectedly, try again in "
1085 errorstream << "Server: " << playername << ": Failed to emerge player"
1087 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1093 Send complete position information
1095 SendMovePlayer(peer_id);
1098 SendPlayerPrivileges(peer_id);
1100 // Send inventory formspec
1101 SendPlayerInventoryFormspec(peer_id);
1104 SendInventory(playersao);
1107 SendPlayerHPOrDie(playersao);
1110 SendPlayerBreath(peer_id);
1112 // Show death screen if necessary
1113 if(player->isDead())
1114 SendDeathscreen(peer_id, false, v3f(0,0,0));
1116 // Note things in chat if not in simple singleplayer mode
1117 if(!m_simple_singleplayer_mode) {
1118 // Send information about server to player in chat
1119 SendChatMessage(peer_id, getStatusString());
1121 Address addr = getPeerAddress(player->peer_id);
1122 std::string ip_str = addr.serializeString();
1123 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1128 std::vector<std::string> names = m_clients.getPlayerNames();
1130 actionstream<<player->getName() <<" joins game. List of players: ";
1132 for (std::vector<std::string>::iterator i = names.begin();
1133 i != names.end(); ++i) {
1134 actionstream << *i << " ";
1137 actionstream << player->getName() <<std::endl;
1142 inline void Server::handleCommand(NetworkPacket* pkt)
1144 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1145 (this->*opHandle.handler)(pkt);
1148 void Server::ProcessData(NetworkPacket *pkt)
1150 DSTACK(FUNCTION_NAME);
1151 // Environment is locked first.
1152 MutexAutoLock envlock(m_env_mutex);
1154 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1155 u32 peer_id = pkt->getPeerId();
1158 Address address = getPeerAddress(peer_id);
1159 std::string addr_s = address.serializeString();
1161 if(m_banmanager->isIpBanned(addr_s)) {
1162 std::string ban_name = m_banmanager->getBanName(addr_s);
1163 infostream << "Server: A banned client tried to connect from "
1164 << addr_s << "; banned name was "
1165 << ban_name << std::endl;
1166 // This actually doesn't seem to transfer to the client
1167 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1168 + utf8_to_wide(ban_name));
1172 catch(con::PeerNotFoundException &e) {
1174 * no peer for this packet found
1175 * most common reason is peer timeout, e.g. peer didn't
1176 * respond for some time, your server was overloaded or
1179 infostream << "Server::ProcessData(): Canceling: peer "
1180 << peer_id << " not found" << std::endl;
1185 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1187 // Command must be handled into ToServerCommandHandler
1188 if (command >= TOSERVER_NUM_MSG_TYPES) {
1189 infostream << "Server: Ignoring unknown command "
1190 << command << std::endl;
1194 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1199 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1201 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1202 errorstream << "Server::ProcessData(): Cancelling: Peer"
1203 " serialization format invalid or not initialized."
1204 " Skipping incoming command=" << command << std::endl;
1208 /* Handle commands related to client startup */
1209 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1214 if (m_clients.getClientState(peer_id) < CS_Active) {
1215 if (command == TOSERVER_PLAYERPOS) return;
1217 errorstream << "Got packet command: " << command << " for peer id "
1218 << peer_id << " but client isn't active yet. Dropping packet "
1224 } catch (SendFailedException &e) {
1225 errorstream << "Server::ProcessData(): SendFailedException: "
1226 << "what=" << e.what()
1228 } catch (PacketError &e) {
1229 actionstream << "Server::ProcessData(): PacketError: "
1230 << "what=" << e.what()
1235 void Server::setTimeOfDay(u32 time)
1237 m_env->setTimeOfDay(time);
1238 m_time_of_day_send_timer = 0;
1241 void Server::onMapEditEvent(MapEditEvent *event)
1243 if(m_ignore_map_edit_events)
1245 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1247 MapEditEvent *e = event->clone();
1248 m_unsent_map_edit_queue.push(e);
1251 Inventory* Server::getInventory(const InventoryLocation &loc)
1254 case InventoryLocation::UNDEFINED:
1255 case InventoryLocation::CURRENT_PLAYER:
1257 case InventoryLocation::PLAYER:
1259 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 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2020 if (i == m_playing_sounds.end())
2022 ServerPlayingSound &psound = i->second;
2024 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2027 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2028 i != psound.clients.end(); ++i) {
2030 m_clients.send(*i, 0, &pkt, true);
2032 // Remove sound reference
2033 m_playing_sounds.erase(i);
2036 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2037 std::vector<u16> *far_players, float far_d_nodes)
2039 float maxd = far_d_nodes*BS;
2040 v3f p_f = intToFloat(p, BS);
2042 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2045 std::vector<u16> clients = m_clients.getClientIDs();
2046 for(std::vector<u16>::iterator i = clients.begin();
2047 i != clients.end(); ++i) {
2050 if(Player *player = m_env->getPlayer(*i)) {
2051 // If player is far away, only set modified blocks not sent
2052 v3f player_pos = player->getPosition();
2053 if(player_pos.getDistanceFrom(p_f) > maxd) {
2054 far_players->push_back(*i);
2061 m_clients.send(*i, 0, &pkt, true);
2065 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2066 std::vector<u16> *far_players, float far_d_nodes,
2067 bool remove_metadata)
2069 float maxd = far_d_nodes*BS;
2070 v3f p_f = intToFloat(p, BS);
2072 std::vector<u16> clients = m_clients.getClientIDs();
2073 for(std::vector<u16>::iterator i = clients.begin();
2074 i != clients.end(); ++i) {
2078 if(Player *player = m_env->getPlayer(*i)) {
2079 // If player is far away, only set modified blocks not sent
2080 v3f player_pos = player->getPosition();
2081 if(player_pos.getDistanceFrom(p_f) > maxd) {
2082 far_players->push_back(*i);
2088 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2090 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2092 pkt << p << n.param0 << n.param1 << n.param2
2093 << (u8) (remove_metadata ? 0 : 1);
2095 if (!remove_metadata) {
2096 if (client->net_proto_version <= 21) {
2097 // Old clients always clear metadata; fix it
2098 // by sending the full block again.
2099 client->SetBlockNotSent(getNodeBlockPos(p));
2106 if (pkt.getSize() > 0)
2107 m_clients.send(*i, 0, &pkt, true);
2111 void Server::setBlockNotSent(v3s16 p)
2113 std::vector<u16> clients = m_clients.getClientIDs();
2115 for(std::vector<u16>::iterator i = clients.begin();
2116 i != clients.end(); ++i) {
2117 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2118 client->SetBlockNotSent(p);
2123 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2125 DSTACK(FUNCTION_NAME);
2127 v3s16 p = block->getPos();
2130 Create a packet with the block in the right format
2133 std::ostringstream os(std::ios_base::binary);
2134 block->serialize(os, ver, false);
2135 block->serializeNetworkSpecific(os, net_proto_version);
2136 std::string s = os.str();
2138 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2141 pkt.putRawString(s.c_str(), s.size());
2145 void Server::SendBlocks(float dtime)
2147 DSTACK(FUNCTION_NAME);
2149 MutexAutoLock envlock(m_env_mutex);
2150 //TODO check if one big lock could be faster then multiple small ones
2152 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2154 std::vector<PrioritySortedBlockTransfer> queue;
2156 s32 total_sending = 0;
2159 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2161 std::vector<u16> clients = m_clients.getClientIDs();
2164 for(std::vector<u16>::iterator i = clients.begin();
2165 i != clients.end(); ++i) {
2166 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2171 total_sending += client->SendingCount();
2172 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2178 // Lowest priority number comes first.
2179 // Lowest is most important.
2180 std::sort(queue.begin(), queue.end());
2183 for(u32 i=0; i<queue.size(); i++)
2185 //TODO: Calculate limit dynamically
2186 if(total_sending >= g_settings->getS32
2187 ("max_simultaneous_block_sends_server_total"))
2190 PrioritySortedBlockTransfer q = queue[i];
2192 MapBlock *block = NULL;
2195 block = m_env->getMap().getBlockNoCreate(q.pos);
2197 catch(InvalidPositionException &e)
2202 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2207 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2209 client->SentBlock(q.pos);
2215 void Server::fillMediaCache()
2217 DSTACK(FUNCTION_NAME);
2219 infostream<<"Server: Calculating media file checksums"<<std::endl;
2221 // Collect all media file paths
2222 std::vector<std::string> paths;
2223 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2224 i != m_mods.end(); ++i) {
2225 const ModSpec &mod = *i;
2226 paths.push_back(mod.path + DIR_DELIM + "textures");
2227 paths.push_back(mod.path + DIR_DELIM + "sounds");
2228 paths.push_back(mod.path + DIR_DELIM + "media");
2229 paths.push_back(mod.path + DIR_DELIM + "models");
2231 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2233 // Collect media file information from paths into cache
2234 for(std::vector<std::string>::iterator i = paths.begin();
2235 i != paths.end(); ++i) {
2236 std::string mediapath = *i;
2237 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2238 for (u32 j = 0; j < dirlist.size(); j++) {
2239 if (dirlist[j].dir) // Ignode dirs
2241 std::string filename = dirlist[j].name;
2242 // If name contains illegal characters, ignore the file
2243 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2244 infostream<<"Server: ignoring illegal file name: \""
2245 << filename << "\"" << std::endl;
2248 // If name is not in a supported format, ignore it
2249 const char *supported_ext[] = {
2250 ".png", ".jpg", ".bmp", ".tga",
2251 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2253 ".x", ".b3d", ".md2", ".obj",
2256 if (removeStringEnd(filename, supported_ext) == ""){
2257 infostream << "Server: ignoring unsupported file extension: \""
2258 << filename << "\"" << std::endl;
2261 // Ok, attempt to load the file and add to cache
2262 std::string filepath = mediapath + DIR_DELIM + filename;
2264 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2266 errorstream << "Server::fillMediaCache(): Could not open \""
2267 << filename << "\" for reading" << std::endl;
2270 std::ostringstream tmp_os(std::ios_base::binary);
2274 fis.read(buf, 1024);
2275 std::streamsize len = fis.gcount();
2276 tmp_os.write(buf, len);
2285 errorstream<<"Server::fillMediaCache(): Failed to read \""
2286 << filename << "\"" << std::endl;
2289 if(tmp_os.str().length() == 0) {
2290 errorstream << "Server::fillMediaCache(): Empty file \""
2291 << filepath << "\"" << std::endl;
2296 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2298 unsigned char *digest = sha1.getDigest();
2299 std::string sha1_base64 = base64_encode(digest, 20);
2300 std::string sha1_hex = hex_encode((char*)digest, 20);
2304 m_media[filename] = MediaInfo(filepath, sha1_base64);
2305 verbosestream << "Server: " << sha1_hex << " is " << filename
2311 void Server::sendMediaAnnouncement(u16 peer_id)
2313 DSTACK(FUNCTION_NAME);
2315 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2319 std::ostringstream os(std::ios_base::binary);
2321 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2322 pkt << (u16) m_media.size();
2324 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2325 i != m_media.end(); ++i) {
2326 pkt << i->first << i->second.sha1_digest;
2329 pkt << g_settings->get("remote_media");
2333 struct SendableMedia
2339 SendableMedia(const std::string &name_="", const std::string &path_="",
2340 const std::string &data_=""):
2347 void Server::sendRequestedMedia(u16 peer_id,
2348 const std::vector<std::string> &tosend)
2350 DSTACK(FUNCTION_NAME);
2352 verbosestream<<"Server::sendRequestedMedia(): "
2353 <<"Sending files to client"<<std::endl;
2357 // Put 5kB in one bunch (this is not accurate)
2358 u32 bytes_per_bunch = 5000;
2360 std::vector< std::vector<SendableMedia> > file_bunches;
2361 file_bunches.push_back(std::vector<SendableMedia>());
2363 u32 file_size_bunch_total = 0;
2365 for(std::vector<std::string>::const_iterator i = tosend.begin();
2366 i != tosend.end(); ++i) {
2367 const std::string &name = *i;
2369 if (m_media.find(name) == m_media.end()) {
2370 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2371 <<"unknown file \""<<(name)<<"\""<<std::endl;
2375 //TODO get path + name
2376 std::string tpath = m_media[name].path;
2379 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2380 if(fis.good() == false){
2381 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2382 <<tpath<<"\" for reading"<<std::endl;
2385 std::ostringstream tmp_os(std::ios_base::binary);
2389 fis.read(buf, 1024);
2390 std::streamsize len = fis.gcount();
2391 tmp_os.write(buf, len);
2392 file_size_bunch_total += len;
2401 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2402 <<name<<"\""<<std::endl;
2405 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2406 <<tname<<"\""<<std::endl;*/
2408 file_bunches[file_bunches.size()-1].push_back(
2409 SendableMedia(name, tpath, tmp_os.str()));
2411 // Start next bunch if got enough data
2412 if(file_size_bunch_total >= bytes_per_bunch) {
2413 file_bunches.push_back(std::vector<SendableMedia>());
2414 file_size_bunch_total = 0;
2419 /* Create and send packets */
2421 u16 num_bunches = file_bunches.size();
2422 for(u16 i = 0; i < num_bunches; i++) {
2425 u16 total number of texture bunches
2426 u16 index of this bunch
2427 u32 number of files in this bunch
2436 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2437 pkt << num_bunches << i << (u32) file_bunches[i].size();
2439 for(std::vector<SendableMedia>::iterator
2440 j = file_bunches[i].begin();
2441 j != file_bunches[i].end(); ++j) {
2443 pkt.putLongString(j->data);
2446 verbosestream << "Server::sendRequestedMedia(): bunch "
2447 << i << "/" << num_bunches
2448 << " files=" << file_bunches[i].size()
2449 << " size=" << pkt.getSize() << std::endl;
2454 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2456 if(m_detached_inventories.count(name) == 0) {
2457 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2460 Inventory *inv = m_detached_inventories[name];
2461 std::ostringstream os(std::ios_base::binary);
2463 os << serializeString(name);
2467 std::string s = os.str();
2469 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2470 pkt.putRawString(s.c_str(), s.size());
2472 if (peer_id != PEER_ID_INEXISTENT) {
2476 m_clients.sendToAll(0, &pkt, true);
2480 void Server::sendDetachedInventories(u16 peer_id)
2482 DSTACK(FUNCTION_NAME);
2484 for(std::map<std::string, Inventory*>::iterator
2485 i = m_detached_inventories.begin();
2486 i != m_detached_inventories.end(); ++i) {
2487 const std::string &name = i->first;
2488 //Inventory *inv = i->second;
2489 sendDetachedInventory(name, peer_id);
2497 void Server::DiePlayer(u16 peer_id)
2499 DSTACK(FUNCTION_NAME);
2500 PlayerSAO *playersao = getPlayerSAO(peer_id);
2501 // In some rare cases this can be NULL -- if the player is disconnected
2502 // when a Lua function modifies l_punch, for example
2506 infostream << "Server::DiePlayer(): Player "
2507 << playersao->getPlayer()->getName()
2508 << " dies" << std::endl;
2510 playersao->setHP(0);
2512 // Trigger scripted stuff
2513 m_script->on_dieplayer(playersao);
2515 SendPlayerHP(peer_id);
2516 SendDeathscreen(peer_id, false, v3f(0,0,0));
2519 void Server::RespawnPlayer(u16 peer_id)
2521 DSTACK(FUNCTION_NAME);
2523 PlayerSAO *playersao = getPlayerSAO(peer_id);
2526 infostream << "Server::RespawnPlayer(): Player "
2527 << playersao->getPlayer()->getName()
2528 << " respawns" << std::endl;
2530 playersao->setHP(PLAYER_MAX_HP);
2531 playersao->setBreath(PLAYER_MAX_BREATH);
2533 SendPlayerHP(peer_id);
2534 SendPlayerBreath(peer_id);
2536 bool repositioned = m_script->on_respawnplayer(playersao);
2538 v3f pos = findSpawnPos();
2539 // setPos will send the new position to client
2540 playersao->setPos(pos);
2545 void Server::DenySudoAccess(u16 peer_id)
2547 DSTACK(FUNCTION_NAME);
2549 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2554 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2555 const std::string &str_reason, bool reconnect)
2557 if (proto_ver >= 25) {
2558 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2560 std::wstring wreason = utf8_to_wide(
2561 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2562 accessDeniedStrings[(u8)reason]);
2563 SendAccessDenied_Legacy(peer_id, wreason);
2566 m_clients.event(peer_id, CSE_SetDenied);
2567 m_con.DisconnectPeer(peer_id);
2571 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2573 DSTACK(FUNCTION_NAME);
2575 SendAccessDenied(peer_id, reason, custom_reason);
2576 m_clients.event(peer_id, CSE_SetDenied);
2577 m_con.DisconnectPeer(peer_id);
2580 // 13/03/15: remove this function when protocol version 25 will become
2581 // the minimum version for MT users, maybe in 1 year
2582 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2584 DSTACK(FUNCTION_NAME);
2586 SendAccessDenied_Legacy(peer_id, reason);
2587 m_clients.event(peer_id, CSE_SetDenied);
2588 m_con.DisconnectPeer(peer_id);
2591 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2593 DSTACK(FUNCTION_NAME);
2596 RemoteClient* client = getClient(peer_id, CS_Invalid);
2598 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2600 // Right now, the auth mechs don't change between login and sudo mode.
2601 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2602 client->allowed_sudo_mechs = sudo_auth_mechs;
2604 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2605 << g_settings->getFloat("dedicated_server_step")
2609 m_clients.event(peer_id, CSE_AuthAccept);
2611 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2613 // We only support SRP right now
2614 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2616 resp_pkt << sudo_auth_mechs;
2618 m_clients.event(peer_id, CSE_SudoSuccess);
2622 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2624 DSTACK(FUNCTION_NAME);
2625 std::wstring message;
2628 Clear references to playing sounds
2630 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2631 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2632 ServerPlayingSound &psound = i->second;
2633 psound.clients.erase(peer_id);
2634 if (psound.clients.empty())
2635 m_playing_sounds.erase(i++);
2640 Player *player = m_env->getPlayer(peer_id);
2642 /* Run scripts and remove from environment */
2646 PlayerSAO *playersao = player->getPlayerSAO();
2649 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2651 playersao->disconnected();
2659 if(player != NULL && reason != CDR_DENY) {
2660 std::ostringstream os(std::ios_base::binary);
2661 std::vector<u16> clients = m_clients.getClientIDs();
2663 for(std::vector<u16>::iterator i = clients.begin();
2664 i != clients.end(); ++i) {
2666 Player *player = m_env->getPlayer(*i);
2670 // Get name of player
2671 os << player->getName() << " ";
2674 std::string name = player->getName();
2675 actionstream << name << " "
2676 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2677 << " List of players: " << os.str() << std::endl;
2679 m_admin_chat->outgoing_queue.push_back(
2680 new ChatEventNick(CET_NICK_REMOVE, name));
2684 MutexAutoLock env_lock(m_env_mutex);
2685 m_clients.DeleteClient(peer_id);
2689 // Send leave chat message to all remaining clients
2690 if(message.length() != 0)
2691 SendChatMessage(PEER_ID_INEXISTENT,message);
2694 void Server::UpdateCrafting(Player* player)
2696 DSTACK(FUNCTION_NAME);
2698 // Get a preview for crafting
2700 InventoryLocation loc;
2701 loc.setPlayer(player->getName());
2702 std::vector<ItemStack> output_replacements;
2703 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2704 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2706 // Put the new preview in
2707 InventoryList *plist = player->inventory.getList("craftpreview");
2708 sanity_check(plist);
2709 sanity_check(plist->getSize() >= 1);
2710 plist->changeItem(0, preview);
2713 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2715 if (evt->type == CET_NICK_ADD) {
2716 // The terminal informed us of its nick choice
2717 m_admin_nick = ((ChatEventNick *)evt)->nick;
2718 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2719 errorstream << "You haven't set up an account." << std::endl
2720 << "Please log in using the client as '"
2721 << m_admin_nick << "' with a secure password." << std::endl
2722 << "Until then, you can't execute admin tasks via the console," << std::endl
2723 << "and everybody can claim the user account instead of you," << std::endl
2724 << "giving them full control over this server." << std::endl;
2727 assert(evt->type == CET_CHAT);
2728 handleAdminChat((ChatEventChat *)evt);
2732 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2733 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2735 // If something goes wrong, this player is to blame
2736 RollbackScopeActor rollback_scope(m_rollback,
2737 std::string("player:") + name);
2741 // Whether to send line to the player that sent the message, or to all players
2742 bool broadcast_line = true;
2745 bool ate = m_script->on_chat_message(name,
2746 wide_to_utf8(wmessage));
2747 // If script ate the message, don't proceed
2752 switch (player->canSendChatMessage()) {
2753 case RPLAYER_CHATRESULT_FLOODING: {
2754 std::wstringstream ws;
2755 ws << L"You cannot send more messages. You are limited to "
2756 << g_settings->getFloat("chat_message_limit_per_10sec")
2757 << L" messages per 10 seconds.";
2760 case RPLAYER_CHATRESULT_KICK:
2761 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2763 case RPLAYER_CHATRESULT_OK: break;
2764 default: FATAL_ERROR("Unhandled chat filtering result found.");
2768 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2769 return L"Your message exceed the maximum chat message limit set on the server. "
2770 L"It was refused. Send a shorter message";
2773 // Commands are implemented in Lua, so only catch invalid
2774 // commands that were not "eaten" and send an error back
2775 if (wmessage[0] == L'/') {
2776 std::wstring wcmd = wmessage.substr(1);
2777 broadcast_line = false;
2778 if (wcmd.length() == 0)
2779 line += L"-!- Empty command";
2781 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2783 if (check_shout_priv && !checkPriv(name, "shout")) {
2784 line += L"-!- You don't have permission to shout.";
2785 broadcast_line = false;
2795 Tell calling method to send the message to sender
2797 if (!broadcast_line) {
2801 Send the message to others
2803 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2805 std::vector<u16> clients = m_clients.getClientIDs();
2807 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2808 for (u16 i = 0; i < clients.size(); i++) {
2809 u16 cid = clients[i];
2810 if (cid != peer_id_to_avoid_sending)
2811 SendChatMessage(cid, line);
2817 void Server::handleAdminChat(const ChatEventChat *evt)
2819 std::string name = evt->nick;
2820 std::wstring wname = utf8_to_wide(name);
2821 std::wstring wmessage = evt->evt_msg;
2823 std::wstring answer = handleChat(name, wname, wmessage);
2825 // If asked to send answer to sender
2826 if (!answer.empty()) {
2827 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2831 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2833 RemoteClient *client = getClientNoEx(peer_id,state_min);
2835 throw ClientNotFoundException("Client not found");
2839 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2841 return m_clients.getClientNoEx(peer_id, state_min);
2844 std::string Server::getPlayerName(u16 peer_id)
2846 Player *player = m_env->getPlayer(peer_id);
2848 return "[id="+itos(peer_id)+"]";
2849 return player->getName();
2852 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2854 Player *player = m_env->getPlayer(peer_id);
2857 return player->getPlayerSAO();
2860 std::wstring Server::getStatusString()
2862 std::wostringstream os(std::ios_base::binary);
2865 os<<L"version="<<narrow_to_wide(g_version_string);
2867 os<<L", uptime="<<m_uptime.get();
2869 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2870 // Information about clients
2873 std::vector<u16> clients = m_clients.getClientIDs();
2874 for(std::vector<u16>::iterator i = clients.begin();
2875 i != clients.end(); ++i) {
2877 Player *player = m_env->getPlayer(*i);
2878 // Get name of player
2879 std::wstring name = L"unknown";
2881 name = narrow_to_wide(player->getName());
2882 // Add name to information string
2890 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2891 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2892 if(g_settings->get("motd") != "")
2893 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2897 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2899 std::set<std::string> privs;
2900 m_script->getAuth(name, NULL, &privs);
2904 bool Server::checkPriv(const std::string &name, const std::string &priv)
2906 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2907 return (privs.count(priv) != 0);
2910 void Server::reportPrivsModified(const std::string &name)
2913 std::vector<u16> clients = m_clients.getClientIDs();
2914 for(std::vector<u16>::iterator i = clients.begin();
2915 i != clients.end(); ++i) {
2916 Player *player = m_env->getPlayer(*i);
2917 reportPrivsModified(player->getName());
2920 Player *player = m_env->getPlayer(name.c_str());
2923 SendPlayerPrivileges(player->peer_id);
2924 PlayerSAO *sao = player->getPlayerSAO();
2927 sao->updatePrivileges(
2928 getPlayerEffectivePrivs(name),
2933 void Server::reportInventoryFormspecModified(const std::string &name)
2935 Player *player = m_env->getPlayer(name.c_str());
2938 SendPlayerInventoryFormspec(player->peer_id);
2941 void Server::setIpBanned(const std::string &ip, const std::string &name)
2943 m_banmanager->add(ip, name);
2946 void Server::unsetIpBanned(const std::string &ip_or_name)
2948 m_banmanager->remove(ip_or_name);
2951 std::string Server::getBanDescription(const std::string &ip_or_name)
2953 return m_banmanager->getBanDescription(ip_or_name);
2956 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2958 // m_env will be NULL if the server is initializing
2962 if (m_admin_nick == name && !m_admin_nick.empty()) {
2963 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2966 Player *player = m_env->getPlayer(name);
2971 if (player->peer_id == PEER_ID_INEXISTENT)
2974 SendChatMessage(player->peer_id, msg);
2977 bool Server::showFormspec(const char *playername, const std::string &formspec,
2978 const std::string &formname)
2980 // m_env will be NULL if the server is initializing
2984 Player *player = m_env->getPlayer(playername);
2988 SendShowFormspecMessage(player->peer_id, formspec, formname);
2992 u32 Server::hudAdd(Player *player, HudElement *form)
2997 u32 id = player->addHud(form);
2999 SendHUDAdd(player->peer_id, id, form);
3004 bool Server::hudRemove(Player *player, u32 id) {
3008 HudElement* todel = player->removeHud(id);
3015 SendHUDRemove(player->peer_id, id);
3019 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3024 SendHUDChange(player->peer_id, id, stat, data);
3028 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3033 SendHUDSetFlags(player->peer_id, flags, mask);
3034 player->hud_flags &= ~mask;
3035 player->hud_flags |= flags;
3037 PlayerSAO* playersao = player->getPlayerSAO();
3039 if (playersao == NULL)
3042 m_script->player_event(playersao, "hud_changed");
3046 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3050 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3053 player->setHotbarItemcount(hotbar_itemcount);
3054 std::ostringstream os(std::ios::binary);
3055 writeS32(os, hotbar_itemcount);
3056 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3060 s32 Server::hudGetHotbarItemcount(Player *player)
3064 return player->getHotbarItemcount();
3067 void Server::hudSetHotbarImage(Player *player, std::string name)
3072 player->setHotbarImage(name);
3073 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3076 std::string Server::hudGetHotbarImage(Player *player)
3080 return player->getHotbarImage();
3083 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3088 player->setHotbarSelectedImage(name);
3089 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3092 std::string Server::hudGetHotbarSelectedImage(Player *player)
3097 return player->getHotbarSelectedImage();
3100 bool Server::setLocalPlayerAnimations(Player *player,
3101 v2s32 animation_frames[4], f32 frame_speed)
3106 player->setLocalAnimations(animation_frames, frame_speed);
3107 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3111 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3116 player->eye_offset_first = first;
3117 player->eye_offset_third = third;
3118 SendEyeOffset(player->peer_id, first, third);
3122 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3123 const std::string &type, const std::vector<std::string> ¶ms)
3128 player->setSky(bgcolor, type, params);
3129 SendSetSky(player->peer_id, bgcolor, type, params);
3133 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3139 player->overrideDayNightRatio(do_override, ratio);
3140 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3144 void Server::notifyPlayers(const std::wstring &msg)
3146 SendChatMessage(PEER_ID_INEXISTENT,msg);
3149 void Server::spawnParticle(const std::string &playername, v3f pos,
3150 v3f velocity, v3f acceleration,
3151 float expirationtime, float size, bool
3152 collisiondetection, bool collision_removal,
3153 bool vertical, const std::string &texture)
3155 // m_env will be NULL if the server is initializing
3159 u16 peer_id = PEER_ID_INEXISTENT;
3160 if (playername != "") {
3161 Player* player = m_env->getPlayer(playername.c_str());
3164 peer_id = player->peer_id;
3167 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3168 expirationtime, size, collisiondetection,
3169 collision_removal, vertical, texture);
3172 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3173 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3174 float minexptime, float maxexptime, float minsize, float maxsize,
3175 bool collisiondetection, bool collision_removal,
3176 bool vertical, const std::string &texture,
3177 const std::string &playername)
3179 // m_env will be NULL if the server is initializing
3183 u16 peer_id = PEER_ID_INEXISTENT;
3184 if (playername != "") {
3185 Player* player = m_env->getPlayer(playername.c_str());
3188 peer_id = player->peer_id;
3191 u32 id = m_env->addParticleSpawner(spawntime);
3192 SendAddParticleSpawner(peer_id, amount, spawntime,
3193 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3194 minexptime, maxexptime, minsize, maxsize,
3195 collisiondetection, collision_removal, vertical, texture, id);
3200 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3202 // m_env will be NULL if the server is initializing
3204 throw ServerError("Can't delete particle spawners during initialisation!");
3206 u16 peer_id = PEER_ID_INEXISTENT;
3207 if (playername != "") {
3208 Player* player = m_env->getPlayer(playername.c_str());
3211 peer_id = player->peer_id;
3214 m_env->deleteParticleSpawner(id);
3215 SendDeleteParticleSpawner(peer_id, id);
3218 void Server::deleteParticleSpawnerAll(u32 id)
3220 m_env->deleteParticleSpawner(id);
3221 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3224 Inventory* Server::createDetachedInventory(const std::string &name)
3226 if(m_detached_inventories.count(name) > 0){
3227 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3228 delete m_detached_inventories[name];
3230 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3232 Inventory *inv = new Inventory(m_itemdef);
3234 m_detached_inventories[name] = inv;
3235 //TODO find a better way to do this
3236 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3240 // actions: time-reversed list
3241 // Return value: success/failure
3242 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3243 std::list<std::string> *log)
3245 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3246 ServerMap *map = (ServerMap*)(&m_env->getMap());
3248 // Fail if no actions to handle
3249 if(actions.empty()){
3250 log->push_back("Nothing to do.");
3257 for(std::list<RollbackAction>::const_iterator
3258 i = actions.begin();
3259 i != actions.end(); ++i)
3261 const RollbackAction &action = *i;
3263 bool success = action.applyRevert(map, this, this);
3266 std::ostringstream os;
3267 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3268 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3270 log->push_back(os.str());
3272 std::ostringstream os;
3273 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3274 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3276 log->push_back(os.str());
3280 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3281 <<" failed"<<std::endl;
3283 // Call it done if less than half failed
3284 return num_failed <= num_tried/2;
3287 // IGameDef interface
3289 IItemDefManager *Server::getItemDefManager()
3294 INodeDefManager *Server::getNodeDefManager()
3299 ICraftDefManager *Server::getCraftDefManager()
3303 ITextureSource *Server::getTextureSource()
3307 IShaderSource *Server::getShaderSource()
3311 scene::ISceneManager *Server::getSceneManager()
3316 u16 Server::allocateUnknownNodeId(const std::string &name)
3318 return m_nodedef->allocateDummy(name);
3321 ISoundManager *Server::getSoundManager()
3323 return &dummySoundManager;
3326 MtEventManager *Server::getEventManager()
3331 IWritableItemDefManager *Server::getWritableItemDefManager()
3336 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3341 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3346 const ModSpec *Server::getModSpec(const std::string &modname) const
3348 std::vector<ModSpec>::const_iterator it;
3349 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3350 const ModSpec &mod = *it;
3351 if (mod.name == modname)
3357 void Server::getModNames(std::vector<std::string> &modlist)
3359 std::vector<ModSpec>::iterator it;
3360 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3361 modlist.push_back(it->name);
3364 std::string Server::getBuiltinLuaPath()
3366 return porting::path_share + DIR_DELIM + "builtin";
3369 v3f Server::findSpawnPos()
3371 ServerMap &map = m_env->getServerMap();
3373 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3374 return nodeposf * BS;
3377 bool is_good = false;
3379 // Try to find a good place a few times
3380 for(s32 i = 0; i < 4000 && !is_good; i++) {
3382 // We're going to try to throw the player to this position
3383 v2s16 nodepos2d = v2s16(
3384 -range + (myrand() % (range * 2)),
3385 -range + (myrand() % (range * 2)));
3387 // Get spawn level at point
3388 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3389 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3390 // the mapgen to signify an unsuitable spawn position
3391 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3394 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3397 for (s32 i = 0; i < 10; i++) {
3398 v3s16 blockpos = getNodeBlockPos(nodepos);
3399 map.emergeBlock(blockpos, true);
3400 content_t c = map.getNodeNoEx(nodepos).getContent();
3401 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3403 if (air_count >= 2) {
3404 nodeposf = intToFloat(nodepos, BS);
3405 // Don't spawn the player outside map boundaries
3406 if (objectpos_over_limit(nodeposf))
3419 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3421 bool newplayer = false;
3424 Try to get an existing player
3426 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3428 // If player is already connected, cancel
3429 if(player != NULL && player->peer_id != 0)
3431 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3436 If player with the wanted peer_id already exists, cancel.
3438 if(m_env->getPlayer(peer_id) != NULL)
3440 infostream<<"emergePlayer(): Player with wrong name but same"
3441 " peer_id already exists"<<std::endl;
3445 // Load player if it isn't already loaded
3447 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3450 // Create player if it doesn't exist
3453 player = new RemotePlayer(this, name);
3454 // Set player position
3455 infostream<<"Server: Finding spawn place for player \""
3456 <<name<<"\""<<std::endl;
3457 v3f pos = findSpawnPos();
3458 player->setPosition(pos);
3460 // Make sure the player is saved
3461 player->setModified(true);
3463 // Add player to environment
3464 m_env->addPlayer(player);
3466 // If the player exists, ensure that they respawn inside legal bounds
3467 // This fixes an assert crash when the player can't be added
3468 // to the environment
3469 if (objectpos_over_limit(player->getPosition())) {
3470 actionstream << "Respawn position for player \""
3471 << name << "\" outside limits, resetting" << std::endl;
3472 v3f pos = findSpawnPos();
3473 player->setPosition(pos);
3477 // Create a new player active object
3478 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3479 getPlayerEffectivePrivs(player->getName()),
3482 player->protocol_version = proto_version;
3484 /* Clean up old HUD elements from previous sessions */
3487 /* Add object to environment */
3488 m_env->addActiveObject(playersao);
3492 m_script->on_newplayer(playersao);
3498 void dedicated_server_loop(Server &server, bool &kill)
3500 DSTACK(FUNCTION_NAME);
3502 verbosestream<<"dedicated_server_loop()"<<std::endl;
3504 IntervalLimiter m_profiler_interval;
3506 static const float steplen = g_settings->getFloat("dedicated_server_step");
3507 static const float profiler_print_interval =
3508 g_settings->getFloat("profiler_print_interval");
3511 // This is kind of a hack but can be done like this
3512 // because server.step() is very light
3514 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3515 sleep_ms((int)(steplen*1000.0));
3517 server.step(steplen);
3519 if(server.getShutdownRequested() || kill)
3521 infostream<<"Dedicated server quitting"<<std::endl;
3523 if(g_settings->getBool("server_announce"))
3524 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3532 if (profiler_print_interval != 0) {
3533 if(m_profiler_interval.step(steplen, profiler_print_interval))
3535 infostream<<"Profiler:"<<std::endl;
3536 g_profiler->print(infostream);
3537 g_profiler->clear();