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