3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_async_fatal_error(""),
166 m_enable_rollback_recording(false),
169 m_itemdef(createItemDefManager()),
170 m_nodedef(createNodeDefManager()),
171 m_craftdef(createCraftDefManager()),
172 m_event(new EventManager()),
174 m_time_of_day_send_timer(0),
177 m_shutdown_requested(false),
178 m_shutdown_ask_reconnect(false),
180 m_ignore_map_edit_events(false),
181 m_ignore_map_edit_events_peer_id(0),
185 m_liquid_transform_timer = 0.0;
186 m_liquid_transform_every = 1.0;
187 m_print_info_timer = 0.0;
188 m_masterserver_timer = 0.0;
189 m_objectdata_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if(!modconf.isConsistent()) {
229 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
230 it != unsatisfied_mods.end(); ++it) {
232 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
233 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
234 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
235 errorstream << " \"" << *dep_it << "\"";
236 errorstream << std::endl;
240 Settings worldmt_settings;
241 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
242 worldmt_settings.readConfigFile(worldmt.c_str());
243 std::vector<std::string> names = worldmt_settings.getNames();
244 std::set<std::string> load_mod_names;
245 for(std::vector<std::string>::iterator it = names.begin();
246 it != names.end(); ++it) {
247 std::string name = *it;
248 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
249 load_mod_names.insert(name.substr(9));
251 // complain about mods declared to be loaded, but not found
252 for(std::vector<ModSpec>::iterator it = m_mods.begin();
253 it != m_mods.end(); ++it)
254 load_mod_names.erase((*it).name);
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
257 load_mod_names.erase((*it).name);
258 if(!load_mod_names.empty()) {
259 errorstream << "The following mods could not be found:";
260 for(std::set<std::string>::iterator it = load_mod_names.begin();
261 it != load_mod_names.end(); ++it)
262 errorstream << " \"" << (*it) << "\"";
263 errorstream << std::endl;
267 MutexAutoLock envlock(m_env_mutex);
269 // Load mapgen params from Settings
270 m_emerge->loadMapgenParams();
272 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
273 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
275 // Initialize scripting
276 infostream<<"Server: Initializing Lua"<<std::endl;
278 m_script = new GameScripting(this);
280 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
282 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
285 infostream << "Server: Loading mods: ";
286 for(std::vector<ModSpec>::iterator i = m_mods.begin();
287 i != m_mods.end(); ++i) {
288 const ModSpec &mod = *i;
289 infostream << mod.name << " ";
291 infostream << std::endl;
292 // Load and run "mod" scripts
293 for (std::vector<ModSpec>::iterator it = m_mods.begin();
294 it != m_mods.end(); ++it) {
295 const ModSpec &mod = *it;
296 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
297 throw ModError("Error loading mod \"" + mod.name +
298 "\": Mod name does not follow naming conventions: "
299 "Only chararacters [a-z0-9_] are allowed.");
301 std::string script_path = mod.path + DIR_DELIM + "init.lua";
302 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
303 << script_path << "\"]" << std::endl;
304 m_script->loadMod(script_path, mod.name);
307 // Read Textures and calculate sha1 sums
310 // Apply item aliases in the node definition manager
311 m_nodedef->updateAliases(m_itemdef);
313 // Apply texture overrides from texturepack/override.txt
314 std::string texture_path = g_settings->get("texture_path");
315 if (texture_path != "" && fs::IsDir(texture_path))
316 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
318 m_nodedef->setNodeRegistrationStatus(true);
320 // Perform pending node name resolutions
321 m_nodedef->runNodeResolveCallbacks();
323 // 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 // Initialize mapgens
332 m_emerge->initMapgens();
334 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
335 if (m_enable_rollback_recording) {
336 // Create rollback manager
337 m_rollback = new RollbackManager(m_path_world, this);
340 // Give environment reference to scripting api
341 m_script->initializeEnvironment(m_env);
343 // Register us to receive map edit events
344 servermap->addEventReceiver(this);
346 // If file exists, load environment metadata
347 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
349 infostream<<"Server: Loading environment metadata"<<std::endl;
353 // Add some test ActiveBlockModifiers to environment
354 add_legacy_abms(m_env, m_nodedef);
356 m_liquid_transform_every = g_settings->getFloat("liquid_update");
361 infostream<<"Server destructing"<<std::endl;
363 // Send shutdown message
364 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
367 MutexAutoLock envlock(m_env_mutex);
369 // Execute script shutdown hooks
370 m_script->on_shutdown();
372 infostream << "Server: Saving players" << std::endl;
373 m_env->saveLoadedPlayers();
375 infostream << "Server: Kicking players" << std::endl;
376 std::string kick_msg;
377 bool reconnect = false;
378 if (getShutdownRequested()) {
379 reconnect = m_shutdown_ask_reconnect;
380 kick_msg = m_shutdown_msg;
382 if (kick_msg == "") {
383 kick_msg = g_settings->get("kick_msg_shutdown");
385 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
386 kick_msg, reconnect);
388 infostream << "Server: Saving environment metadata" << std::endl;
396 // stop all emerge threads before deleting players that may have
397 // requested blocks to be emerged
398 m_emerge->stopThreads();
400 // Delete things in the reverse order of creation
403 // N.B. the EmergeManager should be deleted after the Environment since Map
404 // depends on EmergeManager to write its current params to the map meta
413 // Deinitialize scripting
414 infostream<<"Server: Deinitializing scripting"<<std::endl;
417 // Delete detached inventories
418 for (std::map<std::string, Inventory*>::iterator
419 i = m_detached_inventories.begin();
420 i != m_detached_inventories.end(); ++i) {
425 void Server::start(Address bind_addr)
427 DSTACK(FUNCTION_NAME);
429 m_bind_addr = bind_addr;
431 infostream<<"Starting server on "
432 << bind_addr.serializeString() <<"..."<<std::endl;
434 // Stop thread if already running
437 // Initialize connection
438 m_con.SetTimeoutMs(30);
439 m_con.Serve(bind_addr);
444 // ASCII art for the win!
446 <<" .__ __ __ "<<std::endl
447 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
448 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
449 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
450 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
451 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
452 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
453 actionstream<<"Server for gameid=\""<<m_gamespec.id
454 <<"\" listening on "<<bind_addr.serializeString()<<":"
455 <<bind_addr.getPort() << "."<<std::endl;
460 DSTACK(FUNCTION_NAME);
462 infostream<<"Server: Stopping and waiting threads"<<std::endl;
464 // Stop threads (set run=false first so both start stopping)
466 //m_emergethread.setRun(false);
468 //m_emergethread.stop();
470 infostream<<"Server: Threads stopped"<<std::endl;
473 void Server::step(float dtime)
475 DSTACK(FUNCTION_NAME);
480 MutexAutoLock lock(m_step_dtime_mutex);
481 m_step_dtime += dtime;
483 // Throw if fatal error occurred in thread
484 std::string async_err = m_async_fatal_error.get();
485 if (!async_err.empty()) {
486 if (!m_simple_singleplayer_mode) {
487 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
488 g_settings->get("kick_msg_crash"),
489 g_settings->getBool("ask_reconnect_on_crash"));
491 throw ServerError(async_err);
495 void Server::AsyncRunStep(bool initial_step)
497 DSTACK(FUNCTION_NAME);
499 g_profiler->add("Server::AsyncRunStep (num)", 1);
503 MutexAutoLock lock1(m_step_dtime_mutex);
504 dtime = m_step_dtime;
508 // Send blocks to clients
512 if((dtime < 0.001) && (initial_step == false))
515 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
517 //infostream<<"Server steps "<<dtime<<std::endl;
518 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
521 MutexAutoLock lock1(m_step_dtime_mutex);
522 m_step_dtime -= dtime;
529 m_uptime.set(m_uptime.get() + dtime);
535 Update time of day and overall game time
537 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
540 Send to clients at constant intervals
543 m_time_of_day_send_timer -= dtime;
544 if(m_time_of_day_send_timer < 0.0) {
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
552 MutexAutoLock lock(m_env_mutex);
553 // Figure out and report maximum lag to environment
554 float max_lag = m_env->getMaxLagEstimate();
555 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
557 if(dtime > 0.1 && dtime > max_lag * 2.0)
558 infostream<<"Server: Maximum lag peaked to "<<dtime
562 m_env->reportMaxLagEstimate(max_lag);
564 ScopeProfiler sp(g_profiler, "SEnv step");
565 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
569 static const float map_timer_and_unload_dtime = 2.92;
570 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
572 MutexAutoLock lock(m_env_mutex);
573 // Run Map's timers and unload unused data
574 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
575 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
576 g_settings->getFloat("server_unload_unused_data_timeout"),
581 Listen to the admin chat, if available
584 if (!m_admin_chat->command_queue.empty()) {
585 MutexAutoLock lock(m_env_mutex);
586 while (!m_admin_chat->command_queue.empty()) {
587 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
588 if (evt->type == CET_NICK_ADD) {
589 // The terminal informed us of its nick choice
590 m_admin_nick = ((ChatEventNick *)evt)->nick;
591 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
592 errorstream << "You haven't set up an account." << std::endl
593 << "Please log in using the client as '"
594 << m_admin_nick << "' with a secure password." << std::endl
595 << "Until then, you can't execute admin tasks via the console," << std::endl
596 << "and everybody can claim the user account instead of you," << std::endl
597 << "giving them full control over this server." << std::endl;
600 assert(evt->type == CET_CHAT);
601 handleAdminChat((ChatEventChat *)evt);
606 m_admin_chat->outgoing_queue.push_back(
607 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
614 /* Transform liquids */
615 m_liquid_transform_timer += dtime;
616 if(m_liquid_transform_timer >= m_liquid_transform_every)
618 m_liquid_transform_timer -= m_liquid_transform_every;
620 MutexAutoLock lock(m_env_mutex);
622 ScopeProfiler sp(g_profiler, "Server: liquid transform");
624 std::map<v3s16, MapBlock*> modified_blocks;
625 m_env->getMap().transformLiquids(modified_blocks);
630 core::map<v3s16, MapBlock*> lighting_modified_blocks;
631 ServerMap &map = ((ServerMap&)m_env->getMap());
632 map.updateLighting(modified_blocks, lighting_modified_blocks);
634 // Add blocks modified by lighting to modified_blocks
635 for(core::map<v3s16, MapBlock*>::Iterator
636 i = lighting_modified_blocks.getIterator();
637 i.atEnd() == false; i++)
639 MapBlock *block = i.getNode()->getValue();
640 modified_blocks.insert(block->getPos(), block);
644 Set the modified blocks unsent for all the clients
646 if(!modified_blocks.empty())
648 SetBlocksNotSent(modified_blocks);
651 m_clients.step(dtime);
653 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
655 // send masterserver announce
657 float &counter = m_masterserver_timer;
658 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
659 g_settings->getBool("server_announce"))
661 ServerList::sendAnnounce(counter ? "update" : "start",
662 m_bind_addr.getPort(),
663 m_clients.getPlayerNames(),
665 m_env->getGameTime(),
668 m_emerge->params.mg_name,
677 Check added and deleted active objects
680 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
681 MutexAutoLock envlock(m_env_mutex);
684 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
685 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
687 // Radius inside which objects are active
688 s16 radius = g_settings->getS16("active_object_send_range_blocks");
689 s16 player_radius = g_settings->getS16("player_transfer_distance");
691 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
692 !g_settings->getBool("unlimited_player_transfer_distance"))
693 player_radius = radius;
695 radius *= MAP_BLOCKSIZE;
696 player_radius *= MAP_BLOCKSIZE;
698 for (std::map<u16, RemoteClient*>::iterator
700 i != clients.end(); ++i) {
701 RemoteClient *client = i->second;
703 // If definitions and textures have not been sent, don't
704 // send objects either
705 if (client->getState() < CS_DefinitionsSent)
708 Player *player = m_env->getPlayer(client->peer_id);
710 // This can happen if the client timeouts somehow
711 /*warningstream<<FUNCTION_NAME<<": Client "
713 <<" has no associated player"<<std::endl;*/
717 std::queue<u16> removed_objects;
718 std::queue<u16> added_objects;
719 m_env->getRemovedActiveObjects(player, radius, player_radius,
720 client->m_known_objects, removed_objects);
721 m_env->getAddedActiveObjects(player, radius, player_radius,
722 client->m_known_objects, added_objects);
724 // Ignore if nothing happened
725 if (removed_objects.empty() && added_objects.empty()) {
729 std::string data_buffer;
733 // Handle removed objects
734 writeU16((u8*)buf, removed_objects.size());
735 data_buffer.append(buf, 2);
736 while (!removed_objects.empty()) {
738 u16 id = removed_objects.front();
739 ServerActiveObject* obj = m_env->getActiveObject(id);
741 // Add to data buffer for sending
742 writeU16((u8*)buf, id);
743 data_buffer.append(buf, 2);
745 // Remove from known objects
746 client->m_known_objects.erase(id);
748 if(obj && obj->m_known_by_count > 0)
749 obj->m_known_by_count--;
750 removed_objects.pop();
753 // Handle added objects
754 writeU16((u8*)buf, added_objects.size());
755 data_buffer.append(buf, 2);
756 while (!added_objects.empty()) {
758 u16 id = added_objects.front();
759 ServerActiveObject* obj = m_env->getActiveObject(id);
762 u8 type = ACTIVEOBJECT_TYPE_INVALID;
764 warningstream<<FUNCTION_NAME
765 <<": NULL object"<<std::endl;
767 type = obj->getSendType();
769 // Add to data buffer for sending
770 writeU16((u8*)buf, id);
771 data_buffer.append(buf, 2);
772 writeU8((u8*)buf, type);
773 data_buffer.append(buf, 1);
776 data_buffer.append(serializeLongString(
777 obj->getClientInitializationData(client->net_proto_version)));
779 data_buffer.append(serializeLongString(""));
781 // Add to known objects
782 client->m_known_objects.insert(id);
785 obj->m_known_by_count++;
790 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
791 verbosestream << "Server: Sent object remove/add: "
792 << removed_objects.size() << " removed, "
793 << added_objects.size() << " added, "
794 << "packet size is " << pktSize << std::endl;
803 MutexAutoLock envlock(m_env_mutex);
804 ScopeProfiler sp(g_profiler, "Server: sending object messages");
807 // Value = data sent by object
808 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
810 // Get active object messages from environment
812 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
816 std::vector<ActiveObjectMessage>* message_list = NULL;
817 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
818 n = buffered_messages.find(aom.id);
819 if (n == buffered_messages.end()) {
820 message_list = new std::vector<ActiveObjectMessage>;
821 buffered_messages[aom.id] = message_list;
824 message_list = n->second;
826 message_list->push_back(aom);
830 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
831 // Route data to every client
832 for (std::map<u16, RemoteClient*>::iterator
834 i != clients.end(); ++i) {
835 RemoteClient *client = i->second;
836 std::string reliable_data;
837 std::string unreliable_data;
838 // Go through all objects in message buffer
839 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
840 j = buffered_messages.begin();
841 j != buffered_messages.end(); ++j) {
842 // If object is not known by client, skip it
844 if (client->m_known_objects.find(id) == client->m_known_objects.end())
847 // Get message list of object
848 std::vector<ActiveObjectMessage>* list = j->second;
849 // Go through every message
850 for (std::vector<ActiveObjectMessage>::iterator
851 k = list->begin(); k != list->end(); ++k) {
852 // Compose the full new data with header
853 ActiveObjectMessage aom = *k;
854 std::string new_data;
857 writeU16((u8*)&buf[0], aom.id);
858 new_data.append(buf, 2);
860 new_data += serializeString(aom.datastring);
861 // Add data to buffer
863 reliable_data += new_data;
865 unreliable_data += new_data;
869 reliable_data and unreliable_data are now ready.
872 if(reliable_data.size() > 0) {
873 SendActiveObjectMessages(client->peer_id, reliable_data);
876 if(unreliable_data.size() > 0) {
877 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
882 // Clear buffered_messages
883 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
884 i = buffered_messages.begin();
885 i != buffered_messages.end(); ++i) {
891 Send queued-for-sending map edit events.
894 // We will be accessing the environment
895 MutexAutoLock lock(m_env_mutex);
897 // Don't send too many at a time
900 // Single change sending is disabled if queue size is not small
901 bool disable_single_change_sending = false;
902 if(m_unsent_map_edit_queue.size() >= 4)
903 disable_single_change_sending = true;
905 int event_count = m_unsent_map_edit_queue.size();
907 // We'll log the amount of each
910 while(m_unsent_map_edit_queue.size() != 0)
912 MapEditEvent* event = m_unsent_map_edit_queue.front();
913 m_unsent_map_edit_queue.pop();
915 // Players far away from the change are stored here.
916 // Instead of sending the changes, MapBlocks are set not sent
918 std::vector<u16> far_players;
920 switch (event->type) {
923 prof.add("MEET_ADDNODE", 1);
924 sendAddNode(event->p, event->n, event->already_known_by_peer,
925 &far_players, disable_single_change_sending ? 5 : 30,
926 event->type == MEET_ADDNODE);
928 case MEET_REMOVENODE:
929 prof.add("MEET_REMOVENODE", 1);
930 sendRemoveNode(event->p, event->already_known_by_peer,
931 &far_players, disable_single_change_sending ? 5 : 30);
933 case MEET_BLOCK_NODE_METADATA_CHANGED:
934 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
935 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
936 setBlockNotSent(event->p);
939 infostream << "Server: MEET_OTHER" << std::endl;
940 prof.add("MEET_OTHER", 1);
941 for(std::set<v3s16>::iterator
942 i = event->modified_blocks.begin();
943 i != event->modified_blocks.end(); ++i) {
948 prof.add("unknown", 1);
949 warningstream << "Server: Unknown MapEditEvent "
950 << ((u32)event->type) << std::endl;
955 Set blocks not sent to far players
957 if(!far_players.empty()) {
958 // Convert list format to that wanted by SetBlocksNotSent
959 std::map<v3s16, MapBlock*> modified_blocks2;
960 for(std::set<v3s16>::iterator
961 i = event->modified_blocks.begin();
962 i != event->modified_blocks.end(); ++i) {
963 modified_blocks2[*i] =
964 m_env->getMap().getBlockNoCreateNoEx(*i);
967 // Set blocks not sent
968 for(std::vector<u16>::iterator
969 i = far_players.begin();
970 i != far_players.end(); ++i) {
971 if(RemoteClient *client = getClient(*i))
972 client->SetBlocksNotSent(modified_blocks2);
978 /*// Don't send too many at a time
980 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
984 if(event_count >= 5){
985 infostream<<"Server: MapEditEvents:"<<std::endl;
986 prof.print(infostream);
987 } else if(event_count != 0){
988 verbosestream<<"Server: MapEditEvents:"<<std::endl;
989 prof.print(verbosestream);
995 Trigger emergethread (it somehow gets to a non-triggered but
996 bysy state sometimes)
999 float &counter = m_emergethread_trigger_timer;
1005 m_emerge->startThreads();
1009 // Save map, players and auth stuff
1011 float &counter = m_savemap_timer;
1013 if(counter >= g_settings->getFloat("server_map_save_interval"))
1016 MutexAutoLock lock(m_env_mutex);
1018 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1021 if (m_banmanager->isModified()) {
1022 m_banmanager->save();
1025 // Save changed parts of map
1026 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1029 m_env->saveLoadedPlayers();
1031 // Save environment metadata
1037 void Server::Receive()
1039 DSTACK(FUNCTION_NAME);
1040 SharedBuffer<u8> data;
1044 m_con.Receive(&pkt);
1045 peer_id = pkt.getPeerId();
1048 catch(con::InvalidIncomingDataException &e) {
1049 infostream<<"Server::Receive(): "
1050 "InvalidIncomingDataException: what()="
1051 <<e.what()<<std::endl;
1053 catch(SerializationError &e) {
1054 infostream<<"Server::Receive(): "
1055 "SerializationError: what()="
1056 <<e.what()<<std::endl;
1058 catch(ClientStateError &e) {
1059 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1060 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1061 L"Try reconnecting or updating your client");
1063 catch(con::PeerNotFoundException &e) {
1068 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1070 std::string playername = "";
1071 PlayerSAO *playersao = NULL;
1074 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1075 if (client != NULL) {
1076 playername = client->getName();
1077 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1079 } catch (std::exception &e) {
1085 RemotePlayer *player =
1086 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1088 // If failed, cancel
1089 if ((playersao == NULL) || (player == NULL)) {
1090 if (player && player->peer_id != 0) {
1091 actionstream << "Server: Failed to emerge player \"" << playername
1092 << "\" (player allocated to an another client)" << std::endl;
1093 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1094 L"name. If your client closed unexpectedly, try again in "
1097 errorstream << "Server: " << playername << ": Failed to emerge player"
1099 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1105 Send complete position information
1107 SendMovePlayer(peer_id);
1110 SendPlayerPrivileges(peer_id);
1112 // Send inventory formspec
1113 SendPlayerInventoryFormspec(peer_id);
1116 SendInventory(playersao);
1119 SendPlayerHPOrDie(playersao);
1122 SendPlayerBreath(peer_id);
1124 // Show death screen if necessary
1125 if(player->isDead())
1126 SendDeathscreen(peer_id, false, v3f(0,0,0));
1128 // Note things in chat if not in simple singleplayer mode
1129 if(!m_simple_singleplayer_mode) {
1130 // Send information about server to player in chat
1131 SendChatMessage(peer_id, getStatusString());
1133 // Send information about joining in chat
1135 std::string name = "unknown";
1136 Player *player = m_env->getPlayer(peer_id);
1138 name = player->getName();
1140 std::wstring message;
1142 message += narrow_to_wide(name);
1143 message += L" joined the game.";
1144 SendChatMessage(PEER_ID_INEXISTENT,message);
1146 m_admin_chat->outgoing_queue.push_back(
1147 new ChatEventNick(CET_NICK_ADD, name));
1150 Address addr = getPeerAddress(player->peer_id);
1151 std::string ip_str = addr.serializeString();
1152 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1157 std::vector<std::string> names = m_clients.getPlayerNames();
1159 actionstream<<player->getName() <<" joins game. List of players: ";
1161 for (std::vector<std::string>::iterator i = names.begin();
1162 i != names.end(); ++i) {
1163 actionstream << *i << " ";
1166 actionstream << player->getName() <<std::endl;
1171 inline void Server::handleCommand(NetworkPacket* pkt)
1173 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1174 (this->*opHandle.handler)(pkt);
1177 void Server::ProcessData(NetworkPacket *pkt)
1179 DSTACK(FUNCTION_NAME);
1180 // Environment is locked first.
1181 MutexAutoLock envlock(m_env_mutex);
1183 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1184 u32 peer_id = pkt->getPeerId();
1187 Address address = getPeerAddress(peer_id);
1188 std::string addr_s = address.serializeString();
1190 if(m_banmanager->isIpBanned(addr_s)) {
1191 std::string ban_name = m_banmanager->getBanName(addr_s);
1192 infostream << "Server: A banned client tried to connect from "
1193 << addr_s << "; banned name was "
1194 << ban_name << std::endl;
1195 // This actually doesn't seem to transfer to the client
1196 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1197 + utf8_to_wide(ban_name));
1201 catch(con::PeerNotFoundException &e) {
1203 * no peer for this packet found
1204 * most common reason is peer timeout, e.g. peer didn't
1205 * respond for some time, your server was overloaded or
1208 infostream << "Server::ProcessData(): Canceling: peer "
1209 << peer_id << " not found" << std::endl;
1214 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1216 // Command must be handled into ToServerCommandHandler
1217 if (command >= TOSERVER_NUM_MSG_TYPES) {
1218 infostream << "Server: Ignoring unknown command "
1219 << command << std::endl;
1223 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1228 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1230 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1231 errorstream << "Server::ProcessData(): Cancelling: Peer"
1232 " serialization format invalid or not initialized."
1233 " Skipping incoming command=" << command << std::endl;
1237 /* Handle commands related to client startup */
1238 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1243 if (m_clients.getClientState(peer_id) < CS_Active) {
1244 if (command == TOSERVER_PLAYERPOS) return;
1246 errorstream << "Got packet command: " << command << " for peer id "
1247 << peer_id << " but client isn't active yet. Dropping packet "
1253 } catch (SendFailedException &e) {
1254 errorstream << "Server::ProcessData(): SendFailedException: "
1255 << "what=" << e.what()
1257 } catch (PacketError &e) {
1258 actionstream << "Server::ProcessData(): PacketError: "
1259 << "what=" << e.what()
1264 void Server::setTimeOfDay(u32 time)
1266 m_env->setTimeOfDay(time);
1267 m_time_of_day_send_timer = 0;
1270 void Server::onMapEditEvent(MapEditEvent *event)
1272 if(m_ignore_map_edit_events)
1274 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1276 MapEditEvent *e = event->clone();
1277 m_unsent_map_edit_queue.push(e);
1280 Inventory* Server::getInventory(const InventoryLocation &loc)
1283 case InventoryLocation::UNDEFINED:
1284 case InventoryLocation::CURRENT_PLAYER:
1286 case InventoryLocation::PLAYER:
1288 Player *player = m_env->getPlayer(loc.name.c_str());
1291 PlayerSAO *playersao = player->getPlayerSAO();
1294 return playersao->getInventory();
1297 case InventoryLocation::NODEMETA:
1299 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1302 return meta->getInventory();
1305 case InventoryLocation::DETACHED:
1307 if(m_detached_inventories.count(loc.name) == 0)
1309 return m_detached_inventories[loc.name];
1313 sanity_check(false); // abort
1318 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1321 case InventoryLocation::UNDEFINED:
1323 case InventoryLocation::PLAYER:
1328 Player *player = m_env->getPlayer(loc.name.c_str());
1331 PlayerSAO *playersao = player->getPlayerSAO();
1335 SendInventory(playersao);
1338 case InventoryLocation::NODEMETA:
1340 v3s16 blockpos = getNodeBlockPos(loc.p);
1342 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1344 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1346 setBlockNotSent(blockpos);
1349 case InventoryLocation::DETACHED:
1351 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1355 sanity_check(false); // abort
1360 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1362 std::vector<u16> clients = m_clients.getClientIDs();
1364 // Set the modified blocks unsent for all the clients
1365 for (std::vector<u16>::iterator i = clients.begin();
1366 i != clients.end(); ++i) {
1367 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1368 client->SetBlocksNotSent(block);
1373 void Server::peerAdded(con::Peer *peer)
1375 DSTACK(FUNCTION_NAME);
1376 verbosestream<<"Server::peerAdded(): peer->id="
1377 <<peer->id<<std::endl;
1380 c.type = con::PEER_ADDED;
1381 c.peer_id = peer->id;
1383 m_peer_change_queue.push(c);
1386 void Server::deletingPeer(con::Peer *peer, bool timeout)
1388 DSTACK(FUNCTION_NAME);
1389 verbosestream<<"Server::deletingPeer(): peer->id="
1390 <<peer->id<<", timeout="<<timeout<<std::endl;
1392 m_clients.event(peer->id, CSE_Disconnect);
1394 c.type = con::PEER_REMOVED;
1395 c.peer_id = peer->id;
1396 c.timeout = timeout;
1397 m_peer_change_queue.push(c);
1400 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1402 *retval = m_con.getPeerStat(peer_id,type);
1403 if (*retval == -1) return false;
1407 bool Server::getClientInfo(
1416 std::string* vers_string
1419 *state = m_clients.getClientState(peer_id);
1421 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1423 if (client == NULL) {
1428 *uptime = client->uptime();
1429 *ser_vers = client->serialization_version;
1430 *prot_vers = client->net_proto_version;
1432 *major = client->getMajor();
1433 *minor = client->getMinor();
1434 *patch = client->getPatch();
1435 *vers_string = client->getPatch();
1442 void Server::handlePeerChanges()
1444 while(m_peer_change_queue.size() > 0)
1446 con::PeerChange c = m_peer_change_queue.front();
1447 m_peer_change_queue.pop();
1449 verbosestream<<"Server: Handling peer change: "
1450 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1455 case con::PEER_ADDED:
1456 m_clients.CreateClient(c.peer_id);
1459 case con::PEER_REMOVED:
1460 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1464 FATAL_ERROR("Invalid peer change event received!");
1470 void Server::printToConsoleOnly(const std::string &text)
1473 m_admin_chat->outgoing_queue.push_back(
1474 new ChatEventChat("", utf8_to_wide(text)));
1480 void Server::Send(NetworkPacket* pkt)
1482 m_clients.send(pkt->getPeerId(),
1483 clientCommandFactoryTable[pkt->getCommand()].channel,
1485 clientCommandFactoryTable[pkt->getCommand()].reliable);
1488 void Server::SendMovement(u16 peer_id)
1490 DSTACK(FUNCTION_NAME);
1491 std::ostringstream os(std::ios_base::binary);
1493 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1495 pkt << g_settings->getFloat("movement_acceleration_default");
1496 pkt << g_settings->getFloat("movement_acceleration_air");
1497 pkt << g_settings->getFloat("movement_acceleration_fast");
1498 pkt << g_settings->getFloat("movement_speed_walk");
1499 pkt << g_settings->getFloat("movement_speed_crouch");
1500 pkt << g_settings->getFloat("movement_speed_fast");
1501 pkt << g_settings->getFloat("movement_speed_climb");
1502 pkt << g_settings->getFloat("movement_speed_jump");
1503 pkt << g_settings->getFloat("movement_liquid_fluidity");
1504 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1505 pkt << g_settings->getFloat("movement_liquid_sink");
1506 pkt << g_settings->getFloat("movement_gravity");
1511 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1513 if (!g_settings->getBool("enable_damage"))
1516 u16 peer_id = playersao->getPeerID();
1517 bool is_alive = playersao->getHP() > 0;
1520 SendPlayerHP(peer_id);
1525 void Server::SendHP(u16 peer_id, u8 hp)
1527 DSTACK(FUNCTION_NAME);
1529 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1534 void Server::SendBreath(u16 peer_id, u16 breath)
1536 DSTACK(FUNCTION_NAME);
1538 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1539 pkt << (u16) breath;
1543 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1544 const std::string &custom_reason, bool reconnect)
1546 assert(reason < SERVER_ACCESSDENIED_MAX);
1548 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1550 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1551 pkt << custom_reason;
1552 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1553 reason == SERVER_ACCESSDENIED_CRASH)
1554 pkt << custom_reason << (u8)reconnect;
1558 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1560 DSTACK(FUNCTION_NAME);
1562 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1567 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1568 v3f camera_point_target)
1570 DSTACK(FUNCTION_NAME);
1572 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1573 pkt << set_camera_point_target << camera_point_target;
1577 void Server::SendItemDef(u16 peer_id,
1578 IItemDefManager *itemdef, u16 protocol_version)
1580 DSTACK(FUNCTION_NAME);
1582 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1586 u32 length of the next item
1587 zlib-compressed serialized ItemDefManager
1589 std::ostringstream tmp_os(std::ios::binary);
1590 itemdef->serialize(tmp_os, protocol_version);
1591 std::ostringstream tmp_os2(std::ios::binary);
1592 compressZlib(tmp_os.str(), tmp_os2);
1593 pkt.putLongString(tmp_os2.str());
1596 verbosestream << "Server: Sending item definitions to id(" << peer_id
1597 << "): size=" << pkt.getSize() << std::endl;
1602 void Server::SendNodeDef(u16 peer_id,
1603 INodeDefManager *nodedef, u16 protocol_version)
1605 DSTACK(FUNCTION_NAME);
1607 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1611 u32 length of the next item
1612 zlib-compressed serialized NodeDefManager
1614 std::ostringstream tmp_os(std::ios::binary);
1615 nodedef->serialize(tmp_os, protocol_version);
1616 std::ostringstream tmp_os2(std::ios::binary);
1617 compressZlib(tmp_os.str(), tmp_os2);
1619 pkt.putLongString(tmp_os2.str());
1622 verbosestream << "Server: Sending node definitions to id(" << peer_id
1623 << "): size=" << pkt.getSize() << std::endl;
1629 Non-static send methods
1632 void Server::SendInventory(PlayerSAO* playerSAO)
1634 DSTACK(FUNCTION_NAME);
1636 UpdateCrafting(playerSAO->getPlayer());
1642 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1644 std::ostringstream os;
1645 playerSAO->getInventory()->serialize(os);
1647 std::string s = os.str();
1649 pkt.putRawString(s.c_str(), s.size());
1653 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1655 DSTACK(FUNCTION_NAME);
1657 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1660 if (peer_id != PEER_ID_INEXISTENT) {
1664 m_clients.sendToAll(0, &pkt, true);
1668 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1669 const std::string &formname)
1671 DSTACK(FUNCTION_NAME);
1673 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1675 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1681 // Spawns a particle on peer with peer_id
1682 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1683 float expirationtime, float size, bool collisiondetection,
1684 bool vertical, std::string texture)
1686 DSTACK(FUNCTION_NAME);
1688 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1690 pkt << pos << velocity << acceleration << expirationtime
1691 << size << collisiondetection;
1692 pkt.putLongString(texture);
1695 if (peer_id != PEER_ID_INEXISTENT) {
1699 m_clients.sendToAll(0, &pkt, true);
1703 // Adds a ParticleSpawner on peer with peer_id
1704 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1705 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1706 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1708 DSTACK(FUNCTION_NAME);
1710 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1712 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1713 << minacc << maxacc << minexptime << maxexptime << minsize
1714 << maxsize << collisiondetection;
1716 pkt.putLongString(texture);
1718 pkt << id << vertical;
1720 if (peer_id != PEER_ID_INEXISTENT) {
1724 m_clients.sendToAll(0, &pkt, true);
1728 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1730 DSTACK(FUNCTION_NAME);
1732 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1734 // Ugly error in this packet
1737 if (peer_id != PEER_ID_INEXISTENT) {
1741 m_clients.sendToAll(0, &pkt, true);
1746 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1748 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1750 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1751 << form->text << form->number << form->item << form->dir
1752 << form->align << form->offset << form->world_pos << form->size;
1757 void Server::SendHUDRemove(u16 peer_id, u32 id)
1759 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1764 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1766 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1767 pkt << id << (u8) stat;
1771 case HUD_STAT_SCALE:
1772 case HUD_STAT_ALIGN:
1773 case HUD_STAT_OFFSET:
1774 pkt << *(v2f *) value;
1778 pkt << *(std::string *) value;
1780 case HUD_STAT_WORLD_POS:
1781 pkt << *(v3f *) value;
1784 pkt << *(v2s32 *) value;
1786 case HUD_STAT_NUMBER:
1790 pkt << *(u32 *) value;
1797 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1799 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1801 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1803 pkt << flags << mask;
1808 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1810 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1811 pkt << param << value;
1815 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1816 const std::string &type, const std::vector<std::string> ¶ms)
1818 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1819 pkt << bgcolor << type << (u16) params.size();
1821 for(size_t i=0; i<params.size(); i++)
1827 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1830 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1833 pkt << do_override << (u16) (ratio * 65535);
1838 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1840 DSTACK(FUNCTION_NAME);
1842 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1843 pkt << time << time_speed;
1845 if (peer_id == PEER_ID_INEXISTENT) {
1846 m_clients.sendToAll(0, &pkt, true);
1853 void Server::SendPlayerHP(u16 peer_id)
1855 DSTACK(FUNCTION_NAME);
1856 PlayerSAO *playersao = getPlayerSAO(peer_id);
1857 // In some rare case, if the player is disconnected
1858 // while Lua call l_punch, for example, this can be NULL
1862 SendHP(peer_id, playersao->getHP());
1863 m_script->player_event(playersao,"health_changed");
1865 // Send to other clients
1866 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1867 ActiveObjectMessage aom(playersao->getId(), true, str);
1868 playersao->m_messages_out.push(aom);
1871 void Server::SendPlayerBreath(u16 peer_id)
1873 DSTACK(FUNCTION_NAME);
1874 PlayerSAO *playersao = getPlayerSAO(peer_id);
1877 m_script->player_event(playersao, "breath_changed");
1878 SendBreath(peer_id, playersao->getBreath());
1881 void Server::SendMovePlayer(u16 peer_id)
1883 DSTACK(FUNCTION_NAME);
1884 Player *player = m_env->getPlayer(peer_id);
1887 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1888 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1891 v3f pos = player->getPosition();
1892 f32 pitch = player->getPitch();
1893 f32 yaw = player->getYaw();
1894 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1895 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1896 << " pitch=" << pitch
1904 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1906 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1909 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1910 << animation_frames[3] << animation_speed;
1915 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1917 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1918 pkt << first << third;
1921 void Server::SendPlayerPrivileges(u16 peer_id)
1923 Player *player = m_env->getPlayer(peer_id);
1925 if(player->peer_id == PEER_ID_INEXISTENT)
1928 std::set<std::string> privs;
1929 m_script->getAuth(player->getName(), NULL, &privs);
1931 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1932 pkt << (u16) privs.size();
1934 for(std::set<std::string>::const_iterator i = privs.begin();
1935 i != privs.end(); ++i) {
1942 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1944 Player *player = m_env->getPlayer(peer_id);
1946 if(player->peer_id == PEER_ID_INEXISTENT)
1949 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1950 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1954 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1956 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1957 pkt.putRawString(datas.c_str(), datas.size());
1959 return pkt.getSize();
1962 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1964 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1965 datas.size(), peer_id);
1967 pkt.putRawString(datas.c_str(), datas.size());
1969 m_clients.send(pkt.getPeerId(),
1970 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1975 s32 Server::playSound(const SimpleSoundSpec &spec,
1976 const ServerSoundParams ¶ms)
1978 // Find out initial position of sound
1979 bool pos_exists = false;
1980 v3f pos = params.getPos(m_env, &pos_exists);
1981 // If position is not found while it should be, cancel sound
1982 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1985 // Filter destination clients
1986 std::vector<u16> dst_clients;
1987 if(params.to_player != "")
1989 Player *player = m_env->getPlayer(params.to_player.c_str());
1991 infostream<<"Server::playSound: Player \""<<params.to_player
1992 <<"\" not found"<<std::endl;
1995 if(player->peer_id == PEER_ID_INEXISTENT){
1996 infostream<<"Server::playSound: Player \""<<params.to_player
1997 <<"\" not connected"<<std::endl;
2000 dst_clients.push_back(player->peer_id);
2003 std::vector<u16> clients = m_clients.getClientIDs();
2005 for(std::vector<u16>::iterator
2006 i = clients.begin(); i != clients.end(); ++i) {
2007 Player *player = m_env->getPlayer(*i);
2012 if(player->getPosition().getDistanceFrom(pos) >
2013 params.max_hear_distance)
2016 dst_clients.push_back(*i);
2020 if(dst_clients.empty())
2024 s32 id = m_next_sound_id++;
2025 // The sound will exist as a reference in m_playing_sounds
2026 m_playing_sounds[id] = ServerPlayingSound();
2027 ServerPlayingSound &psound = m_playing_sounds[id];
2028 psound.params = params;
2030 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2031 pkt << id << spec.name << (float) (spec.gain * params.gain)
2032 << (u8) params.type << pos << params.object << params.loop;
2034 for(std::vector<u16>::iterator i = dst_clients.begin();
2035 i != dst_clients.end(); ++i) {
2036 psound.clients.insert(*i);
2037 m_clients.send(*i, 0, &pkt, true);
2041 void Server::stopSound(s32 handle)
2043 // Get sound reference
2044 std::map<s32, ServerPlayingSound>::iterator i =
2045 m_playing_sounds.find(handle);
2046 if(i == m_playing_sounds.end())
2048 ServerPlayingSound &psound = i->second;
2050 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2053 for(std::set<u16>::iterator i = psound.clients.begin();
2054 i != psound.clients.end(); ++i) {
2056 m_clients.send(*i, 0, &pkt, true);
2058 // Remove sound reference
2059 m_playing_sounds.erase(i);
2062 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2063 std::vector<u16> *far_players, float far_d_nodes)
2065 float maxd = far_d_nodes*BS;
2066 v3f p_f = intToFloat(p, BS);
2068 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2071 std::vector<u16> clients = m_clients.getClientIDs();
2072 for(std::vector<u16>::iterator i = clients.begin();
2073 i != clients.end(); ++i) {
2076 if(Player *player = m_env->getPlayer(*i)) {
2077 // If player is far away, only set modified blocks not sent
2078 v3f player_pos = player->getPosition();
2079 if(player_pos.getDistanceFrom(p_f) > maxd) {
2080 far_players->push_back(*i);
2087 m_clients.send(*i, 0, &pkt, true);
2091 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2092 std::vector<u16> *far_players, float far_d_nodes,
2093 bool remove_metadata)
2095 float maxd = far_d_nodes*BS;
2096 v3f p_f = intToFloat(p, BS);
2098 std::vector<u16> clients = m_clients.getClientIDs();
2099 for(std::vector<u16>::iterator i = clients.begin();
2100 i != clients.end(); ++i) {
2104 if(Player *player = m_env->getPlayer(*i)) {
2105 // If player is far away, only set modified blocks not sent
2106 v3f player_pos = player->getPosition();
2107 if(player_pos.getDistanceFrom(p_f) > maxd) {
2108 far_players->push_back(*i);
2114 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2116 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2118 pkt << p << n.param0 << n.param1 << n.param2
2119 << (u8) (remove_metadata ? 0 : 1);
2121 if (!remove_metadata) {
2122 if (client->net_proto_version <= 21) {
2123 // Old clients always clear metadata; fix it
2124 // by sending the full block again.
2125 client->SetBlockNotSent(getNodeBlockPos(p));
2132 if (pkt.getSize() > 0)
2133 m_clients.send(*i, 0, &pkt, true);
2137 void Server::setBlockNotSent(v3s16 p)
2139 std::vector<u16> clients = m_clients.getClientIDs();
2141 for(std::vector<u16>::iterator i = clients.begin();
2142 i != clients.end(); ++i) {
2143 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2144 client->SetBlockNotSent(p);
2149 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2151 DSTACK(FUNCTION_NAME);
2153 v3s16 p = block->getPos();
2156 Create a packet with the block in the right format
2159 std::ostringstream os(std::ios_base::binary);
2160 block->serialize(os, ver, false);
2161 block->serializeNetworkSpecific(os, net_proto_version);
2162 std::string s = os.str();
2164 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2167 pkt.putRawString(s.c_str(), s.size());
2171 void Server::SendBlocks(float dtime)
2173 DSTACK(FUNCTION_NAME);
2175 MutexAutoLock envlock(m_env_mutex);
2176 //TODO check if one big lock could be faster then multiple small ones
2178 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2180 std::vector<PrioritySortedBlockTransfer> queue;
2182 s32 total_sending = 0;
2185 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2187 std::vector<u16> clients = m_clients.getClientIDs();
2190 for(std::vector<u16>::iterator i = clients.begin();
2191 i != clients.end(); ++i) {
2192 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2197 total_sending += client->SendingCount();
2198 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2204 // Lowest priority number comes first.
2205 // Lowest is most important.
2206 std::sort(queue.begin(), queue.end());
2209 for(u32 i=0; i<queue.size(); i++)
2211 //TODO: Calculate limit dynamically
2212 if(total_sending >= g_settings->getS32
2213 ("max_simultaneous_block_sends_server_total"))
2216 PrioritySortedBlockTransfer q = queue[i];
2218 MapBlock *block = NULL;
2221 block = m_env->getMap().getBlockNoCreate(q.pos);
2223 catch(InvalidPositionException &e)
2228 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2233 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2235 client->SentBlock(q.pos);
2241 void Server::fillMediaCache()
2243 DSTACK(FUNCTION_NAME);
2245 infostream<<"Server: Calculating media file checksums"<<std::endl;
2247 // Collect all media file paths
2248 std::vector<std::string> paths;
2249 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2250 i != m_mods.end(); ++i) {
2251 const ModSpec &mod = *i;
2252 paths.push_back(mod.path + DIR_DELIM + "textures");
2253 paths.push_back(mod.path + DIR_DELIM + "sounds");
2254 paths.push_back(mod.path + DIR_DELIM + "media");
2255 paths.push_back(mod.path + DIR_DELIM + "models");
2257 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2259 // Collect media file information from paths into cache
2260 for(std::vector<std::string>::iterator i = paths.begin();
2261 i != paths.end(); ++i) {
2262 std::string mediapath = *i;
2263 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2264 for (u32 j = 0; j < dirlist.size(); j++) {
2265 if (dirlist[j].dir) // Ignode dirs
2267 std::string filename = dirlist[j].name;
2268 // If name contains illegal characters, ignore the file
2269 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2270 infostream<<"Server: ignoring illegal file name: \""
2271 << filename << "\"" << std::endl;
2274 // If name is not in a supported format, ignore it
2275 const char *supported_ext[] = {
2276 ".png", ".jpg", ".bmp", ".tga",
2277 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2279 ".x", ".b3d", ".md2", ".obj",
2282 if (removeStringEnd(filename, supported_ext) == ""){
2283 infostream << "Server: ignoring unsupported file extension: \""
2284 << filename << "\"" << std::endl;
2287 // Ok, attempt to load the file and add to cache
2288 std::string filepath = mediapath + DIR_DELIM + filename;
2290 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2292 errorstream << "Server::fillMediaCache(): Could not open \""
2293 << filename << "\" for reading" << std::endl;
2296 std::ostringstream tmp_os(std::ios_base::binary);
2300 fis.read(buf, 1024);
2301 std::streamsize len = fis.gcount();
2302 tmp_os.write(buf, len);
2311 errorstream<<"Server::fillMediaCache(): Failed to read \""
2312 << filename << "\"" << std::endl;
2315 if(tmp_os.str().length() == 0) {
2316 errorstream << "Server::fillMediaCache(): Empty file \""
2317 << filepath << "\"" << std::endl;
2322 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2324 unsigned char *digest = sha1.getDigest();
2325 std::string sha1_base64 = base64_encode(digest, 20);
2326 std::string sha1_hex = hex_encode((char*)digest, 20);
2330 m_media[filename] = MediaInfo(filepath, sha1_base64);
2331 verbosestream << "Server: " << sha1_hex << " is " << filename
2337 void Server::sendMediaAnnouncement(u16 peer_id)
2339 DSTACK(FUNCTION_NAME);
2341 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2345 std::ostringstream os(std::ios_base::binary);
2347 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2348 pkt << (u16) m_media.size();
2350 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2351 i != m_media.end(); ++i) {
2352 pkt << i->first << i->second.sha1_digest;
2355 pkt << g_settings->get("remote_media");
2359 struct SendableMedia
2365 SendableMedia(const std::string &name_="", const std::string &path_="",
2366 const std::string &data_=""):
2373 void Server::sendRequestedMedia(u16 peer_id,
2374 const std::vector<std::string> &tosend)
2376 DSTACK(FUNCTION_NAME);
2378 verbosestream<<"Server::sendRequestedMedia(): "
2379 <<"Sending files to client"<<std::endl;
2383 // Put 5kB in one bunch (this is not accurate)
2384 u32 bytes_per_bunch = 5000;
2386 std::vector< std::vector<SendableMedia> > file_bunches;
2387 file_bunches.push_back(std::vector<SendableMedia>());
2389 u32 file_size_bunch_total = 0;
2391 for(std::vector<std::string>::const_iterator i = tosend.begin();
2392 i != tosend.end(); ++i) {
2393 const std::string &name = *i;
2395 if(m_media.find(name) == m_media.end()) {
2396 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2397 <<"unknown file \""<<(name)<<"\""<<std::endl;
2401 //TODO get path + name
2402 std::string tpath = m_media[name].path;
2405 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2406 if(fis.good() == false){
2407 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2408 <<tpath<<"\" for reading"<<std::endl;
2411 std::ostringstream tmp_os(std::ios_base::binary);
2415 fis.read(buf, 1024);
2416 std::streamsize len = fis.gcount();
2417 tmp_os.write(buf, len);
2418 file_size_bunch_total += len;
2427 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2428 <<name<<"\""<<std::endl;
2431 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2432 <<tname<<"\""<<std::endl;*/
2434 file_bunches[file_bunches.size()-1].push_back(
2435 SendableMedia(name, tpath, tmp_os.str()));
2437 // Start next bunch if got enough data
2438 if(file_size_bunch_total >= bytes_per_bunch) {
2439 file_bunches.push_back(std::vector<SendableMedia>());
2440 file_size_bunch_total = 0;
2445 /* Create and send packets */
2447 u16 num_bunches = file_bunches.size();
2448 for(u16 i = 0; i < num_bunches; i++) {
2451 u16 total number of texture bunches
2452 u16 index of this bunch
2453 u32 number of files in this bunch
2462 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2463 pkt << num_bunches << i << (u32) file_bunches[i].size();
2465 for(std::vector<SendableMedia>::iterator
2466 j = file_bunches[i].begin();
2467 j != file_bunches[i].end(); ++j) {
2469 pkt.putLongString(j->data);
2472 verbosestream << "Server::sendRequestedMedia(): bunch "
2473 << i << "/" << num_bunches
2474 << " files=" << file_bunches[i].size()
2475 << " size=" << pkt.getSize() << std::endl;
2480 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2482 if(m_detached_inventories.count(name) == 0) {
2483 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2486 Inventory *inv = m_detached_inventories[name];
2487 std::ostringstream os(std::ios_base::binary);
2489 os << serializeString(name);
2493 std::string s = os.str();
2495 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2496 pkt.putRawString(s.c_str(), s.size());
2498 if (peer_id != PEER_ID_INEXISTENT) {
2502 m_clients.sendToAll(0, &pkt, true);
2506 void Server::sendDetachedInventories(u16 peer_id)
2508 DSTACK(FUNCTION_NAME);
2510 for(std::map<std::string, Inventory*>::iterator
2511 i = m_detached_inventories.begin();
2512 i != m_detached_inventories.end(); ++i) {
2513 const std::string &name = i->first;
2514 //Inventory *inv = i->second;
2515 sendDetachedInventory(name, peer_id);
2523 void Server::DiePlayer(u16 peer_id)
2525 DSTACK(FUNCTION_NAME);
2527 PlayerSAO *playersao = getPlayerSAO(peer_id);
2530 infostream << "Server::DiePlayer(): Player "
2531 << playersao->getPlayer()->getName()
2532 << " dies" << std::endl;
2534 playersao->setHP(0);
2536 // Trigger scripted stuff
2537 m_script->on_dieplayer(playersao);
2539 SendPlayerHP(peer_id);
2540 SendDeathscreen(peer_id, false, v3f(0,0,0));
2543 void Server::RespawnPlayer(u16 peer_id)
2545 DSTACK(FUNCTION_NAME);
2547 PlayerSAO *playersao = getPlayerSAO(peer_id);
2550 infostream << "Server::RespawnPlayer(): Player "
2551 << playersao->getPlayer()->getName()
2552 << " respawns" << std::endl;
2554 playersao->setHP(PLAYER_MAX_HP);
2555 playersao->setBreath(PLAYER_MAX_BREATH);
2557 SendPlayerHP(peer_id);
2558 SendPlayerBreath(peer_id);
2560 bool repositioned = m_script->on_respawnplayer(playersao);
2562 v3f pos = findSpawnPos();
2563 // setPos will send the new position to client
2564 playersao->setPos(pos);
2569 void Server::DenySudoAccess(u16 peer_id)
2571 DSTACK(FUNCTION_NAME);
2573 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2578 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2579 const std::string &str_reason, bool reconnect)
2581 if (proto_ver >= 25) {
2582 SendAccessDenied(peer_id, reason, str_reason);
2584 std::wstring wreason = utf8_to_wide(
2585 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2586 accessDeniedStrings[(u8)reason]);
2587 SendAccessDenied_Legacy(peer_id, wreason);
2590 m_clients.event(peer_id, CSE_SetDenied);
2591 m_con.DisconnectPeer(peer_id);
2595 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2597 DSTACK(FUNCTION_NAME);
2599 SendAccessDenied(peer_id, reason, custom_reason);
2600 m_clients.event(peer_id, CSE_SetDenied);
2601 m_con.DisconnectPeer(peer_id);
2604 // 13/03/15: remove this function when protocol version 25 will become
2605 // the minimum version for MT users, maybe in 1 year
2606 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2608 DSTACK(FUNCTION_NAME);
2610 SendAccessDenied_Legacy(peer_id, reason);
2611 m_clients.event(peer_id, CSE_SetDenied);
2612 m_con.DisconnectPeer(peer_id);
2615 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2617 DSTACK(FUNCTION_NAME);
2620 RemoteClient* client = getClient(peer_id, CS_Invalid);
2622 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2624 // Right now, the auth mechs don't change between login and sudo mode.
2625 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2626 client->allowed_sudo_mechs = sudo_auth_mechs;
2628 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2629 << g_settings->getFloat("dedicated_server_step")
2633 m_clients.event(peer_id, CSE_AuthAccept);
2635 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2637 // We only support SRP right now
2638 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2640 resp_pkt << sudo_auth_mechs;
2642 m_clients.event(peer_id, CSE_SudoSuccess);
2646 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2648 DSTACK(FUNCTION_NAME);
2649 std::wstring message;
2652 Clear references to playing sounds
2654 for(std::map<s32, ServerPlayingSound>::iterator
2655 i = m_playing_sounds.begin();
2656 i != m_playing_sounds.end();)
2658 ServerPlayingSound &psound = i->second;
2659 psound.clients.erase(peer_id);
2660 if(psound.clients.empty())
2661 m_playing_sounds.erase(i++);
2666 Player *player = m_env->getPlayer(peer_id);
2668 // Collect information about leaving in chat
2670 if(player != NULL && reason != CDR_DENY)
2672 std::wstring name = narrow_to_wide(player->getName());
2675 message += L" left the game.";
2676 if(reason == CDR_TIMEOUT)
2677 message += L" (timed out)";
2681 /* Run scripts and remove from environment */
2685 PlayerSAO *playersao = player->getPlayerSAO();
2688 m_script->on_leaveplayer(playersao);
2690 playersao->disconnected();
2698 if(player != NULL && reason != CDR_DENY) {
2699 std::ostringstream os(std::ios_base::binary);
2700 std::vector<u16> clients = m_clients.getClientIDs();
2702 for(std::vector<u16>::iterator i = clients.begin();
2703 i != clients.end(); ++i) {
2705 Player *player = m_env->getPlayer(*i);
2709 // Get name of player
2710 os << player->getName() << " ";
2713 std::string name = player->getName();
2714 actionstream << name << " "
2715 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2716 << " List of players: " << os.str() << std::endl;
2718 m_admin_chat->outgoing_queue.push_back(
2719 new ChatEventNick(CET_NICK_REMOVE, name));
2723 MutexAutoLock env_lock(m_env_mutex);
2724 m_clients.DeleteClient(peer_id);
2728 // Send leave chat message to all remaining clients
2729 if(message.length() != 0)
2730 SendChatMessage(PEER_ID_INEXISTENT,message);
2733 void Server::UpdateCrafting(Player* player)
2735 DSTACK(FUNCTION_NAME);
2737 // Get a preview for crafting
2739 InventoryLocation loc;
2740 loc.setPlayer(player->getName());
2741 std::vector<ItemStack> output_replacements;
2742 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2743 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2745 // Put the new preview in
2746 InventoryList *plist = player->inventory.getList("craftpreview");
2747 sanity_check(plist);
2748 sanity_check(plist->getSize() >= 1);
2749 plist->changeItem(0, preview);
2752 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2753 const std::wstring &wmessage, u16 peer_id_to_avoid_sending)
2755 // If something goes wrong, this player is to blame
2756 RollbackScopeActor rollback_scope(m_rollback,
2757 std::string("player:") + name);
2761 // Whether to send line to the player that sent the message, or to all players
2762 bool broadcast_line = true;
2765 bool ate = m_script->on_chat_message(name,
2766 wide_to_utf8(wmessage));
2767 // If script ate the message, don't proceed
2771 // Commands are implemented in Lua, so only catch invalid
2772 // commands that were not "eaten" and send an error back
2773 if (wmessage[0] == L'/') {
2774 std::wstring wcmd = wmessage.substr(1);
2775 broadcast_line = false;
2776 if (wcmd.length() == 0)
2777 line += L"-!- Empty command";
2779 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2788 Tell calling method to send the message to sender
2790 if (!broadcast_line) {
2794 Send the message to others
2796 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2798 std::vector<u16> clients = m_clients.getClientIDs();
2800 for (u16 i = 0; i < clients.size(); i++) {
2801 u16 cid = clients[i];
2802 if (cid != peer_id_to_avoid_sending)
2803 SendChatMessage(cid, line);
2809 void Server::handleAdminChat(const ChatEventChat *evt)
2811 std::string name = evt->nick;
2812 std::wstring wname = utf8_to_wide(name);
2813 std::wstring wmessage = evt->evt_msg;
2815 std::wstring answer = handleChat(name, wname, wmessage);
2817 // If asked to send answer to sender
2818 if (!answer.empty()) {
2819 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2823 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2825 RemoteClient *client = getClientNoEx(peer_id,state_min);
2827 throw ClientNotFoundException("Client not found");
2831 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2833 return m_clients.getClientNoEx(peer_id, state_min);
2836 std::string Server::getPlayerName(u16 peer_id)
2838 Player *player = m_env->getPlayer(peer_id);
2840 return "[id="+itos(peer_id)+"]";
2841 return player->getName();
2844 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2846 Player *player = m_env->getPlayer(peer_id);
2849 return player->getPlayerSAO();
2852 std::wstring Server::getStatusString()
2854 std::wostringstream os(std::ios_base::binary);
2857 os<<L"version="<<narrow_to_wide(g_version_string);
2859 os<<L", uptime="<<m_uptime.get();
2861 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2862 // Information about clients
2865 std::vector<u16> clients = m_clients.getClientIDs();
2866 for(std::vector<u16>::iterator i = clients.begin();
2867 i != clients.end(); ++i) {
2869 Player *player = m_env->getPlayer(*i);
2870 // Get name of player
2871 std::wstring name = L"unknown";
2873 name = narrow_to_wide(player->getName());
2874 // Add name to information string
2882 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2883 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2884 if(g_settings->get("motd") != "")
2885 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2889 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2891 std::set<std::string> privs;
2892 m_script->getAuth(name, NULL, &privs);
2896 bool Server::checkPriv(const std::string &name, const std::string &priv)
2898 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2899 return (privs.count(priv) != 0);
2902 void Server::reportPrivsModified(const std::string &name)
2905 std::vector<u16> clients = m_clients.getClientIDs();
2906 for(std::vector<u16>::iterator i = clients.begin();
2907 i != clients.end(); ++i) {
2908 Player *player = m_env->getPlayer(*i);
2909 reportPrivsModified(player->getName());
2912 Player *player = m_env->getPlayer(name.c_str());
2915 SendPlayerPrivileges(player->peer_id);
2916 PlayerSAO *sao = player->getPlayerSAO();
2919 sao->updatePrivileges(
2920 getPlayerEffectivePrivs(name),
2925 void Server::reportInventoryFormspecModified(const std::string &name)
2927 Player *player = m_env->getPlayer(name.c_str());
2930 SendPlayerInventoryFormspec(player->peer_id);
2933 void Server::setIpBanned(const std::string &ip, const std::string &name)
2935 m_banmanager->add(ip, name);
2938 void Server::unsetIpBanned(const std::string &ip_or_name)
2940 m_banmanager->remove(ip_or_name);
2943 std::string Server::getBanDescription(const std::string &ip_or_name)
2945 return m_banmanager->getBanDescription(ip_or_name);
2948 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2950 // m_env will be NULL if the server is initializing
2954 if (m_admin_nick == name && !m_admin_nick.empty()) {
2955 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2958 Player *player = m_env->getPlayer(name);
2963 if (player->peer_id == PEER_ID_INEXISTENT)
2966 SendChatMessage(player->peer_id, msg);
2969 bool Server::showFormspec(const char *playername, const std::string &formspec,
2970 const std::string &formname)
2972 // m_env will be NULL if the server is initializing
2976 Player *player = m_env->getPlayer(playername);
2980 SendShowFormspecMessage(player->peer_id, formspec, formname);
2984 u32 Server::hudAdd(Player *player, HudElement *form)
2989 u32 id = player->addHud(form);
2991 SendHUDAdd(player->peer_id, id, form);
2996 bool Server::hudRemove(Player *player, u32 id) {
3000 HudElement* todel = player->removeHud(id);
3007 SendHUDRemove(player->peer_id, id);
3011 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3016 SendHUDChange(player->peer_id, id, stat, data);
3020 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3025 SendHUDSetFlags(player->peer_id, flags, mask);
3026 player->hud_flags = flags;
3028 PlayerSAO* playersao = player->getPlayerSAO();
3030 if (playersao == NULL)
3033 m_script->player_event(playersao, "hud_changed");
3037 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3041 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3044 player->setHotbarItemcount(hotbar_itemcount);
3045 std::ostringstream os(std::ios::binary);
3046 writeS32(os, hotbar_itemcount);
3047 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3051 s32 Server::hudGetHotbarItemcount(Player *player)
3055 return player->getHotbarItemcount();
3058 void Server::hudSetHotbarImage(Player *player, std::string name)
3063 player->setHotbarImage(name);
3064 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3067 std::string Server::hudGetHotbarImage(Player *player)
3071 return player->getHotbarImage();
3074 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3079 player->setHotbarSelectedImage(name);
3080 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3083 std::string Server::hudGetHotbarSelectedImage(Player *player)
3088 return player->getHotbarSelectedImage();
3091 bool Server::setLocalPlayerAnimations(Player *player,
3092 v2s32 animation_frames[4], f32 frame_speed)
3097 player->setLocalAnimations(animation_frames, frame_speed);
3098 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3102 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3107 player->eye_offset_first = first;
3108 player->eye_offset_third = third;
3109 SendEyeOffset(player->peer_id, first, third);
3113 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3114 const std::string &type, const std::vector<std::string> ¶ms)
3119 player->setSky(bgcolor, type, params);
3120 SendSetSky(player->peer_id, bgcolor, type, params);
3124 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3130 player->overrideDayNightRatio(do_override, ratio);
3131 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3135 void Server::notifyPlayers(const std::wstring &msg)
3137 SendChatMessage(PEER_ID_INEXISTENT,msg);
3140 void Server::spawnParticle(const std::string &playername, v3f pos,
3141 v3f velocity, v3f acceleration,
3142 float expirationtime, float size, bool
3143 collisiondetection, bool vertical, const std::string &texture)
3145 // m_env will be NULL if the server is initializing
3149 u16 peer_id = PEER_ID_INEXISTENT;
3150 if (playername != "") {
3151 Player* player = m_env->getPlayer(playername.c_str());
3154 peer_id = player->peer_id;
3157 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3158 expirationtime, size, collisiondetection, vertical, texture);
3161 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3162 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3163 float minexptime, float maxexptime, float minsize, float maxsize,
3164 bool collisiondetection, bool vertical, const std::string &texture,
3165 const std::string &playername)
3167 // m_env will be NULL if the server is initializing
3171 u16 peer_id = PEER_ID_INEXISTENT;
3172 if (playername != "") {
3173 Player* player = m_env->getPlayer(playername.c_str());
3176 peer_id = player->peer_id;
3180 for(;;) // look for unused particlespawner id
3183 if (std::find(m_particlespawner_ids.begin(),
3184 m_particlespawner_ids.end(), id)
3185 == m_particlespawner_ids.end())
3187 m_particlespawner_ids.push_back(id);
3192 SendAddParticleSpawner(peer_id, amount, spawntime,
3193 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3194 minexptime, maxexptime, minsize, maxsize,
3195 collisiondetection, 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_particlespawner_ids.erase(
3215 std::remove(m_particlespawner_ids.begin(),
3216 m_particlespawner_ids.end(), id),
3217 m_particlespawner_ids.end());
3218 SendDeleteParticleSpawner(peer_id, id);
3221 Inventory* Server::createDetachedInventory(const std::string &name)
3223 if(m_detached_inventories.count(name) > 0){
3224 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3225 delete m_detached_inventories[name];
3227 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3229 Inventory *inv = new Inventory(m_itemdef);
3231 m_detached_inventories[name] = inv;
3232 //TODO find a better way to do this
3233 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3237 // actions: time-reversed list
3238 // Return value: success/failure
3239 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3240 std::list<std::string> *log)
3242 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3243 ServerMap *map = (ServerMap*)(&m_env->getMap());
3245 // Fail if no actions to handle
3246 if(actions.empty()){
3247 log->push_back("Nothing to do.");
3254 for(std::list<RollbackAction>::const_iterator
3255 i = actions.begin();
3256 i != actions.end(); ++i)
3258 const RollbackAction &action = *i;
3260 bool success = action.applyRevert(map, this, this);
3263 std::ostringstream os;
3264 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3265 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3267 log->push_back(os.str());
3269 std::ostringstream os;
3270 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3271 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3273 log->push_back(os.str());
3277 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3278 <<" failed"<<std::endl;
3280 // Call it done if less than half failed
3281 return num_failed <= num_tried/2;
3284 // IGameDef interface
3286 IItemDefManager *Server::getItemDefManager()
3291 INodeDefManager *Server::getNodeDefManager()
3296 ICraftDefManager *Server::getCraftDefManager()
3300 ITextureSource *Server::getTextureSource()
3304 IShaderSource *Server::getShaderSource()
3308 scene::ISceneManager *Server::getSceneManager()
3313 u16 Server::allocateUnknownNodeId(const std::string &name)
3315 return m_nodedef->allocateDummy(name);
3318 ISoundManager *Server::getSoundManager()
3320 return &dummySoundManager;
3323 MtEventManager *Server::getEventManager()
3328 IWritableItemDefManager *Server::getWritableItemDefManager()
3333 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3338 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3343 const ModSpec *Server::getModSpec(const std::string &modname) const
3345 std::vector<ModSpec>::const_iterator it;
3346 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3347 const ModSpec &mod = *it;
3348 if (mod.name == modname)
3354 void Server::getModNames(std::vector<std::string> &modlist)
3356 std::vector<ModSpec>::iterator it;
3357 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3358 modlist.push_back(it->name);
3361 std::string Server::getBuiltinLuaPath()
3363 return porting::path_share + DIR_DELIM + "builtin";
3366 v3f Server::findSpawnPos()
3368 ServerMap &map = m_env->getServerMap();
3370 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3371 return nodeposf * BS;
3374 s16 water_level = map.getWaterLevel();
3375 s16 vertical_spawn_range = g_settings->getS16("vertical_spawn_range");
3376 bool is_good = false;
3378 // Try to find a good place a few times
3379 for(s32 i = 0; i < 1000 && !is_good; i++) {
3381 // We're going to try to throw the player to this position
3382 v2s16 nodepos2d = v2s16(
3383 -range + (myrand() % (range * 2)),
3384 -range + (myrand() % (range * 2)));
3386 // Get ground height at point
3387 s16 groundheight = map.findGroundLevel(nodepos2d);
3388 // Don't go underwater or to high places
3389 if (groundheight <= water_level ||
3390 groundheight > water_level + vertical_spawn_range)
3393 v3s16 nodepos(nodepos2d.X, groundheight, nodepos2d.Y);
3396 for (s32 i = 0; i < 10; i++) {
3397 v3s16 blockpos = getNodeBlockPos(nodepos);
3398 map.emergeBlock(blockpos, true);
3399 content_t c = map.getNodeNoEx(nodepos).getContent();
3400 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3402 if (air_count >= 2) {
3403 nodeposf = intToFloat(nodepos, BS);
3404 // Don't spawn the player outside map boundaries
3405 if (objectpos_over_limit(nodeposf))
3418 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3420 bool newplayer = false;
3423 Try to get an existing player
3425 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3427 // If player is already connected, cancel
3428 if(player != NULL && player->peer_id != 0)
3430 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3435 If player with the wanted peer_id already exists, cancel.
3437 if(m_env->getPlayer(peer_id) != NULL)
3439 infostream<<"emergePlayer(): Player with wrong name but same"
3440 " peer_id already exists"<<std::endl;
3444 // Load player if it isn't already loaded
3446 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3449 // Create player if it doesn't exist
3452 player = new RemotePlayer(this, name);
3453 // Set player position
3454 infostream<<"Server: Finding spawn place for player \""
3455 <<name<<"\""<<std::endl;
3456 v3f pos = findSpawnPos();
3457 player->setPosition(pos);
3459 // Make sure the player is saved
3460 player->setModified(true);
3462 // Add player to environment
3463 m_env->addPlayer(player);
3465 // If the player exists, ensure that they respawn inside legal bounds
3466 // This fixes an assert crash when the player can't be added
3467 // to the environment
3468 if (objectpos_over_limit(player->getPosition())) {
3469 actionstream << "Respawn position for player \""
3470 << name << "\" outside limits, resetting" << std::endl;
3471 v3f pos = findSpawnPos();
3472 player->setPosition(pos);
3476 // Create a new player active object
3477 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3478 getPlayerEffectivePrivs(player->getName()),
3481 player->protocol_version = proto_version;
3483 /* Clean up old HUD elements from previous sessions */
3486 /* Add object to environment */
3487 m_env->addActiveObject(playersao);
3491 m_script->on_newplayer(playersao);
3497 void dedicated_server_loop(Server &server, bool &kill)
3499 DSTACK(FUNCTION_NAME);
3501 verbosestream<<"dedicated_server_loop()"<<std::endl;
3503 IntervalLimiter m_profiler_interval;
3507 float steplen = g_settings->getFloat("dedicated_server_step");
3508 // This is kind of a hack but can be done like this
3509 // because server.step() is very light
3511 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3512 sleep_ms((int)(steplen*1000.0));
3514 server.step(steplen);
3516 if(server.getShutdownRequested() || kill)
3518 infostream<<"Dedicated server quitting"<<std::endl;
3520 if(g_settings->getBool("server_announce"))
3521 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3529 float profiler_print_interval =
3530 g_settings->getFloat("profiler_print_interval");
3531 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();