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 u16 attached_id, 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;
1697 if (peer_id != PEER_ID_INEXISTENT) {
1701 m_clients.sendToAll(0, &pkt, true);
1705 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1707 DSTACK(FUNCTION_NAME);
1709 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1711 // Ugly error in this packet
1714 if (peer_id != PEER_ID_INEXISTENT) {
1718 m_clients.sendToAll(0, &pkt, true);
1723 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1725 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1727 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1728 << form->text << form->number << form->item << form->dir
1729 << form->align << form->offset << form->world_pos << form->size;
1734 void Server::SendHUDRemove(u16 peer_id, u32 id)
1736 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1741 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1743 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1744 pkt << id << (u8) stat;
1748 case HUD_STAT_SCALE:
1749 case HUD_STAT_ALIGN:
1750 case HUD_STAT_OFFSET:
1751 pkt << *(v2f *) value;
1755 pkt << *(std::string *) value;
1757 case HUD_STAT_WORLD_POS:
1758 pkt << *(v3f *) value;
1761 pkt << *(v2s32 *) value;
1763 case HUD_STAT_NUMBER:
1767 pkt << *(u32 *) value;
1774 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1776 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1778 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1780 pkt << flags << mask;
1785 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1787 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1788 pkt << param << value;
1792 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1793 const std::string &type, const std::vector<std::string> ¶ms)
1795 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1796 pkt << bgcolor << type << (u16) params.size();
1798 for(size_t i=0; i<params.size(); i++)
1804 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1807 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1810 pkt << do_override << (u16) (ratio * 65535);
1815 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1817 DSTACK(FUNCTION_NAME);
1819 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1820 pkt << time << time_speed;
1822 if (peer_id == PEER_ID_INEXISTENT) {
1823 m_clients.sendToAll(0, &pkt, true);
1830 void Server::SendPlayerHP(u16 peer_id)
1832 DSTACK(FUNCTION_NAME);
1833 PlayerSAO *playersao = getPlayerSAO(peer_id);
1834 // In some rare case if the player is disconnected
1835 // while Lua call l_punch, for example, this can be NULL
1839 SendHP(peer_id, playersao->getHP());
1840 m_script->player_event(playersao,"health_changed");
1842 // Send to other clients
1843 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1844 ActiveObjectMessage aom(playersao->getId(), true, str);
1845 playersao->m_messages_out.push(aom);
1848 void Server::SendPlayerBreath(u16 peer_id)
1850 DSTACK(FUNCTION_NAME);
1851 PlayerSAO *playersao = getPlayerSAO(peer_id);
1854 m_script->player_event(playersao, "breath_changed");
1855 SendBreath(peer_id, playersao->getBreath());
1858 void Server::SendMovePlayer(u16 peer_id)
1860 DSTACK(FUNCTION_NAME);
1861 RemotePlayer *player = m_env->getPlayer(peer_id);
1864 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1865 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1868 v3f pos = player->getPosition();
1869 f32 pitch = player->getPitch();
1870 f32 yaw = player->getYaw();
1871 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1872 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1873 << " pitch=" << pitch
1881 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1883 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1886 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1887 << animation_frames[3] << animation_speed;
1892 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1894 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1895 pkt << first << third;
1898 void Server::SendPlayerPrivileges(u16 peer_id)
1900 RemotePlayer *player = m_env->getPlayer(peer_id);
1902 if(player->peer_id == PEER_ID_INEXISTENT)
1905 std::set<std::string> privs;
1906 m_script->getAuth(player->getName(), NULL, &privs);
1908 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1909 pkt << (u16) privs.size();
1911 for(std::set<std::string>::const_iterator i = privs.begin();
1912 i != privs.end(); ++i) {
1919 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1921 RemotePlayer *player = m_env->getPlayer(peer_id);
1923 if(player->peer_id == PEER_ID_INEXISTENT)
1926 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1927 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1931 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1933 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1934 pkt.putRawString(datas.c_str(), datas.size());
1936 return pkt.getSize();
1939 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1941 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1942 datas.size(), peer_id);
1944 pkt.putRawString(datas.c_str(), datas.size());
1946 m_clients.send(pkt.getPeerId(),
1947 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1952 s32 Server::playSound(const SimpleSoundSpec &spec,
1953 const ServerSoundParams ¶ms)
1955 // Find out initial position of sound
1956 bool pos_exists = false;
1957 v3f pos = params.getPos(m_env, &pos_exists);
1958 // If position is not found while it should be, cancel sound
1959 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1962 // Filter destination clients
1963 std::vector<u16> dst_clients;
1964 if(params.to_player != "")
1966 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1968 infostream<<"Server::playSound: Player \""<<params.to_player
1969 <<"\" not found"<<std::endl;
1972 if(player->peer_id == PEER_ID_INEXISTENT){
1973 infostream<<"Server::playSound: Player \""<<params.to_player
1974 <<"\" not connected"<<std::endl;
1977 dst_clients.push_back(player->peer_id);
1980 std::vector<u16> clients = m_clients.getClientIDs();
1982 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1983 RemotePlayer *player = m_env->getPlayer(*i);
1988 if(player->getPosition().getDistanceFrom(pos) >
1989 params.max_hear_distance)
1992 dst_clients.push_back(*i);
1996 if(dst_clients.empty())
2000 s32 id = m_next_sound_id++;
2001 // The sound will exist as a reference in m_playing_sounds
2002 m_playing_sounds[id] = ServerPlayingSound();
2003 ServerPlayingSound &psound = m_playing_sounds[id];
2004 psound.params = params;
2006 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2007 pkt << id << spec.name << (float) (spec.gain * params.gain)
2008 << (u8) params.type << pos << params.object << params.loop;
2010 for(std::vector<u16>::iterator i = dst_clients.begin();
2011 i != dst_clients.end(); ++i) {
2012 psound.clients.insert(*i);
2013 m_clients.send(*i, 0, &pkt, true);
2017 void Server::stopSound(s32 handle)
2019 // Get sound reference
2020 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2021 if (i == m_playing_sounds.end())
2023 ServerPlayingSound &psound = i->second;
2025 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2028 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2029 i != psound.clients.end(); ++i) {
2031 m_clients.send(*i, 0, &pkt, true);
2033 // Remove sound reference
2034 m_playing_sounds.erase(i);
2037 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2038 std::vector<u16> *far_players, float far_d_nodes)
2040 float maxd = far_d_nodes*BS;
2041 v3f p_f = intToFloat(p, BS);
2043 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2046 std::vector<u16> clients = m_clients.getClientIDs();
2047 for(std::vector<u16>::iterator i = clients.begin();
2048 i != clients.end(); ++i) {
2051 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2052 // If player is far away, only set modified blocks not sent
2053 v3f player_pos = player->getPosition();
2054 if(player_pos.getDistanceFrom(p_f) > maxd) {
2055 far_players->push_back(*i);
2062 m_clients.send(*i, 0, &pkt, true);
2066 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2067 std::vector<u16> *far_players, float far_d_nodes,
2068 bool remove_metadata)
2070 float maxd = far_d_nodes*BS;
2071 v3f p_f = intToFloat(p, BS);
2073 std::vector<u16> clients = m_clients.getClientIDs();
2074 for(std::vector<u16>::iterator i = clients.begin();
2075 i != clients.end(); ++i) {
2079 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2080 // If player is far away, only set modified blocks not sent
2081 v3f player_pos = player->getPosition();
2082 if(player_pos.getDistanceFrom(p_f) > maxd) {
2083 far_players->push_back(*i);
2089 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2091 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2093 pkt << p << n.param0 << n.param1 << n.param2
2094 << (u8) (remove_metadata ? 0 : 1);
2096 if (!remove_metadata) {
2097 if (client->net_proto_version <= 21) {
2098 // Old clients always clear metadata; fix it
2099 // by sending the full block again.
2100 client->SetBlockNotSent(getNodeBlockPos(p));
2107 if (pkt.getSize() > 0)
2108 m_clients.send(*i, 0, &pkt, true);
2112 void Server::setBlockNotSent(v3s16 p)
2114 std::vector<u16> clients = m_clients.getClientIDs();
2116 for(std::vector<u16>::iterator i = clients.begin();
2117 i != clients.end(); ++i) {
2118 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2119 client->SetBlockNotSent(p);
2124 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2126 DSTACK(FUNCTION_NAME);
2128 v3s16 p = block->getPos();
2131 Create a packet with the block in the right format
2134 std::ostringstream os(std::ios_base::binary);
2135 block->serialize(os, ver, false);
2136 block->serializeNetworkSpecific(os, net_proto_version);
2137 std::string s = os.str();
2139 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2142 pkt.putRawString(s.c_str(), s.size());
2146 void Server::SendBlocks(float dtime)
2148 DSTACK(FUNCTION_NAME);
2150 MutexAutoLock envlock(m_env_mutex);
2151 //TODO check if one big lock could be faster then multiple small ones
2153 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2155 std::vector<PrioritySortedBlockTransfer> queue;
2157 s32 total_sending = 0;
2160 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2162 std::vector<u16> clients = m_clients.getClientIDs();
2165 for(std::vector<u16>::iterator i = clients.begin();
2166 i != clients.end(); ++i) {
2167 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2172 total_sending += client->SendingCount();
2173 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2179 // Lowest priority number comes first.
2180 // Lowest is most important.
2181 std::sort(queue.begin(), queue.end());
2184 for(u32 i=0; i<queue.size(); i++)
2186 //TODO: Calculate limit dynamically
2187 if(total_sending >= g_settings->getS32
2188 ("max_simultaneous_block_sends_server_total"))
2191 PrioritySortedBlockTransfer q = queue[i];
2193 MapBlock *block = NULL;
2196 block = m_env->getMap().getBlockNoCreate(q.pos);
2198 catch(InvalidPositionException &e)
2203 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2208 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2210 client->SentBlock(q.pos);
2216 void Server::fillMediaCache()
2218 DSTACK(FUNCTION_NAME);
2220 infostream<<"Server: Calculating media file checksums"<<std::endl;
2222 // Collect all media file paths
2223 std::vector<std::string> paths;
2224 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2225 i != m_mods.end(); ++i) {
2226 const ModSpec &mod = *i;
2227 paths.push_back(mod.path + DIR_DELIM + "textures");
2228 paths.push_back(mod.path + DIR_DELIM + "sounds");
2229 paths.push_back(mod.path + DIR_DELIM + "media");
2230 paths.push_back(mod.path + DIR_DELIM + "models");
2232 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2234 // Collect media file information from paths into cache
2235 for(std::vector<std::string>::iterator i = paths.begin();
2236 i != paths.end(); ++i) {
2237 std::string mediapath = *i;
2238 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2239 for (u32 j = 0; j < dirlist.size(); j++) {
2240 if (dirlist[j].dir) // Ignode dirs
2242 std::string filename = dirlist[j].name;
2243 // If name contains illegal characters, ignore the file
2244 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2245 infostream<<"Server: ignoring illegal file name: \""
2246 << filename << "\"" << std::endl;
2249 // If name is not in a supported format, ignore it
2250 const char *supported_ext[] = {
2251 ".png", ".jpg", ".bmp", ".tga",
2252 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2254 ".x", ".b3d", ".md2", ".obj",
2257 if (removeStringEnd(filename, supported_ext) == ""){
2258 infostream << "Server: ignoring unsupported file extension: \""
2259 << filename << "\"" << std::endl;
2262 // Ok, attempt to load the file and add to cache
2263 std::string filepath = mediapath + DIR_DELIM + filename;
2265 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2267 errorstream << "Server::fillMediaCache(): Could not open \""
2268 << filename << "\" for reading" << std::endl;
2271 std::ostringstream tmp_os(std::ios_base::binary);
2275 fis.read(buf, 1024);
2276 std::streamsize len = fis.gcount();
2277 tmp_os.write(buf, len);
2286 errorstream<<"Server::fillMediaCache(): Failed to read \""
2287 << filename << "\"" << std::endl;
2290 if(tmp_os.str().length() == 0) {
2291 errorstream << "Server::fillMediaCache(): Empty file \""
2292 << filepath << "\"" << std::endl;
2297 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2299 unsigned char *digest = sha1.getDigest();
2300 std::string sha1_base64 = base64_encode(digest, 20);
2301 std::string sha1_hex = hex_encode((char*)digest, 20);
2305 m_media[filename] = MediaInfo(filepath, sha1_base64);
2306 verbosestream << "Server: " << sha1_hex << " is " << filename
2312 void Server::sendMediaAnnouncement(u16 peer_id)
2314 DSTACK(FUNCTION_NAME);
2316 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2320 std::ostringstream os(std::ios_base::binary);
2322 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2323 pkt << (u16) m_media.size();
2325 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2326 i != m_media.end(); ++i) {
2327 pkt << i->first << i->second.sha1_digest;
2330 pkt << g_settings->get("remote_media");
2334 struct SendableMedia
2340 SendableMedia(const std::string &name_="", const std::string &path_="",
2341 const std::string &data_=""):
2348 void Server::sendRequestedMedia(u16 peer_id,
2349 const std::vector<std::string> &tosend)
2351 DSTACK(FUNCTION_NAME);
2353 verbosestream<<"Server::sendRequestedMedia(): "
2354 <<"Sending files to client"<<std::endl;
2358 // Put 5kB in one bunch (this is not accurate)
2359 u32 bytes_per_bunch = 5000;
2361 std::vector< std::vector<SendableMedia> > file_bunches;
2362 file_bunches.push_back(std::vector<SendableMedia>());
2364 u32 file_size_bunch_total = 0;
2366 for(std::vector<std::string>::const_iterator i = tosend.begin();
2367 i != tosend.end(); ++i) {
2368 const std::string &name = *i;
2370 if (m_media.find(name) == m_media.end()) {
2371 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2372 <<"unknown file \""<<(name)<<"\""<<std::endl;
2376 //TODO get path + name
2377 std::string tpath = m_media[name].path;
2380 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2381 if(fis.good() == false){
2382 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2383 <<tpath<<"\" for reading"<<std::endl;
2386 std::ostringstream tmp_os(std::ios_base::binary);
2390 fis.read(buf, 1024);
2391 std::streamsize len = fis.gcount();
2392 tmp_os.write(buf, len);
2393 file_size_bunch_total += len;
2402 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2403 <<name<<"\""<<std::endl;
2406 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2407 <<tname<<"\""<<std::endl;*/
2409 file_bunches[file_bunches.size()-1].push_back(
2410 SendableMedia(name, tpath, tmp_os.str()));
2412 // Start next bunch if got enough data
2413 if(file_size_bunch_total >= bytes_per_bunch) {
2414 file_bunches.push_back(std::vector<SendableMedia>());
2415 file_size_bunch_total = 0;
2420 /* Create and send packets */
2422 u16 num_bunches = file_bunches.size();
2423 for(u16 i = 0; i < num_bunches; i++) {
2426 u16 total number of texture bunches
2427 u16 index of this bunch
2428 u32 number of files in this bunch
2437 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2438 pkt << num_bunches << i << (u32) file_bunches[i].size();
2440 for(std::vector<SendableMedia>::iterator
2441 j = file_bunches[i].begin();
2442 j != file_bunches[i].end(); ++j) {
2444 pkt.putLongString(j->data);
2447 verbosestream << "Server::sendRequestedMedia(): bunch "
2448 << i << "/" << num_bunches
2449 << " files=" << file_bunches[i].size()
2450 << " size=" << pkt.getSize() << std::endl;
2455 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2457 if(m_detached_inventories.count(name) == 0) {
2458 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2461 Inventory *inv = m_detached_inventories[name];
2462 std::ostringstream os(std::ios_base::binary);
2464 os << serializeString(name);
2468 std::string s = os.str();
2470 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2471 pkt.putRawString(s.c_str(), s.size());
2473 if (peer_id != PEER_ID_INEXISTENT) {
2477 m_clients.sendToAll(0, &pkt, true);
2481 void Server::sendDetachedInventories(u16 peer_id)
2483 DSTACK(FUNCTION_NAME);
2485 for(std::map<std::string, Inventory*>::iterator
2486 i = m_detached_inventories.begin();
2487 i != m_detached_inventories.end(); ++i) {
2488 const std::string &name = i->first;
2489 //Inventory *inv = i->second;
2490 sendDetachedInventory(name, peer_id);
2498 void Server::DiePlayer(u16 peer_id)
2500 DSTACK(FUNCTION_NAME);
2501 PlayerSAO *playersao = getPlayerSAO(peer_id);
2502 // In some rare cases this can be NULL -- if the player is disconnected
2503 // when a Lua function modifies l_punch, for example
2507 infostream << "Server::DiePlayer(): Player "
2508 << playersao->getPlayer()->getName()
2509 << " dies" << std::endl;
2511 playersao->setHP(0);
2513 // Trigger scripted stuff
2514 m_script->on_dieplayer(playersao);
2516 SendPlayerHP(peer_id);
2517 SendDeathscreen(peer_id, false, v3f(0,0,0));
2520 void Server::RespawnPlayer(u16 peer_id)
2522 DSTACK(FUNCTION_NAME);
2524 PlayerSAO *playersao = getPlayerSAO(peer_id);
2527 infostream << "Server::RespawnPlayer(): Player "
2528 << playersao->getPlayer()->getName()
2529 << " respawns" << std::endl;
2531 playersao->setHP(PLAYER_MAX_HP);
2532 playersao->setBreath(PLAYER_MAX_BREATH);
2534 SendPlayerHP(peer_id);
2535 SendPlayerBreath(peer_id);
2537 bool repositioned = m_script->on_respawnplayer(playersao);
2539 v3f pos = findSpawnPos();
2540 // setPos will send the new position to client
2541 playersao->setPos(pos);
2546 void Server::DenySudoAccess(u16 peer_id)
2548 DSTACK(FUNCTION_NAME);
2550 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2555 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2556 const std::string &str_reason, bool reconnect)
2558 if (proto_ver >= 25) {
2559 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2561 std::wstring wreason = utf8_to_wide(
2562 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2563 accessDeniedStrings[(u8)reason]);
2564 SendAccessDenied_Legacy(peer_id, wreason);
2567 m_clients.event(peer_id, CSE_SetDenied);
2568 m_con.DisconnectPeer(peer_id);
2572 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2574 DSTACK(FUNCTION_NAME);
2576 SendAccessDenied(peer_id, reason, custom_reason);
2577 m_clients.event(peer_id, CSE_SetDenied);
2578 m_con.DisconnectPeer(peer_id);
2581 // 13/03/15: remove this function when protocol version 25 will become
2582 // the minimum version for MT users, maybe in 1 year
2583 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2585 DSTACK(FUNCTION_NAME);
2587 SendAccessDenied_Legacy(peer_id, reason);
2588 m_clients.event(peer_id, CSE_SetDenied);
2589 m_con.DisconnectPeer(peer_id);
2592 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2594 DSTACK(FUNCTION_NAME);
2597 RemoteClient* client = getClient(peer_id, CS_Invalid);
2599 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2601 // Right now, the auth mechs don't change between login and sudo mode.
2602 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2603 client->allowed_sudo_mechs = sudo_auth_mechs;
2605 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2606 << g_settings->getFloat("dedicated_server_step")
2610 m_clients.event(peer_id, CSE_AuthAccept);
2612 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2614 // We only support SRP right now
2615 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2617 resp_pkt << sudo_auth_mechs;
2619 m_clients.event(peer_id, CSE_SudoSuccess);
2623 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2625 DSTACK(FUNCTION_NAME);
2626 std::wstring message;
2629 Clear references to playing sounds
2631 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2632 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2633 ServerPlayingSound &psound = i->second;
2634 psound.clients.erase(peer_id);
2635 if (psound.clients.empty())
2636 m_playing_sounds.erase(i++);
2641 RemotePlayer *player = m_env->getPlayer(peer_id);
2643 /* Run scripts and remove from environment */
2644 if(player != NULL) {
2645 PlayerSAO *playersao = player->getPlayerSAO();
2648 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2650 playersao->disconnected();
2657 if(player != NULL && reason != CDR_DENY) {
2658 std::ostringstream os(std::ios_base::binary);
2659 std::vector<u16> clients = m_clients.getClientIDs();
2661 for(std::vector<u16>::iterator i = clients.begin();
2662 i != clients.end(); ++i) {
2664 RemotePlayer *player = m_env->getPlayer(*i);
2668 // Get name of player
2669 os << player->getName() << " ";
2672 std::string name = player->getName();
2673 actionstream << name << " "
2674 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2675 << " List of players: " << os.str() << std::endl;
2677 m_admin_chat->outgoing_queue.push_back(
2678 new ChatEventNick(CET_NICK_REMOVE, name));
2682 MutexAutoLock env_lock(m_env_mutex);
2683 m_clients.DeleteClient(peer_id);
2687 // Send leave chat message to all remaining clients
2688 if(message.length() != 0)
2689 SendChatMessage(PEER_ID_INEXISTENT,message);
2692 void Server::UpdateCrafting(RemotePlayer *player)
2694 DSTACK(FUNCTION_NAME);
2696 // Get a preview for crafting
2698 InventoryLocation loc;
2699 loc.setPlayer(player->getName());
2700 std::vector<ItemStack> output_replacements;
2701 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2702 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2703 (&player->inventory)->getList("craft"), loc);
2705 // Put the new preview in
2706 InventoryList *plist = player->inventory.getList("craftpreview");
2707 sanity_check(plist);
2708 sanity_check(plist->getSize() >= 1);
2709 plist->changeItem(0, preview);
2712 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2714 if (evt->type == CET_NICK_ADD) {
2715 // The terminal informed us of its nick choice
2716 m_admin_nick = ((ChatEventNick *)evt)->nick;
2717 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2718 errorstream << "You haven't set up an account." << std::endl
2719 << "Please log in using the client as '"
2720 << m_admin_nick << "' with a secure password." << std::endl
2721 << "Until then, you can't execute admin tasks via the console," << std::endl
2722 << "and everybody can claim the user account instead of you," << std::endl
2723 << "giving them full control over this server." << std::endl;
2726 assert(evt->type == CET_CHAT);
2727 handleAdminChat((ChatEventChat *)evt);
2731 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2732 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2734 // If something goes wrong, this player is to blame
2735 RollbackScopeActor rollback_scope(m_rollback,
2736 std::string("player:") + name);
2740 // Whether to send line to the player that sent the message, or to all players
2741 bool broadcast_line = true;
2744 bool ate = m_script->on_chat_message(name,
2745 wide_to_utf8(wmessage));
2746 // If script ate the message, don't proceed
2751 switch (player->canSendChatMessage()) {
2752 case RPLAYER_CHATRESULT_FLOODING: {
2753 std::wstringstream ws;
2754 ws << L"You cannot send more messages. You are limited to "
2755 << g_settings->getFloat("chat_message_limit_per_10sec")
2756 << L" messages per 10 seconds.";
2759 case RPLAYER_CHATRESULT_KICK:
2760 DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
2762 case RPLAYER_CHATRESULT_OK: break;
2763 default: FATAL_ERROR("Unhandled chat filtering result found.");
2767 if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
2768 return L"Your message exceed the maximum chat message limit set on the server. "
2769 L"It was refused. Send a shorter message";
2772 // Commands are implemented in Lua, so only catch invalid
2773 // commands that were not "eaten" and send an error back
2774 if (wmessage[0] == L'/') {
2775 std::wstring wcmd = wmessage.substr(1);
2776 broadcast_line = false;
2777 if (wcmd.length() == 0)
2778 line += L"-!- Empty command";
2780 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2782 if (check_shout_priv && !checkPriv(name, "shout")) {
2783 line += L"-!- You don't have permission to shout.";
2784 broadcast_line = false;
2794 Tell calling method to send the message to sender
2796 if (!broadcast_line) {
2800 Send the message to others
2802 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2804 std::vector<u16> clients = m_clients.getClientIDs();
2806 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2807 for (u16 i = 0; i < clients.size(); i++) {
2808 u16 cid = clients[i];
2809 if (cid != peer_id_to_avoid_sending)
2810 SendChatMessage(cid, line);
2816 void Server::handleAdminChat(const ChatEventChat *evt)
2818 std::string name = evt->nick;
2819 std::wstring wname = utf8_to_wide(name);
2820 std::wstring wmessage = evt->evt_msg;
2822 std::wstring answer = handleChat(name, wname, wmessage);
2824 // If asked to send answer to sender
2825 if (!answer.empty()) {
2826 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2830 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2832 RemoteClient *client = getClientNoEx(peer_id,state_min);
2834 throw ClientNotFoundException("Client not found");
2838 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2840 return m_clients.getClientNoEx(peer_id, state_min);
2843 std::string Server::getPlayerName(u16 peer_id)
2845 RemotePlayer *player = m_env->getPlayer(peer_id);
2847 return "[id="+itos(peer_id)+"]";
2848 return player->getName();
2851 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2853 RemotePlayer *player = m_env->getPlayer(peer_id);
2856 return player->getPlayerSAO();
2859 std::wstring Server::getStatusString()
2861 std::wostringstream os(std::ios_base::binary);
2864 os<<L"version="<<narrow_to_wide(g_version_string);
2866 os<<L", uptime="<<m_uptime.get();
2868 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2869 // Information about clients
2872 std::vector<u16> clients = m_clients.getClientIDs();
2873 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2875 RemotePlayer *player = m_env->getPlayer(*i);
2876 // Get name of player
2877 std::wstring name = L"unknown";
2879 name = narrow_to_wide(player->getName());
2880 // Add name to information string
2888 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2889 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2890 if(g_settings->get("motd") != "")
2891 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2895 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2897 std::set<std::string> privs;
2898 m_script->getAuth(name, NULL, &privs);
2902 bool Server::checkPriv(const std::string &name, const std::string &priv)
2904 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2905 return (privs.count(priv) != 0);
2908 void Server::reportPrivsModified(const std::string &name)
2911 std::vector<u16> clients = m_clients.getClientIDs();
2912 for(std::vector<u16>::iterator i = clients.begin();
2913 i != clients.end(); ++i) {
2914 RemotePlayer *player = m_env->getPlayer(*i);
2915 reportPrivsModified(player->getName());
2918 RemotePlayer *player = m_env->getPlayer(name.c_str());
2921 SendPlayerPrivileges(player->peer_id);
2922 PlayerSAO *sao = player->getPlayerSAO();
2925 sao->updatePrivileges(
2926 getPlayerEffectivePrivs(name),
2931 void Server::reportInventoryFormspecModified(const std::string &name)
2933 RemotePlayer *player = m_env->getPlayer(name.c_str());
2936 SendPlayerInventoryFormspec(player->peer_id);
2939 void Server::setIpBanned(const std::string &ip, const std::string &name)
2941 m_banmanager->add(ip, name);
2944 void Server::unsetIpBanned(const std::string &ip_or_name)
2946 m_banmanager->remove(ip_or_name);
2949 std::string Server::getBanDescription(const std::string &ip_or_name)
2951 return m_banmanager->getBanDescription(ip_or_name);
2954 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2956 // m_env will be NULL if the server is initializing
2960 if (m_admin_nick == name && !m_admin_nick.empty()) {
2961 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2964 RemotePlayer *player = m_env->getPlayer(name);
2969 if (player->peer_id == PEER_ID_INEXISTENT)
2972 SendChatMessage(player->peer_id, msg);
2975 bool Server::showFormspec(const char *playername, const std::string &formspec,
2976 const std::string &formname)
2978 // m_env will be NULL if the server is initializing
2982 RemotePlayer *player = m_env->getPlayer(playername);
2986 SendShowFormspecMessage(player->peer_id, formspec, formname);
2990 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
2995 u32 id = player->addHud(form);
2997 SendHUDAdd(player->peer_id, id, form);
3002 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3006 HudElement* todel = player->removeHud(id);
3013 SendHUDRemove(player->peer_id, id);
3017 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3022 SendHUDChange(player->peer_id, id, stat, data);
3026 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3031 SendHUDSetFlags(player->peer_id, flags, mask);
3032 player->hud_flags &= ~mask;
3033 player->hud_flags |= flags;
3035 PlayerSAO* playersao = player->getPlayerSAO();
3037 if (playersao == NULL)
3040 m_script->player_event(playersao, "hud_changed");
3044 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3049 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3052 player->setHotbarItemcount(hotbar_itemcount);
3053 std::ostringstream os(std::ios::binary);
3054 writeS32(os, hotbar_itemcount);
3055 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3059 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3064 player->setHotbarImage(name);
3065 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3068 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3072 return player->getHotbarImage();
3075 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3080 player->setHotbarSelectedImage(name);
3081 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3084 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3085 v2s32 animation_frames[4], f32 frame_speed)
3090 player->setLocalAnimations(animation_frames, frame_speed);
3091 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3095 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3100 player->eye_offset_first = first;
3101 player->eye_offset_third = third;
3102 SendEyeOffset(player->peer_id, first, third);
3106 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3107 const std::string &type, const std::vector<std::string> ¶ms)
3112 player->setSky(bgcolor, type, params);
3113 SendSetSky(player->peer_id, bgcolor, type, params);
3117 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3123 player->overrideDayNightRatio(do_override, ratio);
3124 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3128 void Server::notifyPlayers(const std::wstring &msg)
3130 SendChatMessage(PEER_ID_INEXISTENT,msg);
3133 void Server::spawnParticle(const std::string &playername, v3f pos,
3134 v3f velocity, v3f acceleration,
3135 float expirationtime, float size, bool
3136 collisiondetection, bool collision_removal,
3137 bool vertical, const std::string &texture)
3139 // m_env will be NULL if the server is initializing
3143 u16 peer_id = PEER_ID_INEXISTENT;
3144 if (playername != "") {
3145 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3148 peer_id = player->peer_id;
3151 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3152 expirationtime, size, collisiondetection,
3153 collision_removal, vertical, texture);
3156 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3157 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3158 float minexptime, float maxexptime, float minsize, float maxsize,
3159 bool collisiondetection, bool collision_removal,
3160 ServerActiveObject *attached, bool vertical, const std::string &texture,
3161 const std::string &playername)
3163 // m_env will be NULL if the server is initializing
3167 u16 peer_id = PEER_ID_INEXISTENT;
3168 if (playername != "") {
3169 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3172 peer_id = player->peer_id;
3175 u16 attached_id = attached ? attached->getId() : 0;
3178 if (attached_id == 0)
3179 id = m_env->addParticleSpawner(spawntime);
3181 id = m_env->addParticleSpawner(spawntime, attached_id);
3183 SendAddParticleSpawner(peer_id, amount, spawntime,
3184 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3185 minexptime, maxexptime, minsize, maxsize,
3186 collisiondetection, collision_removal, attached_id, vertical,
3192 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3194 // m_env will be NULL if the server is initializing
3196 throw ServerError("Can't delete particle spawners during initialisation!");
3198 u16 peer_id = PEER_ID_INEXISTENT;
3199 if (playername != "") {
3200 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3203 peer_id = player->peer_id;
3206 m_env->deleteParticleSpawner(id);
3207 SendDeleteParticleSpawner(peer_id, id);
3210 Inventory* Server::createDetachedInventory(const std::string &name)
3212 if(m_detached_inventories.count(name) > 0){
3213 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3214 delete m_detached_inventories[name];
3216 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3218 Inventory *inv = new Inventory(m_itemdef);
3220 m_detached_inventories[name] = inv;
3221 //TODO find a better way to do this
3222 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3226 // actions: time-reversed list
3227 // Return value: success/failure
3228 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3229 std::list<std::string> *log)
3231 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3232 ServerMap *map = (ServerMap*)(&m_env->getMap());
3234 // Fail if no actions to handle
3235 if(actions.empty()){
3236 log->push_back("Nothing to do.");
3243 for(std::list<RollbackAction>::const_iterator
3244 i = actions.begin();
3245 i != actions.end(); ++i)
3247 const RollbackAction &action = *i;
3249 bool success = action.applyRevert(map, this, this);
3252 std::ostringstream os;
3253 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3254 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3256 log->push_back(os.str());
3258 std::ostringstream os;
3259 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3260 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3262 log->push_back(os.str());
3266 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3267 <<" failed"<<std::endl;
3269 // Call it done if less than half failed
3270 return num_failed <= num_tried/2;
3273 // IGameDef interface
3275 IItemDefManager *Server::getItemDefManager()
3280 INodeDefManager *Server::getNodeDefManager()
3285 ICraftDefManager *Server::getCraftDefManager()
3289 ITextureSource *Server::getTextureSource()
3293 IShaderSource *Server::getShaderSource()
3297 scene::ISceneManager *Server::getSceneManager()
3302 u16 Server::allocateUnknownNodeId(const std::string &name)
3304 return m_nodedef->allocateDummy(name);
3307 ISoundManager *Server::getSoundManager()
3309 return &dummySoundManager;
3312 MtEventManager *Server::getEventManager()
3317 IWritableItemDefManager *Server::getWritableItemDefManager()
3322 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3327 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3332 const ModSpec *Server::getModSpec(const std::string &modname) const
3334 std::vector<ModSpec>::const_iterator it;
3335 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3336 const ModSpec &mod = *it;
3337 if (mod.name == modname)
3343 void Server::getModNames(std::vector<std::string> &modlist)
3345 std::vector<ModSpec>::iterator it;
3346 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3347 modlist.push_back(it->name);
3350 std::string Server::getBuiltinLuaPath()
3352 return porting::path_share + DIR_DELIM + "builtin";
3355 v3f Server::findSpawnPos()
3357 ServerMap &map = m_env->getServerMap();
3359 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3360 return nodeposf * BS;
3363 bool is_good = false;
3365 // Try to find a good place a few times
3366 for(s32 i = 0; i < 4000 && !is_good; i++) {
3368 // We're going to try to throw the player to this position
3369 v2s16 nodepos2d = v2s16(
3370 -range + (myrand() % (range * 2)),
3371 -range + (myrand() % (range * 2)));
3373 // Get spawn level at point
3374 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3375 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3376 // the mapgen to signify an unsuitable spawn position
3377 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3380 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3383 for (s32 i = 0; i < 10; i++) {
3384 v3s16 blockpos = getNodeBlockPos(nodepos);
3385 map.emergeBlock(blockpos, true);
3386 content_t c = map.getNodeNoEx(nodepos).getContent();
3387 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3389 if (air_count >= 2) {
3390 nodeposf = intToFloat(nodepos, BS);
3391 // Don't spawn the player outside map boundaries
3392 if (objectpos_over_limit(nodeposf))
3405 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3407 bool newplayer = false;
3410 Try to get an existing player
3412 RemotePlayer *player = m_env->getPlayer(name);
3414 // If player is already connected, cancel
3415 if (player != NULL && player->peer_id != 0) {
3416 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3421 If player with the wanted peer_id already exists, cancel.
3423 if (m_env->getPlayer(peer_id) != NULL) {
3424 infostream<<"emergePlayer(): Player with wrong name but same"
3425 " peer_id already exists"<<std::endl;
3429 // Load player if it isn't already loaded
3431 player = m_env->loadPlayer(name);
3434 // Create player if it doesn't exist
3437 player = new RemotePlayer(name, this->idef());
3438 // Set player position
3439 infostream<<"Server: Finding spawn place for player \""
3440 <<name<<"\""<<std::endl;
3441 v3f pos = findSpawnPos();
3442 player->setPosition(pos);
3444 // Make sure the player is saved
3445 player->setModified(true);
3447 // Add player to environment
3448 m_env->addPlayer(player);
3450 // If the player exists, ensure that they respawn inside legal bounds
3451 // This fixes an assert crash when the player can't be added
3452 // to the environment
3453 if (objectpos_over_limit(player->getPosition())) {
3454 actionstream << "Respawn position for player \""
3455 << name << "\" outside limits, resetting" << std::endl;
3456 v3f pos = findSpawnPos();
3457 player->setPosition(pos);
3461 // Create a new player active object
3462 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3463 getPlayerEffectivePrivs(player->getName()),
3466 player->protocol_version = proto_version;
3468 /* Clean up old HUD elements from previous sessions */
3471 /* Add object to environment */
3472 m_env->addActiveObject(playersao);
3476 m_script->on_newplayer(playersao);
3482 void dedicated_server_loop(Server &server, bool &kill)
3484 DSTACK(FUNCTION_NAME);
3486 verbosestream<<"dedicated_server_loop()"<<std::endl;
3488 IntervalLimiter m_profiler_interval;
3490 static const float steplen = g_settings->getFloat("dedicated_server_step");
3491 static const float profiler_print_interval =
3492 g_settings->getFloat("profiler_print_interval");
3495 // This is kind of a hack but can be done like this
3496 // because server.step() is very light
3498 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3499 sleep_ms((int)(steplen*1000.0));
3501 server.step(steplen);
3503 if(server.getShutdownRequested() || kill)
3505 infostream<<"Dedicated server quitting"<<std::endl;
3507 if(g_settings->getBool("server_announce"))
3508 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3516 if (profiler_print_interval != 0) {
3517 if(m_profiler_interval.step(steplen, profiler_print_interval))
3519 infostream<<"Profiler:"<<std::endl;
3520 g_profiler->print(infostream);
3521 g_profiler->clear();