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_masterserver_timer = 0.0;
188 m_emergethread_trigger_timer = 0.0;
189 m_savemap_timer = 0.0;
192 m_lag = g_settings->getFloat("dedicated_server_step");
195 throw ServerError("Supplied empty world path");
197 if(!gamespec.isValid())
198 throw ServerError("Supplied invalid gamespec");
200 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
201 if(m_simple_singleplayer_mode)
202 infostream<<" in simple singleplayer mode"<<std::endl;
204 infostream<<std::endl;
205 infostream<<"- world: "<<m_path_world<<std::endl;
206 infostream<<"- game: "<<m_gamespec.path<<std::endl;
208 // Create world if it doesn't exist
209 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
210 throw ServerError("Failed to initialize world");
212 // Create server thread
213 m_thread = new ServerThread(this);
215 // Create emerge manager
216 m_emerge = new EmergeManager(this);
218 // Create ban manager
219 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
220 m_banmanager = new BanManager(ban_path);
222 ModConfiguration modconf(m_path_world);
223 m_mods = modconf.getMods();
224 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
225 // complain about mods with unsatisfied dependencies
226 if(!modconf.isConsistent()) {
227 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
228 it != unsatisfied_mods.end(); ++it) {
230 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
231 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
232 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
233 errorstream << " \"" << *dep_it << "\"";
234 errorstream << std::endl;
238 Settings worldmt_settings;
239 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
240 worldmt_settings.readConfigFile(worldmt.c_str());
241 std::vector<std::string> names = worldmt_settings.getNames();
242 std::set<std::string> load_mod_names;
243 for(std::vector<std::string>::iterator it = names.begin();
244 it != names.end(); ++it) {
245 std::string name = *it;
246 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
247 load_mod_names.insert(name.substr(9));
249 // complain about mods declared to be loaded, but not found
250 for(std::vector<ModSpec>::iterator it = m_mods.begin();
251 it != m_mods.end(); ++it)
252 load_mod_names.erase((*it).name);
253 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
254 it != unsatisfied_mods.end(); ++it)
255 load_mod_names.erase((*it).name);
256 if(!load_mod_names.empty()) {
257 errorstream << "The following mods could not be found:";
258 for(std::set<std::string>::iterator it = load_mod_names.begin();
259 it != load_mod_names.end(); ++it)
260 errorstream << " \"" << (*it) << "\"";
261 errorstream << std::endl;
265 MutexAutoLock envlock(m_env_mutex);
267 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
268 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
270 // Initialize scripting
271 infostream<<"Server: Initializing Lua"<<std::endl;
273 m_script = new GameScripting(this);
275 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
277 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
280 infostream << "Server: Loading mods: ";
281 for(std::vector<ModSpec>::iterator i = m_mods.begin();
282 i != m_mods.end(); ++i) {
283 const ModSpec &mod = *i;
284 infostream << mod.name << " ";
286 infostream << std::endl;
287 // Load and run "mod" scripts
288 for (std::vector<ModSpec>::iterator it = m_mods.begin();
289 it != m_mods.end(); ++it) {
290 const ModSpec &mod = *it;
291 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
292 throw ModError("Error loading mod \"" + mod.name +
293 "\": Mod name does not follow naming conventions: "
294 "Only chararacters [a-z0-9_] are allowed.");
296 std::string script_path = mod.path + DIR_DELIM + "init.lua";
297 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
298 << script_path << "\"]" << std::endl;
299 m_script->loadMod(script_path, mod.name);
302 // Read Textures and calculate sha1 sums
305 // Apply item aliases in the node definition manager
306 m_nodedef->updateAliases(m_itemdef);
308 // Apply texture overrides from texturepack/override.txt
309 std::string texture_path = g_settings->get("texture_path");
310 if (texture_path != "" && fs::IsDir(texture_path))
311 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
313 m_nodedef->setNodeRegistrationStatus(true);
315 // Perform pending node name resolutions
316 m_nodedef->runNodeResolveCallbacks();
318 // unmap node names for connected nodeboxes
319 m_nodedef->mapNodeboxConnections();
321 // init the recipe hashes to speed up crafting
322 m_craftdef->initHashes(this);
324 // Initialize Environment
325 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
327 m_clients.setEnv(m_env);
329 if (!servermap->settings_mgr.makeMapgenParams())
330 FATAL_ERROR("Couldn't create any mapgen type");
332 // Initialize mapgens
333 m_emerge->initMapgens(servermap->getMapgenParams());
335 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
336 if (m_enable_rollback_recording) {
337 // Create rollback manager
338 m_rollback = new RollbackManager(m_path_world, this);
341 // Give environment reference to scripting api
342 m_script->initializeEnvironment(m_env);
344 // Register us to receive map edit events
345 servermap->addEventReceiver(this);
347 // If file exists, load environment metadata
348 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
349 infostream << "Server: Loading environment metadata" << std::endl;
352 m_env->loadDefaultMeta();
355 // Add some test ActiveBlockModifiers to environment
356 add_legacy_abms(m_env, m_nodedef);
358 m_liquid_transform_every = g_settings->getFloat("liquid_update");
359 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
364 infostream<<"Server destructing"<<std::endl;
366 // Send shutdown message
367 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
370 MutexAutoLock envlock(m_env_mutex);
372 // Execute script shutdown hooks
373 m_script->on_shutdown();
375 infostream << "Server: Saving players" << std::endl;
376 m_env->saveLoadedPlayers();
378 infostream << "Server: Kicking players" << std::endl;
379 std::string kick_msg;
380 bool reconnect = false;
381 if (getShutdownRequested()) {
382 reconnect = m_shutdown_ask_reconnect;
383 kick_msg = m_shutdown_msg;
385 if (kick_msg == "") {
386 kick_msg = g_settings->get("kick_msg_shutdown");
388 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
389 kick_msg, reconnect);
391 infostream << "Server: Saving environment metadata" << std::endl;
399 // stop all emerge threads before deleting players that may have
400 // requested blocks to be emerged
401 m_emerge->stopThreads();
403 // Delete things in the reverse order of creation
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 handleChatInterfaceEvent(evt);
592 m_admin_chat->outgoing_queue.push_back(
593 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
600 /* Transform liquids */
601 m_liquid_transform_timer += dtime;
602 if(m_liquid_transform_timer >= m_liquid_transform_every)
604 m_liquid_transform_timer -= m_liquid_transform_every;
606 MutexAutoLock lock(m_env_mutex);
608 ScopeProfiler sp(g_profiler, "Server: liquid transform");
610 std::map<v3s16, MapBlock*> modified_blocks;
611 m_env->getMap().transformLiquids(modified_blocks);
616 core::map<v3s16, MapBlock*> lighting_modified_blocks;
617 ServerMap &map = ((ServerMap&)m_env->getMap());
618 map.updateLighting(modified_blocks, lighting_modified_blocks);
620 // Add blocks modified by lighting to modified_blocks
621 for(core::map<v3s16, MapBlock*>::Iterator
622 i = lighting_modified_blocks.getIterator();
623 i.atEnd() == false; i++)
625 MapBlock *block = i.getNode()->getValue();
626 modified_blocks.insert(block->getPos(), block);
630 Set the modified blocks unsent for all the clients
632 if(!modified_blocks.empty())
634 SetBlocksNotSent(modified_blocks);
637 m_clients.step(dtime);
639 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
641 // send masterserver announce
643 float &counter = m_masterserver_timer;
644 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
645 g_settings->getBool("server_announce"))
647 ServerList::sendAnnounce(counter ? "update" : "start",
648 m_bind_addr.getPort(),
649 m_clients.getPlayerNames(),
651 m_env->getGameTime(),
654 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
663 Check added and deleted active objects
666 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
667 MutexAutoLock envlock(m_env_mutex);
670 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
671 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
673 // Radius inside which objects are active
674 static const s16 radius =
675 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
677 // Radius inside which players are active
678 static const bool is_transfer_limited =
679 g_settings->exists("unlimited_player_transfer_distance") &&
680 !g_settings->getBool("unlimited_player_transfer_distance");
681 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
682 s16 player_radius = player_transfer_dist;
683 if (player_radius == 0 && is_transfer_limited)
684 player_radius = radius;
686 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
687 i != clients.end(); ++i) {
688 RemoteClient *client = i->second;
690 // If definitions and textures have not been sent, don't
691 // send objects either
692 if (client->getState() < CS_DefinitionsSent)
695 RemotePlayer *player = m_env->getPlayer(client->peer_id);
696 if (player == NULL) {
697 // This can happen if the client timeouts somehow
698 /*warningstream<<FUNCTION_NAME<<": Client "
700 <<" has no associated player"<<std::endl;*/
704 std::queue<u16> removed_objects;
705 std::queue<u16> added_objects;
706 m_env->getRemovedActiveObjects(player, radius, player_radius,
707 client->m_known_objects, removed_objects);
708 m_env->getAddedActiveObjects(player, radius, player_radius,
709 client->m_known_objects, added_objects);
711 // Ignore if nothing happened
712 if (removed_objects.empty() && added_objects.empty()) {
716 std::string data_buffer;
720 // Handle removed objects
721 writeU16((u8*)buf, removed_objects.size());
722 data_buffer.append(buf, 2);
723 while (!removed_objects.empty()) {
725 u16 id = removed_objects.front();
726 ServerActiveObject* obj = m_env->getActiveObject(id);
728 // Add to data buffer for sending
729 writeU16((u8*)buf, id);
730 data_buffer.append(buf, 2);
732 // Remove from known objects
733 client->m_known_objects.erase(id);
735 if(obj && obj->m_known_by_count > 0)
736 obj->m_known_by_count--;
737 removed_objects.pop();
740 // Handle added objects
741 writeU16((u8*)buf, added_objects.size());
742 data_buffer.append(buf, 2);
743 while (!added_objects.empty()) {
745 u16 id = added_objects.front();
746 ServerActiveObject* obj = m_env->getActiveObject(id);
749 u8 type = ACTIVEOBJECT_TYPE_INVALID;
751 warningstream<<FUNCTION_NAME
752 <<": NULL object"<<std::endl;
754 type = obj->getSendType();
756 // Add to data buffer for sending
757 writeU16((u8*)buf, id);
758 data_buffer.append(buf, 2);
759 writeU8((u8*)buf, type);
760 data_buffer.append(buf, 1);
763 data_buffer.append(serializeLongString(
764 obj->getClientInitializationData(client->net_proto_version)));
766 data_buffer.append(serializeLongString(""));
768 // Add to known objects
769 client->m_known_objects.insert(id);
772 obj->m_known_by_count++;
777 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
778 verbosestream << "Server: Sent object remove/add: "
779 << removed_objects.size() << " removed, "
780 << added_objects.size() << " added, "
781 << "packet size is " << pktSize << std::endl;
790 MutexAutoLock envlock(m_env_mutex);
791 ScopeProfiler sp(g_profiler, "Server: sending object messages");
794 // Value = data sent by object
795 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
797 // Get active object messages from environment
799 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
803 std::vector<ActiveObjectMessage>* message_list = NULL;
804 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
805 n = buffered_messages.find(aom.id);
806 if (n == buffered_messages.end()) {
807 message_list = new std::vector<ActiveObjectMessage>;
808 buffered_messages[aom.id] = message_list;
811 message_list = n->second;
813 message_list->push_back(aom);
817 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
818 // Route data to every client
819 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
820 i != clients.end(); ++i) {
821 RemoteClient *client = i->second;
822 std::string reliable_data;
823 std::string unreliable_data;
824 // Go through all objects in message buffer
825 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
826 j = buffered_messages.begin();
827 j != buffered_messages.end(); ++j) {
828 // If object is not known by client, skip it
830 if (client->m_known_objects.find(id) == client->m_known_objects.end())
833 // Get message list of object
834 std::vector<ActiveObjectMessage>* list = j->second;
835 // Go through every message
836 for (std::vector<ActiveObjectMessage>::iterator
837 k = list->begin(); k != list->end(); ++k) {
838 // Compose the full new data with header
839 ActiveObjectMessage aom = *k;
840 std::string new_data;
843 writeU16((u8*)&buf[0], aom.id);
844 new_data.append(buf, 2);
846 new_data += serializeString(aom.datastring);
847 // Add data to buffer
849 reliable_data += new_data;
851 unreliable_data += new_data;
855 reliable_data and unreliable_data are now ready.
858 if(reliable_data.size() > 0) {
859 SendActiveObjectMessages(client->peer_id, reliable_data);
862 if(unreliable_data.size() > 0) {
863 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
868 // Clear buffered_messages
869 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
870 i = buffered_messages.begin();
871 i != buffered_messages.end(); ++i) {
877 Send queued-for-sending map edit events.
880 // We will be accessing the environment
881 MutexAutoLock lock(m_env_mutex);
883 // Don't send too many at a time
886 // Single change sending is disabled if queue size is not small
887 bool disable_single_change_sending = false;
888 if(m_unsent_map_edit_queue.size() >= 4)
889 disable_single_change_sending = true;
891 int event_count = m_unsent_map_edit_queue.size();
893 // We'll log the amount of each
896 while(m_unsent_map_edit_queue.size() != 0)
898 MapEditEvent* event = m_unsent_map_edit_queue.front();
899 m_unsent_map_edit_queue.pop();
901 // Players far away from the change are stored here.
902 // Instead of sending the changes, MapBlocks are set not sent
904 std::vector<u16> far_players;
906 switch (event->type) {
909 prof.add("MEET_ADDNODE", 1);
910 sendAddNode(event->p, event->n, event->already_known_by_peer,
911 &far_players, disable_single_change_sending ? 5 : 30,
912 event->type == MEET_ADDNODE);
914 case MEET_REMOVENODE:
915 prof.add("MEET_REMOVENODE", 1);
916 sendRemoveNode(event->p, event->already_known_by_peer,
917 &far_players, disable_single_change_sending ? 5 : 30);
919 case MEET_BLOCK_NODE_METADATA_CHANGED:
920 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
921 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
922 setBlockNotSent(event->p);
925 infostream << "Server: MEET_OTHER" << std::endl;
926 prof.add("MEET_OTHER", 1);
927 for(std::set<v3s16>::iterator
928 i = event->modified_blocks.begin();
929 i != event->modified_blocks.end(); ++i) {
934 prof.add("unknown", 1);
935 warningstream << "Server: Unknown MapEditEvent "
936 << ((u32)event->type) << std::endl;
941 Set blocks not sent to far players
943 if(!far_players.empty()) {
944 // Convert list format to that wanted by SetBlocksNotSent
945 std::map<v3s16, MapBlock*> modified_blocks2;
946 for(std::set<v3s16>::iterator
947 i = event->modified_blocks.begin();
948 i != event->modified_blocks.end(); ++i) {
949 modified_blocks2[*i] =
950 m_env->getMap().getBlockNoCreateNoEx(*i);
953 // Set blocks not sent
954 for(std::vector<u16>::iterator
955 i = far_players.begin();
956 i != far_players.end(); ++i) {
957 if(RemoteClient *client = getClient(*i))
958 client->SetBlocksNotSent(modified_blocks2);
964 /*// Don't send too many at a time
966 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
970 if(event_count >= 5){
971 infostream<<"Server: MapEditEvents:"<<std::endl;
972 prof.print(infostream);
973 } else if(event_count != 0){
974 verbosestream<<"Server: MapEditEvents:"<<std::endl;
975 prof.print(verbosestream);
981 Trigger emergethread (it somehow gets to a non-triggered but
982 bysy state sometimes)
985 float &counter = m_emergethread_trigger_timer;
987 if (counter >= 2.0) {
990 m_emerge->startThreads();
994 // Save map, players and auth stuff
996 float &counter = m_savemap_timer;
998 static const float save_interval =
999 g_settings->getFloat("server_map_save_interval");
1000 if (counter >= save_interval) {
1002 MutexAutoLock lock(m_env_mutex);
1004 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1007 if (m_banmanager->isModified()) {
1008 m_banmanager->save();
1011 // Save changed parts of map
1012 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1015 m_env->saveLoadedPlayers();
1017 // Save environment metadata
1023 void Server::Receive()
1025 DSTACK(FUNCTION_NAME);
1026 SharedBuffer<u8> data;
1030 m_con.Receive(&pkt);
1031 peer_id = pkt.getPeerId();
1034 catch(con::InvalidIncomingDataException &e) {
1035 infostream<<"Server::Receive(): "
1036 "InvalidIncomingDataException: what()="
1037 <<e.what()<<std::endl;
1039 catch(SerializationError &e) {
1040 infostream<<"Server::Receive(): "
1041 "SerializationError: what()="
1042 <<e.what()<<std::endl;
1044 catch(ClientStateError &e) {
1045 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1046 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1047 L"Try reconnecting or updating your client");
1049 catch(con::PeerNotFoundException &e) {
1054 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1056 std::string playername = "";
1057 PlayerSAO *playersao = NULL;
1060 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1061 if (client != NULL) {
1062 playername = client->getName();
1063 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1065 } catch (std::exception &e) {
1071 RemotePlayer *player =
1072 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1074 // If failed, cancel
1075 if ((playersao == NULL) || (player == NULL)) {
1076 if (player && player->peer_id != 0) {
1077 actionstream << "Server: Failed to emerge player \"" << playername
1078 << "\" (player allocated to an another client)" << std::endl;
1079 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1080 L"name. If your client closed unexpectedly, try again in "
1083 errorstream << "Server: " << playername << ": Failed to emerge player"
1085 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1091 Send complete position information
1093 SendMovePlayer(peer_id);
1096 SendPlayerPrivileges(peer_id);
1098 // Send inventory formspec
1099 SendPlayerInventoryFormspec(peer_id);
1102 SendInventory(playersao);
1105 SendPlayerHPOrDie(playersao);
1108 SendPlayerBreath(peer_id);
1110 // Show death screen if necessary
1111 if (player->isDead())
1112 SendDeathscreen(peer_id, false, v3f(0,0,0));
1114 // Note things in chat if not in simple singleplayer mode
1115 if(!m_simple_singleplayer_mode) {
1116 // Send information about server to player in chat
1117 SendChatMessage(peer_id, getStatusString());
1119 Address addr = getPeerAddress(player->peer_id);
1120 std::string ip_str = addr.serializeString();
1121 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1126 const std::vector<std::string> &names = m_clients.getPlayerNames();
1128 actionstream << player->getName() << " joins game. List of players: ";
1130 for (std::vector<std::string>::const_iterator i = names.begin();
1131 i != names.end(); ++i) {
1132 actionstream << *i << " ";
1135 actionstream << player->getName() <<std::endl;
1140 inline void Server::handleCommand(NetworkPacket* pkt)
1142 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1143 (this->*opHandle.handler)(pkt);
1146 void Server::ProcessData(NetworkPacket *pkt)
1148 DSTACK(FUNCTION_NAME);
1149 // Environment is locked first.
1150 MutexAutoLock envlock(m_env_mutex);
1152 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1153 u32 peer_id = pkt->getPeerId();
1156 Address address = getPeerAddress(peer_id);
1157 std::string addr_s = address.serializeString();
1159 if(m_banmanager->isIpBanned(addr_s)) {
1160 std::string ban_name = m_banmanager->getBanName(addr_s);
1161 infostream << "Server: A banned client tried to connect from "
1162 << addr_s << "; banned name was "
1163 << ban_name << std::endl;
1164 // This actually doesn't seem to transfer to the client
1165 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1166 + utf8_to_wide(ban_name));
1170 catch(con::PeerNotFoundException &e) {
1172 * no peer for this packet found
1173 * most common reason is peer timeout, e.g. peer didn't
1174 * respond for some time, your server was overloaded or
1177 infostream << "Server::ProcessData(): Canceling: peer "
1178 << peer_id << " not found" << std::endl;
1183 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1185 // Command must be handled into ToServerCommandHandler
1186 if (command >= TOSERVER_NUM_MSG_TYPES) {
1187 infostream << "Server: Ignoring unknown command "
1188 << command << std::endl;
1192 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1197 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1199 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1200 errorstream << "Server::ProcessData(): Cancelling: Peer"
1201 " serialization format invalid or not initialized."
1202 " Skipping incoming command=" << command << std::endl;
1206 /* Handle commands related to client startup */
1207 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1212 if (m_clients.getClientState(peer_id) < CS_Active) {
1213 if (command == TOSERVER_PLAYERPOS) return;
1215 errorstream << "Got packet command: " << command << " for peer id "
1216 << peer_id << " but client isn't active yet. Dropping packet "
1222 } catch (SendFailedException &e) {
1223 errorstream << "Server::ProcessData(): SendFailedException: "
1224 << "what=" << e.what()
1226 } catch (PacketError &e) {
1227 actionstream << "Server::ProcessData(): PacketError: "
1228 << "what=" << e.what()
1233 void Server::setTimeOfDay(u32 time)
1235 m_env->setTimeOfDay(time);
1236 m_time_of_day_send_timer = 0;
1239 void Server::onMapEditEvent(MapEditEvent *event)
1241 if(m_ignore_map_edit_events)
1243 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1245 MapEditEvent *e = event->clone();
1246 m_unsent_map_edit_queue.push(e);
1249 Inventory* Server::getInventory(const InventoryLocation &loc)
1252 case InventoryLocation::UNDEFINED:
1253 case InventoryLocation::CURRENT_PLAYER:
1255 case InventoryLocation::PLAYER:
1257 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1260 PlayerSAO *playersao = player->getPlayerSAO();
1263 return playersao->getInventory();
1266 case InventoryLocation::NODEMETA:
1268 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1271 return meta->getInventory();
1274 case InventoryLocation::DETACHED:
1276 if(m_detached_inventories.count(loc.name) == 0)
1278 return m_detached_inventories[loc.name];
1282 sanity_check(false); // abort
1287 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1290 case InventoryLocation::UNDEFINED:
1292 case InventoryLocation::PLAYER:
1297 RemotePlayer *player =
1298 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1303 PlayerSAO *playersao = player->getPlayerSAO();
1307 SendInventory(playersao);
1310 case InventoryLocation::NODEMETA:
1312 v3s16 blockpos = getNodeBlockPos(loc.p);
1314 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1316 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1318 setBlockNotSent(blockpos);
1321 case InventoryLocation::DETACHED:
1323 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1327 sanity_check(false); // abort
1332 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1334 std::vector<u16> clients = m_clients.getClientIDs();
1336 // Set the modified blocks unsent for all the clients
1337 for (std::vector<u16>::iterator i = clients.begin();
1338 i != clients.end(); ++i) {
1339 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1340 client->SetBlocksNotSent(block);
1345 void Server::peerAdded(con::Peer *peer)
1347 DSTACK(FUNCTION_NAME);
1348 verbosestream<<"Server::peerAdded(): peer->id="
1349 <<peer->id<<std::endl;
1352 c.type = con::PEER_ADDED;
1353 c.peer_id = peer->id;
1355 m_peer_change_queue.push(c);
1358 void Server::deletingPeer(con::Peer *peer, bool timeout)
1360 DSTACK(FUNCTION_NAME);
1361 verbosestream<<"Server::deletingPeer(): peer->id="
1362 <<peer->id<<", timeout="<<timeout<<std::endl;
1364 m_clients.event(peer->id, CSE_Disconnect);
1366 c.type = con::PEER_REMOVED;
1367 c.peer_id = peer->id;
1368 c.timeout = timeout;
1369 m_peer_change_queue.push(c);
1372 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1374 *retval = m_con.getPeerStat(peer_id,type);
1375 if (*retval == -1) return false;
1379 bool Server::getClientInfo(
1388 std::string* vers_string
1391 *state = m_clients.getClientState(peer_id);
1393 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1395 if (client == NULL) {
1400 *uptime = client->uptime();
1401 *ser_vers = client->serialization_version;
1402 *prot_vers = client->net_proto_version;
1404 *major = client->getMajor();
1405 *minor = client->getMinor();
1406 *patch = client->getPatch();
1407 *vers_string = client->getPatch();
1414 void Server::handlePeerChanges()
1416 while(m_peer_change_queue.size() > 0)
1418 con::PeerChange c = m_peer_change_queue.front();
1419 m_peer_change_queue.pop();
1421 verbosestream<<"Server: Handling peer change: "
1422 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1427 case con::PEER_ADDED:
1428 m_clients.CreateClient(c.peer_id);
1431 case con::PEER_REMOVED:
1432 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1436 FATAL_ERROR("Invalid peer change event received!");
1442 void Server::printToConsoleOnly(const std::string &text)
1445 m_admin_chat->outgoing_queue.push_back(
1446 new ChatEventChat("", utf8_to_wide(text)));
1448 std::cout << text << std::endl;
1452 void Server::Send(NetworkPacket* pkt)
1454 m_clients.send(pkt->getPeerId(),
1455 clientCommandFactoryTable[pkt->getCommand()].channel,
1457 clientCommandFactoryTable[pkt->getCommand()].reliable);
1460 void Server::SendMovement(u16 peer_id)
1462 DSTACK(FUNCTION_NAME);
1463 std::ostringstream os(std::ios_base::binary);
1465 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1467 pkt << g_settings->getFloat("movement_acceleration_default");
1468 pkt << g_settings->getFloat("movement_acceleration_air");
1469 pkt << g_settings->getFloat("movement_acceleration_fast");
1470 pkt << g_settings->getFloat("movement_speed_walk");
1471 pkt << g_settings->getFloat("movement_speed_crouch");
1472 pkt << g_settings->getFloat("movement_speed_fast");
1473 pkt << g_settings->getFloat("movement_speed_climb");
1474 pkt << g_settings->getFloat("movement_speed_jump");
1475 pkt << g_settings->getFloat("movement_liquid_fluidity");
1476 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1477 pkt << g_settings->getFloat("movement_liquid_sink");
1478 pkt << g_settings->getFloat("movement_gravity");
1483 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1485 if (!g_settings->getBool("enable_damage"))
1488 u16 peer_id = playersao->getPeerID();
1489 bool is_alive = playersao->getHP() > 0;
1492 SendPlayerHP(peer_id);
1497 void Server::SendHP(u16 peer_id, u8 hp)
1499 DSTACK(FUNCTION_NAME);
1501 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1506 void Server::SendBreath(u16 peer_id, u16 breath)
1508 DSTACK(FUNCTION_NAME);
1510 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1511 pkt << (u16) breath;
1515 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1516 const std::string &custom_reason, bool reconnect)
1518 assert(reason < SERVER_ACCESSDENIED_MAX);
1520 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1522 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1523 pkt << custom_reason;
1524 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1525 reason == SERVER_ACCESSDENIED_CRASH)
1526 pkt << custom_reason << (u8)reconnect;
1530 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1532 DSTACK(FUNCTION_NAME);
1534 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1539 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1540 v3f camera_point_target)
1542 DSTACK(FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1545 pkt << set_camera_point_target << camera_point_target;
1549 void Server::SendItemDef(u16 peer_id,
1550 IItemDefManager *itemdef, u16 protocol_version)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1558 u32 length of the next item
1559 zlib-compressed serialized ItemDefManager
1561 std::ostringstream tmp_os(std::ios::binary);
1562 itemdef->serialize(tmp_os, protocol_version);
1563 std::ostringstream tmp_os2(std::ios::binary);
1564 compressZlib(tmp_os.str(), tmp_os2);
1565 pkt.putLongString(tmp_os2.str());
1568 verbosestream << "Server: Sending item definitions to id(" << peer_id
1569 << "): size=" << pkt.getSize() << std::endl;
1574 void Server::SendNodeDef(u16 peer_id,
1575 INodeDefManager *nodedef, u16 protocol_version)
1577 DSTACK(FUNCTION_NAME);
1579 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1583 u32 length of the next item
1584 zlib-compressed serialized NodeDefManager
1586 std::ostringstream tmp_os(std::ios::binary);
1587 nodedef->serialize(tmp_os, protocol_version);
1588 std::ostringstream tmp_os2(std::ios::binary);
1589 compressZlib(tmp_os.str(), tmp_os2);
1591 pkt.putLongString(tmp_os2.str());
1594 verbosestream << "Server: Sending node definitions to id(" << peer_id
1595 << "): size=" << pkt.getSize() << std::endl;
1601 Non-static send methods
1604 void Server::SendInventory(PlayerSAO* playerSAO)
1606 DSTACK(FUNCTION_NAME);
1608 UpdateCrafting(playerSAO->getPlayer());
1614 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1616 std::ostringstream os;
1617 playerSAO->getInventory()->serialize(os);
1619 std::string s = os.str();
1621 pkt.putRawString(s.c_str(), s.size());
1625 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1627 DSTACK(FUNCTION_NAME);
1629 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1632 if (peer_id != PEER_ID_INEXISTENT) {
1636 m_clients.sendToAll(0, &pkt, true);
1640 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1641 const std::string &formname)
1643 DSTACK(FUNCTION_NAME);
1645 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1647 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1653 // Spawns a particle on peer with peer_id
1654 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1655 float expirationtime, float size, bool collisiondetection,
1656 bool collision_removal,
1657 bool vertical, const std::string &texture)
1659 DSTACK(FUNCTION_NAME);
1661 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1663 pkt << pos << velocity << acceleration << expirationtime
1664 << size << collisiondetection;
1665 pkt.putLongString(texture);
1667 pkt << collision_removal;
1669 if (peer_id != PEER_ID_INEXISTENT) {
1673 m_clients.sendToAll(0, &pkt, true);
1677 // Adds a ParticleSpawner on peer with peer_id
1678 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1679 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1680 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1681 bool vertical, const std::string &texture, u32 id)
1683 DSTACK(FUNCTION_NAME);
1685 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1687 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1688 << minacc << maxacc << minexptime << maxexptime << minsize
1689 << maxsize << collisiondetection;
1691 pkt.putLongString(texture);
1693 pkt << id << vertical;
1694 pkt << collision_removal;
1696 if (peer_id != PEER_ID_INEXISTENT) {
1700 m_clients.sendToAll(0, &pkt, true);
1704 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1706 DSTACK(FUNCTION_NAME);
1708 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1710 // Ugly error in this packet
1713 if (peer_id != PEER_ID_INEXISTENT) {
1717 m_clients.sendToAll(0, &pkt, true);
1722 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1724 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1726 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1727 << form->text << form->number << form->item << form->dir
1728 << form->align << form->offset << form->world_pos << form->size;
1733 void Server::SendHUDRemove(u16 peer_id, u32 id)
1735 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1740 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1742 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1743 pkt << id << (u8) stat;
1747 case HUD_STAT_SCALE:
1748 case HUD_STAT_ALIGN:
1749 case HUD_STAT_OFFSET:
1750 pkt << *(v2f *) value;
1754 pkt << *(std::string *) value;
1756 case HUD_STAT_WORLD_POS:
1757 pkt << *(v3f *) value;
1760 pkt << *(v2s32 *) value;
1762 case HUD_STAT_NUMBER:
1766 pkt << *(u32 *) value;
1773 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1775 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1777 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1779 pkt << flags << mask;
1784 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1786 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1787 pkt << param << value;
1791 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1792 const std::string &type, const std::vector<std::string> ¶ms)
1794 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1795 pkt << bgcolor << type << (u16) params.size();
1797 for(size_t i=0; i<params.size(); i++)
1803 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1806 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1809 pkt << do_override << (u16) (ratio * 65535);
1814 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1816 DSTACK(FUNCTION_NAME);
1818 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1819 pkt << time << time_speed;
1821 if (peer_id == PEER_ID_INEXISTENT) {
1822 m_clients.sendToAll(0, &pkt, true);
1829 void Server::SendPlayerHP(u16 peer_id)
1831 DSTACK(FUNCTION_NAME);
1832 PlayerSAO *playersao = getPlayerSAO(peer_id);
1833 // In some rare case if the player is disconnected
1834 // while Lua call l_punch, for example, this can be NULL
1838 SendHP(peer_id, playersao->getHP());
1839 m_script->player_event(playersao,"health_changed");
1841 // Send to other clients
1842 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1843 ActiveObjectMessage aom(playersao->getId(), true, str);
1844 playersao->m_messages_out.push(aom);
1847 void Server::SendPlayerBreath(u16 peer_id)
1849 DSTACK(FUNCTION_NAME);
1850 PlayerSAO *playersao = getPlayerSAO(peer_id);
1853 m_script->player_event(playersao, "breath_changed");
1854 SendBreath(peer_id, playersao->getBreath());
1857 void Server::SendMovePlayer(u16 peer_id)
1859 DSTACK(FUNCTION_NAME);
1860 RemotePlayer *player = m_env->getPlayer(peer_id);
1863 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1864 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1867 v3f pos = player->getPosition();
1868 f32 pitch = player->getPitch();
1869 f32 yaw = player->getYaw();
1870 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1871 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1872 << " pitch=" << pitch
1880 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1882 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1885 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1886 << animation_frames[3] << animation_speed;
1891 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1893 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1894 pkt << first << third;
1897 void Server::SendPlayerPrivileges(u16 peer_id)
1899 RemotePlayer *player = m_env->getPlayer(peer_id);
1901 if(player->peer_id == PEER_ID_INEXISTENT)
1904 std::set<std::string> privs;
1905 m_script->getAuth(player->getName(), NULL, &privs);
1907 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1908 pkt << (u16) privs.size();
1910 for(std::set<std::string>::const_iterator i = privs.begin();
1911 i != privs.end(); ++i) {
1918 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1920 RemotePlayer *player = m_env->getPlayer(peer_id);
1922 if(player->peer_id == PEER_ID_INEXISTENT)
1925 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1926 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1930 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1932 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1933 pkt.putRawString(datas.c_str(), datas.size());
1935 return pkt.getSize();
1938 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1940 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1941 datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 m_clients.send(pkt.getPeerId(),
1946 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1951 s32 Server::playSound(const SimpleSoundSpec &spec,
1952 const ServerSoundParams ¶ms)
1954 // Find out initial position of sound
1955 bool pos_exists = false;
1956 v3f pos = params.getPos(m_env, &pos_exists);
1957 // If position is not found while it should be, cancel sound
1958 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1961 // Filter destination clients
1962 std::vector<u16> dst_clients;
1963 if(params.to_player != "")
1965 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1967 infostream<<"Server::playSound: Player \""<<params.to_player
1968 <<"\" not found"<<std::endl;
1971 if(player->peer_id == PEER_ID_INEXISTENT){
1972 infostream<<"Server::playSound: Player \""<<params.to_player
1973 <<"\" not connected"<<std::endl;
1976 dst_clients.push_back(player->peer_id);
1979 std::vector<u16> clients = m_clients.getClientIDs();
1981 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1982 RemotePlayer *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 (RemotePlayer *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 (RemotePlayer *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 RemotePlayer *player = m_env->getPlayer(peer_id);
2642 /* Run scripts and remove from environment */
2643 if(player != NULL) {
2644 PlayerSAO *playersao = player->getPlayerSAO();
2647 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2649 playersao->disconnected();
2656 if(player != NULL && reason != CDR_DENY) {
2657 std::ostringstream os(std::ios_base::binary);
2658 std::vector<u16> clients = m_clients.getClientIDs();
2660 for(std::vector<u16>::iterator i = clients.begin();
2661 i != clients.end(); ++i) {
2663 RemotePlayer *player = m_env->getPlayer(*i);
2667 // Get name of player
2668 os << player->getName() << " ";
2671 std::string name = player->getName();
2672 actionstream << name << " "
2673 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2674 << " List of players: " << os.str() << std::endl;
2676 m_admin_chat->outgoing_queue.push_back(
2677 new ChatEventNick(CET_NICK_REMOVE, name));
2681 MutexAutoLock env_lock(m_env_mutex);
2682 m_clients.DeleteClient(peer_id);
2686 // Send leave chat message to all remaining clients
2687 if(message.length() != 0)
2688 SendChatMessage(PEER_ID_INEXISTENT,message);
2691 void Server::UpdateCrafting(RemotePlayer *player)
2693 DSTACK(FUNCTION_NAME);
2695 // Get a preview for crafting
2697 InventoryLocation loc;
2698 loc.setPlayer(player->getName());
2699 std::vector<ItemStack> output_replacements;
2700 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2701 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2702 (&player->inventory)->getList("craft"), loc);
2704 // Put the new preview in
2705 InventoryList *plist = player->inventory.getList("craftpreview");
2706 sanity_check(plist);
2707 sanity_check(plist->getSize() >= 1);
2708 plist->changeItem(0, preview);
2711 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2713 if (evt->type == CET_NICK_ADD) {
2714 // The terminal informed us of its nick choice
2715 m_admin_nick = ((ChatEventNick *)evt)->nick;
2716 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2717 errorstream << "You haven't set up an account." << std::endl
2718 << "Please log in using the client as '"
2719 << m_admin_nick << "' with a secure password." << std::endl
2720 << "Until then, you can't execute admin tasks via the console," << std::endl
2721 << "and everybody can claim the user account instead of you," << std::endl
2722 << "giving them full control over this server." << std::endl;
2725 assert(evt->type == CET_CHAT);
2726 handleAdminChat((ChatEventChat *)evt);
2730 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2731 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2733 // If something goes wrong, this player is to blame
2734 RollbackScopeActor rollback_scope(m_rollback,
2735 std::string("player:") + name);
2739 // Whether to send line to the player that sent the message, or to all players
2740 bool broadcast_line = true;
2743 bool ate = m_script->on_chat_message(name,
2744 wide_to_utf8(wmessage));
2745 // If script ate the message, don't proceed
2750 switch (player->canSendChatMessage()) {
2751 case RPLAYER_CHATRESULT_FLOODING: {
2752 std::wstringstream ws;
2753 ws << L"You cannot send more messages. You are limited to "
2754 << g_settings->getFloat("chat_message_limit_per_10sec")
2755 << L" messages per 10 seconds.";
2758 case RPLAYER_CHATRESULT_KICK:
2759 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2761 case RPLAYER_CHATRESULT_OK: break;
2762 default: FATAL_ERROR("Unhandled chat filtering result found.");
2766 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2767 return L"Your message exceed the maximum chat message limit set on the server. "
2768 L"It was refused. Send a shorter message";
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];
2781 if (check_shout_priv && !checkPriv(name, "shout")) {
2782 line += L"-!- You don't have permission to shout.";
2783 broadcast_line = false;
2793 Tell calling method to send the message to sender
2795 if (!broadcast_line) {
2799 Send the message to others
2801 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2803 std::vector<u16> clients = m_clients.getClientIDs();
2805 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2806 for (u16 i = 0; i < clients.size(); i++) {
2807 u16 cid = clients[i];
2808 if (cid != peer_id_to_avoid_sending)
2809 SendChatMessage(cid, line);
2815 void Server::handleAdminChat(const ChatEventChat *evt)
2817 std::string name = evt->nick;
2818 std::wstring wname = utf8_to_wide(name);
2819 std::wstring wmessage = evt->evt_msg;
2821 std::wstring answer = handleChat(name, wname, wmessage);
2823 // If asked to send answer to sender
2824 if (!answer.empty()) {
2825 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2829 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2831 RemoteClient *client = getClientNoEx(peer_id,state_min);
2833 throw ClientNotFoundException("Client not found");
2837 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2839 return m_clients.getClientNoEx(peer_id, state_min);
2842 std::string Server::getPlayerName(u16 peer_id)
2844 RemotePlayer *player = m_env->getPlayer(peer_id);
2846 return "[id="+itos(peer_id)+"]";
2847 return player->getName();
2850 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2852 RemotePlayer *player = m_env->getPlayer(peer_id);
2855 return player->getPlayerSAO();
2858 std::wstring Server::getStatusString()
2860 std::wostringstream os(std::ios_base::binary);
2863 os<<L"version="<<narrow_to_wide(g_version_string);
2865 os<<L", uptime="<<m_uptime.get();
2867 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2868 // Information about clients
2871 std::vector<u16> clients = m_clients.getClientIDs();
2872 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2874 RemotePlayer *player = m_env->getPlayer(*i);
2875 // Get name of player
2876 std::wstring name = L"unknown";
2878 name = narrow_to_wide(player->getName());
2879 // Add name to information string
2887 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2888 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2889 if(g_settings->get("motd") != "")
2890 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2894 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2896 std::set<std::string> privs;
2897 m_script->getAuth(name, NULL, &privs);
2901 bool Server::checkPriv(const std::string &name, const std::string &priv)
2903 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2904 return (privs.count(priv) != 0);
2907 void Server::reportPrivsModified(const std::string &name)
2910 std::vector<u16> clients = m_clients.getClientIDs();
2911 for(std::vector<u16>::iterator i = clients.begin();
2912 i != clients.end(); ++i) {
2913 RemotePlayer *player = m_env->getPlayer(*i);
2914 reportPrivsModified(player->getName());
2917 RemotePlayer *player = m_env->getPlayer(name.c_str());
2920 SendPlayerPrivileges(player->peer_id);
2921 PlayerSAO *sao = player->getPlayerSAO();
2924 sao->updatePrivileges(
2925 getPlayerEffectivePrivs(name),
2930 void Server::reportInventoryFormspecModified(const std::string &name)
2932 RemotePlayer *player = m_env->getPlayer(name.c_str());
2935 SendPlayerInventoryFormspec(player->peer_id);
2938 void Server::setIpBanned(const std::string &ip, const std::string &name)
2940 m_banmanager->add(ip, name);
2943 void Server::unsetIpBanned(const std::string &ip_or_name)
2945 m_banmanager->remove(ip_or_name);
2948 std::string Server::getBanDescription(const std::string &ip_or_name)
2950 return m_banmanager->getBanDescription(ip_or_name);
2953 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2955 // m_env will be NULL if the server is initializing
2959 if (m_admin_nick == name && !m_admin_nick.empty()) {
2960 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2963 RemotePlayer *player = m_env->getPlayer(name);
2968 if (player->peer_id == PEER_ID_INEXISTENT)
2971 SendChatMessage(player->peer_id, msg);
2974 bool Server::showFormspec(const char *playername, const std::string &formspec,
2975 const std::string &formname)
2977 // m_env will be NULL if the server is initializing
2981 RemotePlayer *player = m_env->getPlayer(playername);
2985 SendShowFormspecMessage(player->peer_id, formspec, formname);
2989 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
2994 u32 id = player->addHud(form);
2996 SendHUDAdd(player->peer_id, id, form);
3001 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3005 HudElement* todel = player->removeHud(id);
3012 SendHUDRemove(player->peer_id, id);
3016 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3021 SendHUDChange(player->peer_id, id, stat, data);
3025 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3030 SendHUDSetFlags(player->peer_id, flags, mask);
3031 player->hud_flags &= ~mask;
3032 player->hud_flags |= flags;
3034 PlayerSAO* playersao = player->getPlayerSAO();
3036 if (playersao == NULL)
3039 m_script->player_event(playersao, "hud_changed");
3043 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3048 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3051 player->setHotbarItemcount(hotbar_itemcount);
3052 std::ostringstream os(std::ios::binary);
3053 writeS32(os, hotbar_itemcount);
3054 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3058 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3063 player->setHotbarImage(name);
3064 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3067 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3071 return player->getHotbarImage();
3074 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3079 player->setHotbarSelectedImage(name);
3080 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3083 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3084 v2s32 animation_frames[4], f32 frame_speed)
3089 player->setLocalAnimations(animation_frames, frame_speed);
3090 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3094 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3099 player->eye_offset_first = first;
3100 player->eye_offset_third = third;
3101 SendEyeOffset(player->peer_id, first, third);
3105 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3106 const std::string &type, const std::vector<std::string> ¶ms)
3111 player->setSky(bgcolor, type, params);
3112 SendSetSky(player->peer_id, bgcolor, type, params);
3116 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3122 player->overrideDayNightRatio(do_override, ratio);
3123 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3127 void Server::notifyPlayers(const std::wstring &msg)
3129 SendChatMessage(PEER_ID_INEXISTENT,msg);
3132 void Server::spawnParticle(const std::string &playername, v3f pos,
3133 v3f velocity, v3f acceleration,
3134 float expirationtime, float size, bool
3135 collisiondetection, bool collision_removal,
3136 bool vertical, const std::string &texture)
3138 // m_env will be NULL if the server is initializing
3142 u16 peer_id = PEER_ID_INEXISTENT;
3143 if (playername != "") {
3144 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3147 peer_id = player->peer_id;
3150 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3151 expirationtime, size, collisiondetection,
3152 collision_removal, vertical, texture);
3155 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3156 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3157 float minexptime, float maxexptime, float minsize, float maxsize,
3158 bool collisiondetection, bool collision_removal,
3159 bool vertical, const std::string &texture,
3160 const std::string &playername)
3162 // m_env will be NULL if the server is initializing
3166 u16 peer_id = PEER_ID_INEXISTENT;
3167 if (playername != "") {
3168 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3171 peer_id = player->peer_id;
3174 u32 id = m_env->addParticleSpawner(spawntime);
3175 SendAddParticleSpawner(peer_id, amount, spawntime,
3176 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3177 minexptime, maxexptime, minsize, maxsize,
3178 collisiondetection, collision_removal, vertical, texture, id);
3183 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3185 // m_env will be NULL if the server is initializing
3187 throw ServerError("Can't delete particle spawners during initialisation!");
3189 u16 peer_id = PEER_ID_INEXISTENT;
3190 if (playername != "") {
3191 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3194 peer_id = player->peer_id;
3197 m_env->deleteParticleSpawner(id);
3198 SendDeleteParticleSpawner(peer_id, id);
3201 Inventory* Server::createDetachedInventory(const std::string &name)
3203 if(m_detached_inventories.count(name) > 0){
3204 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3205 delete m_detached_inventories[name];
3207 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3209 Inventory *inv = new Inventory(m_itemdef);
3211 m_detached_inventories[name] = inv;
3212 //TODO find a better way to do this
3213 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3217 // actions: time-reversed list
3218 // Return value: success/failure
3219 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3220 std::list<std::string> *log)
3222 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3223 ServerMap *map = (ServerMap*)(&m_env->getMap());
3225 // Fail if no actions to handle
3226 if(actions.empty()){
3227 log->push_back("Nothing to do.");
3234 for(std::list<RollbackAction>::const_iterator
3235 i = actions.begin();
3236 i != actions.end(); ++i)
3238 const RollbackAction &action = *i;
3240 bool success = action.applyRevert(map, this, this);
3243 std::ostringstream os;
3244 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3245 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3247 log->push_back(os.str());
3249 std::ostringstream os;
3250 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3251 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3253 log->push_back(os.str());
3257 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3258 <<" failed"<<std::endl;
3260 // Call it done if less than half failed
3261 return num_failed <= num_tried/2;
3264 // IGameDef interface
3266 IItemDefManager *Server::getItemDefManager()
3271 INodeDefManager *Server::getNodeDefManager()
3276 ICraftDefManager *Server::getCraftDefManager()
3280 ITextureSource *Server::getTextureSource()
3284 IShaderSource *Server::getShaderSource()
3288 scene::ISceneManager *Server::getSceneManager()
3293 u16 Server::allocateUnknownNodeId(const std::string &name)
3295 return m_nodedef->allocateDummy(name);
3298 ISoundManager *Server::getSoundManager()
3300 return &dummySoundManager;
3303 MtEventManager *Server::getEventManager()
3308 IWritableItemDefManager *Server::getWritableItemDefManager()
3313 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3318 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3323 const ModSpec *Server::getModSpec(const std::string &modname) const
3325 std::vector<ModSpec>::const_iterator it;
3326 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3327 const ModSpec &mod = *it;
3328 if (mod.name == modname)
3334 void Server::getModNames(std::vector<std::string> &modlist)
3336 std::vector<ModSpec>::iterator it;
3337 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3338 modlist.push_back(it->name);
3341 std::string Server::getBuiltinLuaPath()
3343 return porting::path_share + DIR_DELIM + "builtin";
3346 v3f Server::findSpawnPos()
3348 ServerMap &map = m_env->getServerMap();
3350 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3351 return nodeposf * BS;
3354 bool is_good = false;
3356 // Try to find a good place a few times
3357 for(s32 i = 0; i < 4000 && !is_good; i++) {
3359 // We're going to try to throw the player to this position
3360 v2s16 nodepos2d = v2s16(
3361 -range + (myrand() % (range * 2)),
3362 -range + (myrand() % (range * 2)));
3364 // Get spawn level at point
3365 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3366 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3367 // the mapgen to signify an unsuitable spawn position
3368 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3371 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3374 for (s32 i = 0; i < 10; i++) {
3375 v3s16 blockpos = getNodeBlockPos(nodepos);
3376 map.emergeBlock(blockpos, true);
3377 content_t c = map.getNodeNoEx(nodepos).getContent();
3378 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3380 if (air_count >= 2) {
3381 nodeposf = intToFloat(nodepos, BS);
3382 // Don't spawn the player outside map boundaries
3383 if (objectpos_over_limit(nodeposf))
3396 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3398 bool newplayer = false;
3401 Try to get an existing player
3403 RemotePlayer *player = m_env->getPlayer(name);
3405 // If player is already connected, cancel
3406 if (player != NULL && player->peer_id != 0) {
3407 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3412 If player with the wanted peer_id already exists, cancel.
3414 if (m_env->getPlayer(peer_id) != NULL) {
3415 infostream<<"emergePlayer(): Player with wrong name but same"
3416 " peer_id already exists"<<std::endl;
3420 // Load player if it isn't already loaded
3422 player = m_env->loadPlayer(name);
3425 // Create player if it doesn't exist
3428 player = new RemotePlayer(name, this->idef());
3429 // Set player position
3430 infostream<<"Server: Finding spawn place for player \""
3431 <<name<<"\""<<std::endl;
3432 v3f pos = findSpawnPos();
3433 player->setPosition(pos);
3435 // Make sure the player is saved
3436 player->setModified(true);
3438 // Add player to environment
3439 m_env->addPlayer(player);
3441 // If the player exists, ensure that they respawn inside legal bounds
3442 // This fixes an assert crash when the player can't be added
3443 // to the environment
3444 if (objectpos_over_limit(player->getPosition())) {
3445 actionstream << "Respawn position for player \""
3446 << name << "\" outside limits, resetting" << std::endl;
3447 v3f pos = findSpawnPos();
3448 player->setPosition(pos);
3452 // Create a new player active object
3453 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3454 getPlayerEffectivePrivs(player->getName()),
3457 player->protocol_version = proto_version;
3459 /* Clean up old HUD elements from previous sessions */
3462 /* Add object to environment */
3463 m_env->addActiveObject(playersao);
3467 m_script->on_newplayer(playersao);
3473 void dedicated_server_loop(Server &server, bool &kill)
3475 DSTACK(FUNCTION_NAME);
3477 verbosestream<<"dedicated_server_loop()"<<std::endl;
3479 IntervalLimiter m_profiler_interval;
3481 static const float steplen = g_settings->getFloat("dedicated_server_step");
3482 static const float profiler_print_interval =
3483 g_settings->getFloat("profiler_print_interval");
3486 // This is kind of a hack but can be done like this
3487 // because server.step() is very light
3489 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3490 sleep_ms((int)(steplen*1000.0));
3492 server.step(steplen);
3494 if(server.getShutdownRequested() || kill)
3496 infostream<<"Dedicated server quitting"<<std::endl;
3498 if(g_settings->getBool("server_announce"))
3499 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3507 if (profiler_print_interval != 0) {
3508 if(m_profiler_interval.step(steplen, profiler_print_interval))
3510 infostream<<"Profiler:"<<std::endl;
3511 g_profiler->print(infostream);
3512 g_profiler->clear();