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,
153 m_path_world(path_world),
154 m_gamespec(gamespec),
155 m_simple_singleplayer_mode(simple_singleplayer_mode),
156 m_async_fatal_error(""),
165 m_enable_rollback_recording(false),
168 m_itemdef(createItemDefManager()),
169 m_nodedef(createNodeDefManager()),
170 m_craftdef(createCraftDefManager()),
171 m_event(new EventManager()),
173 m_time_of_day_send_timer(0),
176 m_shutdown_requested(false),
177 m_shutdown_ask_reconnect(false),
178 m_ignore_map_edit_events(false),
179 m_ignore_map_edit_events_peer_id(0),
183 m_liquid_transform_timer = 0.0;
184 m_liquid_transform_every = 1.0;
185 m_print_info_timer = 0.0;
186 m_masterserver_timer = 0.0;
187 m_objectdata_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 // Load mapgen params from Settings
268 m_emerge->loadMapgenParams();
270 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
271 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
273 // Initialize scripting
274 infostream<<"Server: Initializing Lua"<<std::endl;
276 m_script = new GameScripting(this);
278 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
279 std::string error_msg;
281 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
282 throw ModError("Failed to load and run " + script_path
283 + "\nError from Lua:\n" + error_msg);
286 infostream << "Server: Loading mods: ";
287 for(std::vector<ModSpec>::iterator i = m_mods.begin();
288 i != m_mods.end(); ++i) {
289 const ModSpec &mod = *i;
290 infostream << mod.name << " ";
292 infostream << std::endl;
293 // Load and run "mod" scripts
294 for (std::vector<ModSpec>::iterator i = m_mods.begin();
295 i != m_mods.end(); ++i) {
296 const ModSpec &mod = *i;
297 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
298 std::ostringstream err;
299 err << "Error loading mod \"" << mod.name
300 << "\": mod_name does not follow naming conventions: "
301 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
302 errorstream << err.str().c_str();
303 throw ModError(err.str());
305 std::string script_path = mod.path + DIR_DELIM "init.lua";
306 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
307 << script_path << "\"]" << std::endl;
308 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
309 errorstream << "Server: Failed to load and run "
310 << script_path << std::endl;
311 throw ModError("Failed to load and run " + script_path
312 + "\nError from Lua:\n" + error_msg);
316 // Read Textures and calculate sha1 sums
319 // Apply item aliases in the node definition manager
320 m_nodedef->updateAliases(m_itemdef);
322 // Apply texture overrides from texturepack/override.txt
323 std::string texture_path = g_settings->get("texture_path");
324 if (texture_path != "" && fs::IsDir(texture_path))
325 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
327 m_nodedef->setNodeRegistrationStatus(true);
329 // Perform pending node name resolutions
330 m_nodedef->runNodeResolveCallbacks();
332 // init the recipe hashes to speed up crafting
333 m_craftdef->initHashes(this);
335 // Initialize Environment
336 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
338 m_clients.setEnv(m_env);
340 // Initialize mapgens
341 m_emerge->initMapgens();
343 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
344 if (m_enable_rollback_recording) {
345 // Create rollback manager
346 m_rollback = new RollbackManager(m_path_world, this);
349 // Give environment reference to scripting api
350 m_script->initializeEnvironment(m_env);
352 // Register us to receive map edit events
353 servermap->addEventReceiver(this);
355 // If file exists, load environment metadata
356 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
358 infostream<<"Server: Loading environment metadata"<<std::endl;
362 // Add some test ActiveBlockModifiers to environment
363 add_legacy_abms(m_env, m_nodedef);
365 m_liquid_transform_every = g_settings->getFloat("liquid_update");
370 infostream<<"Server destructing"<<std::endl;
372 // Send shutdown message
373 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
376 MutexAutoLock envlock(m_env_mutex);
378 // Execute script shutdown hooks
379 m_script->on_shutdown();
381 infostream << "Server: Saving players" << std::endl;
382 m_env->saveLoadedPlayers();
384 infostream << "Server: Kicking players" << std::endl;
385 std::string kick_msg;
386 bool reconnect = false;
387 if (getShutdownRequested()) {
388 reconnect = m_shutdown_ask_reconnect;
389 kick_msg = m_shutdown_msg;
391 if (kick_msg == "") {
392 kick_msg = g_settings->get("kick_msg_shutdown");
394 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
395 kick_msg, reconnect);
397 infostream << "Server: Saving environment metadata" << std::endl;
405 // stop all emerge threads before deleting players that may have
406 // requested blocks to be emerged
407 m_emerge->stopThreads();
409 // Delete things in the reverse order of creation
412 // N.B. the EmergeManager should be deleted after the Environment since Map
413 // depends on EmergeManager to write its current params to the map meta
422 // Deinitialize scripting
423 infostream<<"Server: Deinitializing scripting"<<std::endl;
426 // Delete detached inventories
427 for (std::map<std::string, Inventory*>::iterator
428 i = m_detached_inventories.begin();
429 i != m_detached_inventories.end(); ++i) {
434 void Server::start(Address bind_addr)
436 DSTACK(FUNCTION_NAME);
438 m_bind_addr = bind_addr;
440 infostream<<"Starting server on "
441 << bind_addr.serializeString() <<"..."<<std::endl;
443 // Stop thread if already running
446 // Initialize connection
447 m_con.SetTimeoutMs(30);
448 m_con.Serve(bind_addr);
453 // ASCII art for the win!
455 <<" .__ __ __ "<<std::endl
456 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
457 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
458 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
459 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
460 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
461 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
462 actionstream<<"Server for gameid=\""<<m_gamespec.id
463 <<"\" listening on "<<bind_addr.serializeString()<<":"
464 <<bind_addr.getPort() << "."<<std::endl;
469 DSTACK(FUNCTION_NAME);
471 infostream<<"Server: Stopping and waiting threads"<<std::endl;
473 // Stop threads (set run=false first so both start stopping)
475 //m_emergethread.setRun(false);
477 //m_emergethread.stop();
479 infostream<<"Server: Threads stopped"<<std::endl;
482 void Server::step(float dtime)
484 DSTACK(FUNCTION_NAME);
489 MutexAutoLock lock(m_step_dtime_mutex);
490 m_step_dtime += dtime;
492 // Throw if fatal error occurred in thread
493 std::string async_err = m_async_fatal_error.get();
494 if(async_err != "") {
495 if (m_simple_singleplayer_mode) {
496 throw ServerError(async_err);
499 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
500 g_settings->get("kick_msg_crash"),
501 g_settings->getBool("ask_reconnect_on_crash"));
502 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
503 << "Please fix the following error:" << std::endl
504 << async_err << std::endl;
505 FATAL_ERROR(async_err.c_str());
510 void Server::AsyncRunStep(bool initial_step)
512 DSTACK(FUNCTION_NAME);
514 g_profiler->add("Server::AsyncRunStep (num)", 1);
518 MutexAutoLock lock1(m_step_dtime_mutex);
519 dtime = m_step_dtime;
523 // Send blocks to clients
527 if((dtime < 0.001) && (initial_step == false))
530 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
532 //infostream<<"Server steps "<<dtime<<std::endl;
533 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
536 MutexAutoLock lock1(m_step_dtime_mutex);
537 m_step_dtime -= dtime;
544 m_uptime.set(m_uptime.get() + dtime);
550 Update time of day and overall game time
552 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
555 Send to clients at constant intervals
558 m_time_of_day_send_timer -= dtime;
559 if(m_time_of_day_send_timer < 0.0) {
560 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
561 u16 time = m_env->getTimeOfDay();
562 float time_speed = g_settings->getFloat("time_speed");
563 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
567 MutexAutoLock lock(m_env_mutex);
568 // Figure out and report maximum lag to environment
569 float max_lag = m_env->getMaxLagEstimate();
570 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
572 if(dtime > 0.1 && dtime > max_lag * 2.0)
573 infostream<<"Server: Maximum lag peaked to "<<dtime
577 m_env->reportMaxLagEstimate(max_lag);
579 ScopeProfiler sp(g_profiler, "SEnv step");
580 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
584 static const float map_timer_and_unload_dtime = 2.92;
585 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
587 MutexAutoLock lock(m_env_mutex);
588 // Run Map's timers and unload unused data
589 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
590 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
591 g_settings->getFloat("server_unload_unused_data_timeout"),
599 /* Transform liquids */
600 m_liquid_transform_timer += dtime;
601 if(m_liquid_transform_timer >= m_liquid_transform_every)
603 m_liquid_transform_timer -= m_liquid_transform_every;
605 MutexAutoLock lock(m_env_mutex);
607 ScopeProfiler sp(g_profiler, "Server: liquid transform");
609 std::map<v3s16, MapBlock*> modified_blocks;
610 m_env->getMap().transformLiquids(modified_blocks);
615 core::map<v3s16, MapBlock*> lighting_modified_blocks;
616 ServerMap &map = ((ServerMap&)m_env->getMap());
617 map.updateLighting(modified_blocks, lighting_modified_blocks);
619 // Add blocks modified by lighting to modified_blocks
620 for(core::map<v3s16, MapBlock*>::Iterator
621 i = lighting_modified_blocks.getIterator();
622 i.atEnd() == false; i++)
624 MapBlock *block = i.getNode()->getValue();
625 modified_blocks.insert(block->getPos(), block);
629 Set the modified blocks unsent for all the clients
631 if(!modified_blocks.empty())
633 SetBlocksNotSent(modified_blocks);
636 m_clients.step(dtime);
638 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
640 // send masterserver announce
642 float &counter = m_masterserver_timer;
643 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
644 g_settings->getBool("server_announce"))
646 ServerList::sendAnnounce(counter ? "update" : "start",
647 m_bind_addr.getPort(),
648 m_clients.getPlayerNames(),
650 m_env->getGameTime(),
653 m_emerge->params.mg_name,
662 Check added and deleted active objects
665 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
666 MutexAutoLock envlock(m_env_mutex);
669 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
670 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
672 // Radius inside which objects are active
673 s16 radius = g_settings->getS16("active_object_send_range_blocks");
674 s16 player_radius = g_settings->getS16("player_transfer_distance");
676 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
677 !g_settings->getBool("unlimited_player_transfer_distance"))
678 player_radius = radius;
680 radius *= MAP_BLOCKSIZE;
681 player_radius *= MAP_BLOCKSIZE;
683 for (std::map<u16, RemoteClient*>::iterator
685 i != clients.end(); ++i) {
686 RemoteClient *client = i->second;
688 // If definitions and textures have not been sent, don't
689 // send objects either
690 if (client->getState() < CS_DefinitionsSent)
693 Player *player = m_env->getPlayer(client->peer_id);
695 // This can happen if the client timeouts somehow
696 /*warningstream<<FUNCTION_NAME<<": Client "
698 <<" has no associated player"<<std::endl;*/
702 std::queue<u16> removed_objects;
703 std::queue<u16> added_objects;
704 m_env->getRemovedActiveObjects(player, radius, player_radius,
705 client->m_known_objects, removed_objects);
706 m_env->getAddedActiveObjects(player, radius, player_radius,
707 client->m_known_objects, added_objects);
709 // Ignore if nothing happened
710 if (removed_objects.empty() && added_objects.empty()) {
714 std::string data_buffer;
718 // Handle removed objects
719 writeU16((u8*)buf, removed_objects.size());
720 data_buffer.append(buf, 2);
721 while (!removed_objects.empty()) {
723 u16 id = removed_objects.front();
724 ServerActiveObject* obj = m_env->getActiveObject(id);
726 // Add to data buffer for sending
727 writeU16((u8*)buf, id);
728 data_buffer.append(buf, 2);
730 // Remove from known objects
731 client->m_known_objects.erase(id);
733 if(obj && obj->m_known_by_count > 0)
734 obj->m_known_by_count--;
735 removed_objects.pop();
738 // Handle added objects
739 writeU16((u8*)buf, added_objects.size());
740 data_buffer.append(buf, 2);
741 while (!added_objects.empty()) {
743 u16 id = added_objects.front();
744 ServerActiveObject* obj = m_env->getActiveObject(id);
747 u8 type = ACTIVEOBJECT_TYPE_INVALID;
749 warningstream<<FUNCTION_NAME
750 <<": NULL object"<<std::endl;
752 type = obj->getSendType();
754 // Add to data buffer for sending
755 writeU16((u8*)buf, id);
756 data_buffer.append(buf, 2);
757 writeU8((u8*)buf, type);
758 data_buffer.append(buf, 1);
761 data_buffer.append(serializeLongString(
762 obj->getClientInitializationData(client->net_proto_version)));
764 data_buffer.append(serializeLongString(""));
766 // Add to known objects
767 client->m_known_objects.insert(id);
770 obj->m_known_by_count++;
775 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
776 verbosestream << "Server: Sent object remove/add: "
777 << removed_objects.size() << " removed, "
778 << added_objects.size() << " added, "
779 << "packet size is " << pktSize << std::endl;
788 MutexAutoLock envlock(m_env_mutex);
789 ScopeProfiler sp(g_profiler, "Server: sending object messages");
792 // Value = data sent by object
793 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
795 // Get active object messages from environment
797 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
801 std::vector<ActiveObjectMessage>* message_list = NULL;
802 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
803 n = buffered_messages.find(aom.id);
804 if (n == buffered_messages.end()) {
805 message_list = new std::vector<ActiveObjectMessage>;
806 buffered_messages[aom.id] = message_list;
809 message_list = n->second;
811 message_list->push_back(aom);
815 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
816 // Route data to every client
817 for (std::map<u16, RemoteClient*>::iterator
819 i != clients.end(); ++i) {
820 RemoteClient *client = i->second;
821 std::string reliable_data;
822 std::string unreliable_data;
823 // Go through all objects in message buffer
824 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
825 j = buffered_messages.begin();
826 j != buffered_messages.end(); ++j) {
827 // If object is not known by client, skip it
829 if (client->m_known_objects.find(id) == client->m_known_objects.end())
832 // Get message list of object
833 std::vector<ActiveObjectMessage>* list = j->second;
834 // Go through every message
835 for (std::vector<ActiveObjectMessage>::iterator
836 k = list->begin(); k != list->end(); ++k) {
837 // Compose the full new data with header
838 ActiveObjectMessage aom = *k;
839 std::string new_data;
842 writeU16((u8*)&buf[0], aom.id);
843 new_data.append(buf, 2);
845 new_data += serializeString(aom.datastring);
846 // Add data to buffer
848 reliable_data += new_data;
850 unreliable_data += new_data;
854 reliable_data and unreliable_data are now ready.
857 if(reliable_data.size() > 0) {
858 SendActiveObjectMessages(client->peer_id, reliable_data);
861 if(unreliable_data.size() > 0) {
862 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
867 // Clear buffered_messages
868 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
869 i = buffered_messages.begin();
870 i != buffered_messages.end(); ++i) {
876 Send queued-for-sending map edit events.
879 // We will be accessing the environment
880 MutexAutoLock lock(m_env_mutex);
882 // Don't send too many at a time
885 // Single change sending is disabled if queue size is not small
886 bool disable_single_change_sending = false;
887 if(m_unsent_map_edit_queue.size() >= 4)
888 disable_single_change_sending = true;
890 int event_count = m_unsent_map_edit_queue.size();
892 // We'll log the amount of each
895 while(m_unsent_map_edit_queue.size() != 0)
897 MapEditEvent* event = m_unsent_map_edit_queue.front();
898 m_unsent_map_edit_queue.pop();
900 // Players far away from the change are stored here.
901 // Instead of sending the changes, MapBlocks are set not sent
903 std::vector<u16> far_players;
905 switch (event->type) {
908 prof.add("MEET_ADDNODE", 1);
909 sendAddNode(event->p, event->n, event->already_known_by_peer,
910 &far_players, disable_single_change_sending ? 5 : 30,
911 event->type == MEET_ADDNODE);
913 case MEET_REMOVENODE:
914 prof.add("MEET_REMOVENODE", 1);
915 sendRemoveNode(event->p, event->already_known_by_peer,
916 &far_players, disable_single_change_sending ? 5 : 30);
918 case MEET_BLOCK_NODE_METADATA_CHANGED:
919 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
920 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
921 setBlockNotSent(event->p);
924 infostream << "Server: MEET_OTHER" << std::endl;
925 prof.add("MEET_OTHER", 1);
926 for(std::set<v3s16>::iterator
927 i = event->modified_blocks.begin();
928 i != event->modified_blocks.end(); ++i) {
933 prof.add("unknown", 1);
934 warningstream << "Server: Unknown MapEditEvent "
935 << ((u32)event->type) << std::endl;
940 Set blocks not sent to far players
942 if(!far_players.empty()) {
943 // Convert list format to that wanted by SetBlocksNotSent
944 std::map<v3s16, MapBlock*> modified_blocks2;
945 for(std::set<v3s16>::iterator
946 i = event->modified_blocks.begin();
947 i != event->modified_blocks.end(); ++i) {
948 modified_blocks2[*i] =
949 m_env->getMap().getBlockNoCreateNoEx(*i);
952 // Set blocks not sent
953 for(std::vector<u16>::iterator
954 i = far_players.begin();
955 i != far_players.end(); ++i) {
956 if(RemoteClient *client = getClient(*i))
957 client->SetBlocksNotSent(modified_blocks2);
963 /*// Don't send too many at a time
965 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
969 if(event_count >= 5){
970 infostream<<"Server: MapEditEvents:"<<std::endl;
971 prof.print(infostream);
972 } else if(event_count != 0){
973 verbosestream<<"Server: MapEditEvents:"<<std::endl;
974 prof.print(verbosestream);
980 Trigger emergethread (it somehow gets to a non-triggered but
981 bysy state sometimes)
984 float &counter = m_emergethread_trigger_timer;
990 m_emerge->startThreads();
994 // Save map, players and auth stuff
996 float &counter = m_savemap_timer;
998 if(counter >= g_settings->getFloat("server_map_save_interval"))
1001 MutexAutoLock lock(m_env_mutex);
1003 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1006 if (m_banmanager->isModified()) {
1007 m_banmanager->save();
1010 // Save changed parts of map
1011 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1014 m_env->saveLoadedPlayers();
1016 // Save environment metadata
1022 void Server::Receive()
1024 DSTACK(FUNCTION_NAME);
1025 SharedBuffer<u8> data;
1029 m_con.Receive(&pkt);
1030 peer_id = pkt.getPeerId();
1033 catch(con::InvalidIncomingDataException &e) {
1034 infostream<<"Server::Receive(): "
1035 "InvalidIncomingDataException: what()="
1036 <<e.what()<<std::endl;
1038 catch(SerializationError &e) {
1039 infostream<<"Server::Receive(): "
1040 "SerializationError: what()="
1041 <<e.what()<<std::endl;
1043 catch(ClientStateError &e) {
1044 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1045 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1046 L"Try reconnecting or updating your client");
1048 catch(con::PeerNotFoundException &e) {
1053 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1055 std::string playername = "";
1056 PlayerSAO *playersao = NULL;
1059 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1060 if (client != NULL) {
1061 playername = client->getName();
1062 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1064 } catch (std::exception &e) {
1070 RemotePlayer *player =
1071 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1073 // If failed, cancel
1074 if ((playersao == NULL) || (player == NULL)) {
1075 if (player && player->peer_id != 0) {
1076 actionstream << "Server: Failed to emerge player \"" << playername
1077 << "\" (player allocated to an another client)" << std::endl;
1078 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1079 L"name. If your client closed unexpectedly, try again in "
1082 errorstream << "Server: " << playername << ": Failed to emerge player"
1084 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1090 Send complete position information
1092 SendMovePlayer(peer_id);
1095 SendPlayerPrivileges(peer_id);
1097 // Send inventory formspec
1098 SendPlayerInventoryFormspec(peer_id);
1101 SendInventory(playersao);
1104 SendPlayerHPOrDie(playersao);
1107 SendPlayerBreath(peer_id);
1109 // Show death screen if necessary
1110 if(player->isDead())
1111 SendDeathscreen(peer_id, false, v3f(0,0,0));
1113 // Note things in chat if not in simple singleplayer mode
1114 if(!m_simple_singleplayer_mode) {
1115 // Send information about server to player in chat
1116 SendChatMessage(peer_id, getStatusString());
1118 // Send information about joining in chat
1120 std::wstring name = L"unknown";
1121 Player *player = m_env->getPlayer(peer_id);
1123 name = narrow_to_wide(player->getName());
1125 std::wstring message;
1128 message += L" joined the game.";
1129 SendChatMessage(PEER_ID_INEXISTENT,message);
1132 Address addr = getPeerAddress(player->peer_id);
1133 std::string ip_str = addr.serializeString();
1134 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1139 std::vector<std::string> names = m_clients.getPlayerNames();
1141 actionstream<<player->getName() <<" joins game. List of players: ";
1143 for (std::vector<std::string>::iterator i = names.begin();
1144 i != names.end(); ++i) {
1145 actionstream << *i << " ";
1148 actionstream << player->getName() <<std::endl;
1153 inline void Server::handleCommand(NetworkPacket* pkt)
1155 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1156 (this->*opHandle.handler)(pkt);
1159 void Server::ProcessData(NetworkPacket *pkt)
1161 DSTACK(FUNCTION_NAME);
1162 // Environment is locked first.
1163 MutexAutoLock envlock(m_env_mutex);
1165 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1166 u32 peer_id = pkt->getPeerId();
1169 Address address = getPeerAddress(peer_id);
1170 std::string addr_s = address.serializeString();
1172 if(m_banmanager->isIpBanned(addr_s)) {
1173 std::string ban_name = m_banmanager->getBanName(addr_s);
1174 infostream << "Server: A banned client tried to connect from "
1175 << addr_s << "; banned name was "
1176 << ban_name << std::endl;
1177 // This actually doesn't seem to transfer to the client
1178 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1179 + utf8_to_wide(ban_name));
1183 catch(con::PeerNotFoundException &e) {
1185 * no peer for this packet found
1186 * most common reason is peer timeout, e.g. peer didn't
1187 * respond for some time, your server was overloaded or
1190 infostream << "Server::ProcessData(): Canceling: peer "
1191 << peer_id << " not found" << std::endl;
1196 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1198 // Command must be handled into ToServerCommandHandler
1199 if (command >= TOSERVER_NUM_MSG_TYPES) {
1200 infostream << "Server: Ignoring unknown command "
1201 << command << std::endl;
1205 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1210 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1212 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1213 errorstream << "Server::ProcessData(): Cancelling: Peer"
1214 " serialization format invalid or not initialized."
1215 " Skipping incoming command=" << command << std::endl;
1219 /* Handle commands related to client startup */
1220 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1225 if (m_clients.getClientState(peer_id) < CS_Active) {
1226 if (command == TOSERVER_PLAYERPOS) return;
1228 errorstream << "Got packet command: " << command << " for peer id "
1229 << peer_id << " but client isn't active yet. Dropping packet "
1235 } catch (SendFailedException &e) {
1236 errorstream << "Server::ProcessData(): SendFailedException: "
1237 << "what=" << e.what()
1239 } catch (PacketError &e) {
1240 actionstream << "Server::ProcessData(): PacketError: "
1241 << "what=" << e.what()
1246 void Server::setTimeOfDay(u32 time)
1248 m_env->setTimeOfDay(time);
1249 m_time_of_day_send_timer = 0;
1252 u32 Server::getTimeOfDay()
1254 return m_env->getTimeOfDay();
1257 void Server::onMapEditEvent(MapEditEvent *event)
1259 if(m_ignore_map_edit_events)
1261 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1263 MapEditEvent *e = event->clone();
1264 m_unsent_map_edit_queue.push(e);
1267 Inventory* Server::getInventory(const InventoryLocation &loc)
1270 case InventoryLocation::UNDEFINED:
1271 case InventoryLocation::CURRENT_PLAYER:
1273 case InventoryLocation::PLAYER:
1275 Player *player = m_env->getPlayer(loc.name.c_str());
1278 PlayerSAO *playersao = player->getPlayerSAO();
1281 return playersao->getInventory();
1284 case InventoryLocation::NODEMETA:
1286 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1289 return meta->getInventory();
1292 case InventoryLocation::DETACHED:
1294 if(m_detached_inventories.count(loc.name) == 0)
1296 return m_detached_inventories[loc.name];
1300 sanity_check(false); // abort
1305 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1308 case InventoryLocation::UNDEFINED:
1310 case InventoryLocation::PLAYER:
1315 Player *player = m_env->getPlayer(loc.name.c_str());
1318 PlayerSAO *playersao = player->getPlayerSAO();
1322 SendInventory(playersao);
1325 case InventoryLocation::NODEMETA:
1327 v3s16 blockpos = getNodeBlockPos(loc.p);
1329 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1331 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1333 setBlockNotSent(blockpos);
1336 case InventoryLocation::DETACHED:
1338 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1342 sanity_check(false); // abort
1347 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1349 std::vector<u16> clients = m_clients.getClientIDs();
1351 // Set the modified blocks unsent for all the clients
1352 for (std::vector<u16>::iterator i = clients.begin();
1353 i != clients.end(); ++i) {
1354 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1355 client->SetBlocksNotSent(block);
1360 void Server::peerAdded(con::Peer *peer)
1362 DSTACK(FUNCTION_NAME);
1363 verbosestream<<"Server::peerAdded(): peer->id="
1364 <<peer->id<<std::endl;
1367 c.type = con::PEER_ADDED;
1368 c.peer_id = peer->id;
1370 m_peer_change_queue.push(c);
1373 void Server::deletingPeer(con::Peer *peer, bool timeout)
1375 DSTACK(FUNCTION_NAME);
1376 verbosestream<<"Server::deletingPeer(): peer->id="
1377 <<peer->id<<", timeout="<<timeout<<std::endl;
1379 m_clients.event(peer->id, CSE_Disconnect);
1381 c.type = con::PEER_REMOVED;
1382 c.peer_id = peer->id;
1383 c.timeout = timeout;
1384 m_peer_change_queue.push(c);
1387 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1389 *retval = m_con.getPeerStat(peer_id,type);
1390 if (*retval == -1) return false;
1394 bool Server::getClientInfo(
1403 std::string* vers_string
1406 *state = m_clients.getClientState(peer_id);
1408 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1410 if (client == NULL) {
1415 *uptime = client->uptime();
1416 *ser_vers = client->serialization_version;
1417 *prot_vers = client->net_proto_version;
1419 *major = client->getMajor();
1420 *minor = client->getMinor();
1421 *patch = client->getPatch();
1422 *vers_string = client->getPatch();
1429 void Server::handlePeerChanges()
1431 while(m_peer_change_queue.size() > 0)
1433 con::PeerChange c = m_peer_change_queue.front();
1434 m_peer_change_queue.pop();
1436 verbosestream<<"Server: Handling peer change: "
1437 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1442 case con::PEER_ADDED:
1443 m_clients.CreateClient(c.peer_id);
1446 case con::PEER_REMOVED:
1447 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1451 FATAL_ERROR("Invalid peer change event received!");
1457 void Server::Send(NetworkPacket* pkt)
1459 m_clients.send(pkt->getPeerId(),
1460 clientCommandFactoryTable[pkt->getCommand()].channel,
1462 clientCommandFactoryTable[pkt->getCommand()].reliable);
1465 void Server::SendMovement(u16 peer_id)
1467 DSTACK(FUNCTION_NAME);
1468 std::ostringstream os(std::ios_base::binary);
1470 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1472 pkt << g_settings->getFloat("movement_acceleration_default");
1473 pkt << g_settings->getFloat("movement_acceleration_air");
1474 pkt << g_settings->getFloat("movement_acceleration_fast");
1475 pkt << g_settings->getFloat("movement_speed_walk");
1476 pkt << g_settings->getFloat("movement_speed_crouch");
1477 pkt << g_settings->getFloat("movement_speed_fast");
1478 pkt << g_settings->getFloat("movement_speed_climb");
1479 pkt << g_settings->getFloat("movement_speed_jump");
1480 pkt << g_settings->getFloat("movement_liquid_fluidity");
1481 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1482 pkt << g_settings->getFloat("movement_liquid_sink");
1483 pkt << g_settings->getFloat("movement_gravity");
1488 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1490 if (!g_settings->getBool("enable_damage"))
1493 u16 peer_id = playersao->getPeerID();
1494 bool is_alive = playersao->getHP() > 0;
1497 SendPlayerHP(peer_id);
1502 void Server::SendHP(u16 peer_id, u8 hp)
1504 DSTACK(FUNCTION_NAME);
1506 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1511 void Server::SendBreath(u16 peer_id, u16 breath)
1513 DSTACK(FUNCTION_NAME);
1515 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1516 pkt << (u16) breath;
1520 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1521 const std::string &custom_reason, bool reconnect)
1523 assert(reason < SERVER_ACCESSDENIED_MAX);
1525 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1527 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1528 pkt << custom_reason;
1529 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1530 reason == SERVER_ACCESSDENIED_CRASH)
1531 pkt << custom_reason << (u8)reconnect;
1535 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1537 DSTACK(FUNCTION_NAME);
1539 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1544 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1545 v3f camera_point_target)
1547 DSTACK(FUNCTION_NAME);
1549 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1550 pkt << set_camera_point_target << camera_point_target;
1554 void Server::SendItemDef(u16 peer_id,
1555 IItemDefManager *itemdef, u16 protocol_version)
1557 DSTACK(FUNCTION_NAME);
1559 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1563 u32 length of the next item
1564 zlib-compressed serialized ItemDefManager
1566 std::ostringstream tmp_os(std::ios::binary);
1567 itemdef->serialize(tmp_os, protocol_version);
1568 std::ostringstream tmp_os2(std::ios::binary);
1569 compressZlib(tmp_os.str(), tmp_os2);
1570 pkt.putLongString(tmp_os2.str());
1573 verbosestream << "Server: Sending item definitions to id(" << peer_id
1574 << "): size=" << pkt.getSize() << std::endl;
1579 void Server::SendNodeDef(u16 peer_id,
1580 INodeDefManager *nodedef, u16 protocol_version)
1582 DSTACK(FUNCTION_NAME);
1584 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1588 u32 length of the next item
1589 zlib-compressed serialized NodeDefManager
1591 std::ostringstream tmp_os(std::ios::binary);
1592 nodedef->serialize(tmp_os, protocol_version);
1593 std::ostringstream tmp_os2(std::ios::binary);
1594 compressZlib(tmp_os.str(), tmp_os2);
1596 pkt.putLongString(tmp_os2.str());
1599 verbosestream << "Server: Sending node definitions to id(" << peer_id
1600 << "): size=" << pkt.getSize() << std::endl;
1606 Non-static send methods
1609 void Server::SendInventory(PlayerSAO* playerSAO)
1611 DSTACK(FUNCTION_NAME);
1613 UpdateCrafting(playerSAO->getPlayer());
1619 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1621 std::ostringstream os;
1622 playerSAO->getInventory()->serialize(os);
1624 std::string s = os.str();
1626 pkt.putRawString(s.c_str(), s.size());
1630 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1632 DSTACK(FUNCTION_NAME);
1634 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1637 if (peer_id != PEER_ID_INEXISTENT) {
1641 m_clients.sendToAll(0, &pkt, true);
1645 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1646 const std::string &formname)
1648 DSTACK(FUNCTION_NAME);
1650 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1652 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1658 // Spawns a particle on peer with peer_id
1659 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1660 float expirationtime, float size, bool collisiondetection,
1661 bool vertical, std::string texture)
1663 DSTACK(FUNCTION_NAME);
1665 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1667 pkt << pos << velocity << acceleration << expirationtime
1668 << size << collisiondetection;
1669 pkt.putLongString(texture);
1672 if (peer_id != PEER_ID_INEXISTENT) {
1676 m_clients.sendToAll(0, &pkt, true);
1680 // Adds a ParticleSpawner on peer with peer_id
1681 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1682 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1683 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1685 DSTACK(FUNCTION_NAME);
1687 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1689 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1690 << minacc << maxacc << minexptime << maxexptime << minsize
1691 << maxsize << collisiondetection;
1693 pkt.putLongString(texture);
1695 pkt << id << vertical;
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 Player *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 Player *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 Player *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 Player *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
1983 i = clients.begin(); i != clients.end(); ++i) {
1984 Player *player = m_env->getPlayer(*i);
1989 if(player->getPosition().getDistanceFrom(pos) >
1990 params.max_hear_distance)
1993 dst_clients.push_back(*i);
1997 if(dst_clients.empty())
2001 s32 id = m_next_sound_id++;
2002 // The sound will exist as a reference in m_playing_sounds
2003 m_playing_sounds[id] = ServerPlayingSound();
2004 ServerPlayingSound &psound = m_playing_sounds[id];
2005 psound.params = params;
2007 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2008 pkt << id << spec.name << (float) (spec.gain * params.gain)
2009 << (u8) params.type << pos << params.object << params.loop;
2011 for(std::vector<u16>::iterator i = dst_clients.begin();
2012 i != dst_clients.end(); ++i) {
2013 psound.clients.insert(*i);
2014 m_clients.send(*i, 0, &pkt, true);
2018 void Server::stopSound(s32 handle)
2020 // Get sound reference
2021 std::map<s32, ServerPlayingSound>::iterator i =
2022 m_playing_sounds.find(handle);
2023 if(i == m_playing_sounds.end())
2025 ServerPlayingSound &psound = i->second;
2027 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2030 for(std::set<u16>::iterator i = psound.clients.begin();
2031 i != psound.clients.end(); ++i) {
2033 m_clients.send(*i, 0, &pkt, true);
2035 // Remove sound reference
2036 m_playing_sounds.erase(i);
2039 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2040 std::vector<u16> *far_players, float far_d_nodes)
2042 float maxd = far_d_nodes*BS;
2043 v3f p_f = intToFloat(p, BS);
2045 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2048 std::vector<u16> clients = m_clients.getClientIDs();
2049 for(std::vector<u16>::iterator i = clients.begin();
2050 i != clients.end(); ++i) {
2053 if(Player *player = m_env->getPlayer(*i)) {
2054 // If player is far away, only set modified blocks not sent
2055 v3f player_pos = player->getPosition();
2056 if(player_pos.getDistanceFrom(p_f) > maxd) {
2057 far_players->push_back(*i);
2064 m_clients.send(*i, 0, &pkt, true);
2068 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2069 std::vector<u16> *far_players, float far_d_nodes,
2070 bool remove_metadata)
2072 float maxd = far_d_nodes*BS;
2073 v3f p_f = intToFloat(p, BS);
2075 std::vector<u16> clients = m_clients.getClientIDs();
2076 for(std::vector<u16>::iterator i = clients.begin();
2077 i != clients.end(); ++i) {
2081 if(Player *player = m_env->getPlayer(*i)) {
2082 // If player is far away, only set modified blocks not sent
2083 v3f player_pos = player->getPosition();
2084 if(player_pos.getDistanceFrom(p_f) > maxd) {
2085 far_players->push_back(*i);
2091 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2093 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2095 pkt << p << n.param0 << n.param1 << n.param2
2096 << (u8) (remove_metadata ? 0 : 1);
2098 if (!remove_metadata) {
2099 if (client->net_proto_version <= 21) {
2100 // Old clients always clear metadata; fix it
2101 // by sending the full block again.
2102 client->SetBlockNotSent(getNodeBlockPos(p));
2109 if (pkt.getSize() > 0)
2110 m_clients.send(*i, 0, &pkt, true);
2114 void Server::setBlockNotSent(v3s16 p)
2116 std::vector<u16> clients = m_clients.getClientIDs();
2118 for(std::vector<u16>::iterator i = clients.begin();
2119 i != clients.end(); ++i) {
2120 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2121 client->SetBlockNotSent(p);
2126 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2128 DSTACK(FUNCTION_NAME);
2130 v3s16 p = block->getPos();
2133 Create a packet with the block in the right format
2136 std::ostringstream os(std::ios_base::binary);
2137 block->serialize(os, ver, false);
2138 block->serializeNetworkSpecific(os, net_proto_version);
2139 std::string s = os.str();
2141 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2144 pkt.putRawString(s.c_str(), s.size());
2148 void Server::SendBlocks(float dtime)
2150 DSTACK(FUNCTION_NAME);
2152 MutexAutoLock envlock(m_env_mutex);
2153 //TODO check if one big lock could be faster then multiple small ones
2155 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2157 std::vector<PrioritySortedBlockTransfer> queue;
2159 s32 total_sending = 0;
2162 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2164 std::vector<u16> clients = m_clients.getClientIDs();
2167 for(std::vector<u16>::iterator i = clients.begin();
2168 i != clients.end(); ++i) {
2169 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2174 total_sending += client->SendingCount();
2175 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2181 // Lowest priority number comes first.
2182 // Lowest is most important.
2183 std::sort(queue.begin(), queue.end());
2186 for(u32 i=0; i<queue.size(); i++)
2188 //TODO: Calculate limit dynamically
2189 if(total_sending >= g_settings->getS32
2190 ("max_simultaneous_block_sends_server_total"))
2193 PrioritySortedBlockTransfer q = queue[i];
2195 MapBlock *block = NULL;
2198 block = m_env->getMap().getBlockNoCreate(q.pos);
2200 catch(InvalidPositionException &e)
2205 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2210 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2212 client->SentBlock(q.pos);
2218 void Server::fillMediaCache()
2220 DSTACK(FUNCTION_NAME);
2222 infostream<<"Server: Calculating media file checksums"<<std::endl;
2224 // Collect all media file paths
2225 std::vector<std::string> paths;
2226 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2227 i != m_mods.end(); ++i) {
2228 const ModSpec &mod = *i;
2229 paths.push_back(mod.path + DIR_DELIM + "textures");
2230 paths.push_back(mod.path + DIR_DELIM + "sounds");
2231 paths.push_back(mod.path + DIR_DELIM + "media");
2232 paths.push_back(mod.path + DIR_DELIM + "models");
2234 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2236 // Collect media file information from paths into cache
2237 for(std::vector<std::string>::iterator i = paths.begin();
2238 i != paths.end(); ++i) {
2239 std::string mediapath = *i;
2240 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2241 for (u32 j = 0; j < dirlist.size(); j++) {
2242 if (dirlist[j].dir) // Ignode dirs
2244 std::string filename = dirlist[j].name;
2245 // If name contains illegal characters, ignore the file
2246 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2247 infostream<<"Server: ignoring illegal file name: \""
2248 << filename << "\"" << std::endl;
2251 // If name is not in a supported format, ignore it
2252 const char *supported_ext[] = {
2253 ".png", ".jpg", ".bmp", ".tga",
2254 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2256 ".x", ".b3d", ".md2", ".obj",
2259 if (removeStringEnd(filename, supported_ext) == ""){
2260 infostream << "Server: ignoring unsupported file extension: \""
2261 << filename << "\"" << std::endl;
2264 // Ok, attempt to load the file and add to cache
2265 std::string filepath = mediapath + DIR_DELIM + filename;
2267 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2269 errorstream << "Server::fillMediaCache(): Could not open \""
2270 << filename << "\" for reading" << std::endl;
2273 std::ostringstream tmp_os(std::ios_base::binary);
2277 fis.read(buf, 1024);
2278 std::streamsize len = fis.gcount();
2279 tmp_os.write(buf, len);
2288 errorstream<<"Server::fillMediaCache(): Failed to read \""
2289 << filename << "\"" << std::endl;
2292 if(tmp_os.str().length() == 0) {
2293 errorstream << "Server::fillMediaCache(): Empty file \""
2294 << filepath << "\"" << std::endl;
2299 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2301 unsigned char *digest = sha1.getDigest();
2302 std::string sha1_base64 = base64_encode(digest, 20);
2303 std::string sha1_hex = hex_encode((char*)digest, 20);
2307 m_media[filename] = MediaInfo(filepath, sha1_base64);
2308 verbosestream << "Server: " << sha1_hex << " is " << filename
2314 void Server::sendMediaAnnouncement(u16 peer_id)
2316 DSTACK(FUNCTION_NAME);
2318 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2322 std::ostringstream os(std::ios_base::binary);
2324 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2325 pkt << (u16) m_media.size();
2327 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2328 i != m_media.end(); ++i) {
2329 pkt << i->first << i->second.sha1_digest;
2332 pkt << g_settings->get("remote_media");
2336 struct SendableMedia
2342 SendableMedia(const std::string &name_="", const std::string &path_="",
2343 const std::string &data_=""):
2350 void Server::sendRequestedMedia(u16 peer_id,
2351 const std::vector<std::string> &tosend)
2353 DSTACK(FUNCTION_NAME);
2355 verbosestream<<"Server::sendRequestedMedia(): "
2356 <<"Sending files to client"<<std::endl;
2360 // Put 5kB in one bunch (this is not accurate)
2361 u32 bytes_per_bunch = 5000;
2363 std::vector< std::vector<SendableMedia> > file_bunches;
2364 file_bunches.push_back(std::vector<SendableMedia>());
2366 u32 file_size_bunch_total = 0;
2368 for(std::vector<std::string>::const_iterator i = tosend.begin();
2369 i != tosend.end(); ++i) {
2370 const std::string &name = *i;
2372 if(m_media.find(name) == m_media.end()) {
2373 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2374 <<"unknown file \""<<(name)<<"\""<<std::endl;
2378 //TODO get path + name
2379 std::string tpath = m_media[name].path;
2382 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2383 if(fis.good() == false){
2384 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2385 <<tpath<<"\" for reading"<<std::endl;
2388 std::ostringstream tmp_os(std::ios_base::binary);
2392 fis.read(buf, 1024);
2393 std::streamsize len = fis.gcount();
2394 tmp_os.write(buf, len);
2395 file_size_bunch_total += len;
2404 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2405 <<name<<"\""<<std::endl;
2408 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2409 <<tname<<"\""<<std::endl;*/
2411 file_bunches[file_bunches.size()-1].push_back(
2412 SendableMedia(name, tpath, tmp_os.str()));
2414 // Start next bunch if got enough data
2415 if(file_size_bunch_total >= bytes_per_bunch) {
2416 file_bunches.push_back(std::vector<SendableMedia>());
2417 file_size_bunch_total = 0;
2422 /* Create and send packets */
2424 u16 num_bunches = file_bunches.size();
2425 for(u16 i = 0; i < num_bunches; i++) {
2428 u16 total number of texture bunches
2429 u16 index of this bunch
2430 u32 number of files in this bunch
2439 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2440 pkt << num_bunches << i << (u32) file_bunches[i].size();
2442 for(std::vector<SendableMedia>::iterator
2443 j = file_bunches[i].begin();
2444 j != file_bunches[i].end(); ++j) {
2446 pkt.putLongString(j->data);
2449 verbosestream << "Server::sendRequestedMedia(): bunch "
2450 << i << "/" << num_bunches
2451 << " files=" << file_bunches[i].size()
2452 << " size=" << pkt.getSize() << std::endl;
2457 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2459 if(m_detached_inventories.count(name) == 0) {
2460 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2463 Inventory *inv = m_detached_inventories[name];
2464 std::ostringstream os(std::ios_base::binary);
2466 os << serializeString(name);
2470 std::string s = os.str();
2472 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2473 pkt.putRawString(s.c_str(), s.size());
2475 if (peer_id != PEER_ID_INEXISTENT) {
2479 m_clients.sendToAll(0, &pkt, true);
2483 void Server::sendDetachedInventories(u16 peer_id)
2485 DSTACK(FUNCTION_NAME);
2487 for(std::map<std::string, Inventory*>::iterator
2488 i = m_detached_inventories.begin();
2489 i != m_detached_inventories.end(); ++i) {
2490 const std::string &name = i->first;
2491 //Inventory *inv = i->second;
2492 sendDetachedInventory(name, peer_id);
2500 void Server::DiePlayer(u16 peer_id)
2502 DSTACK(FUNCTION_NAME);
2504 PlayerSAO *playersao = getPlayerSAO(peer_id);
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);
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 // Collect information about leaving in chat
2647 if(player != NULL && reason != CDR_DENY)
2649 std::wstring name = narrow_to_wide(player->getName());
2652 message += L" left the game.";
2653 if(reason == CDR_TIMEOUT)
2654 message += L" (timed out)";
2658 /* Run scripts and remove from environment */
2662 PlayerSAO *playersao = player->getPlayerSAO();
2665 m_script->on_leaveplayer(playersao);
2667 playersao->disconnected();
2675 if(player != NULL && reason != CDR_DENY) {
2676 std::ostringstream os(std::ios_base::binary);
2677 std::vector<u16> clients = m_clients.getClientIDs();
2679 for(std::vector<u16>::iterator i = clients.begin();
2680 i != clients.end(); ++i) {
2682 Player *player = m_env->getPlayer(*i);
2686 // Get name of player
2687 os << player->getName() << " ";
2690 actionstream << player->getName() << " "
2691 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2692 << " List of players: " << os.str() << std::endl;
2696 MutexAutoLock env_lock(m_env_mutex);
2697 m_clients.DeleteClient(peer_id);
2701 // Send leave chat message to all remaining clients
2702 if(message.length() != 0)
2703 SendChatMessage(PEER_ID_INEXISTENT,message);
2706 void Server::UpdateCrafting(Player* player)
2708 DSTACK(FUNCTION_NAME);
2710 // Get a preview for crafting
2712 InventoryLocation loc;
2713 loc.setPlayer(player->getName());
2714 std::vector<ItemStack> output_replacements;
2715 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2716 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2718 // Put the new preview in
2719 InventoryList *plist = player->inventory.getList("craftpreview");
2720 sanity_check(plist);
2721 sanity_check(plist->getSize() >= 1);
2722 plist->changeItem(0, preview);
2725 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2727 RemoteClient *client = getClientNoEx(peer_id,state_min);
2729 throw ClientNotFoundException("Client not found");
2733 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2735 return m_clients.getClientNoEx(peer_id, state_min);
2738 std::string Server::getPlayerName(u16 peer_id)
2740 Player *player = m_env->getPlayer(peer_id);
2742 return "[id="+itos(peer_id)+"]";
2743 return player->getName();
2746 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2748 Player *player = m_env->getPlayer(peer_id);
2751 return player->getPlayerSAO();
2754 std::wstring Server::getStatusString()
2756 std::wostringstream os(std::ios_base::binary);
2759 os<<L"version="<<narrow_to_wide(g_version_string);
2761 os<<L", uptime="<<m_uptime.get();
2763 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2764 // Information about clients
2767 std::vector<u16> clients = m_clients.getClientIDs();
2768 for(std::vector<u16>::iterator i = clients.begin();
2769 i != clients.end(); ++i) {
2771 Player *player = m_env->getPlayer(*i);
2772 // Get name of player
2773 std::wstring name = L"unknown";
2775 name = narrow_to_wide(player->getName());
2776 // Add name to information string
2784 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2785 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2786 if(g_settings->get("motd") != "")
2787 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2791 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2793 std::set<std::string> privs;
2794 m_script->getAuth(name, NULL, &privs);
2798 bool Server::checkPriv(const std::string &name, const std::string &priv)
2800 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2801 return (privs.count(priv) != 0);
2804 void Server::reportPrivsModified(const std::string &name)
2807 std::vector<u16> clients = m_clients.getClientIDs();
2808 for(std::vector<u16>::iterator i = clients.begin();
2809 i != clients.end(); ++i) {
2810 Player *player = m_env->getPlayer(*i);
2811 reportPrivsModified(player->getName());
2814 Player *player = m_env->getPlayer(name.c_str());
2817 SendPlayerPrivileges(player->peer_id);
2818 PlayerSAO *sao = player->getPlayerSAO();
2821 sao->updatePrivileges(
2822 getPlayerEffectivePrivs(name),
2827 void Server::reportInventoryFormspecModified(const std::string &name)
2829 Player *player = m_env->getPlayer(name.c_str());
2832 SendPlayerInventoryFormspec(player->peer_id);
2835 void Server::setIpBanned(const std::string &ip, const std::string &name)
2837 m_banmanager->add(ip, name);
2840 void Server::unsetIpBanned(const std::string &ip_or_name)
2842 m_banmanager->remove(ip_or_name);
2845 std::string Server::getBanDescription(const std::string &ip_or_name)
2847 return m_banmanager->getBanDescription(ip_or_name);
2850 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2852 // m_env will be NULL if the server is initializing
2856 Player *player = m_env->getPlayer(name);
2860 if (player->peer_id == PEER_ID_INEXISTENT)
2863 SendChatMessage(player->peer_id, msg);
2866 bool Server::showFormspec(const char *playername, const std::string &formspec,
2867 const std::string &formname)
2869 // m_env will be NULL if the server is initializing
2873 Player *player = m_env->getPlayer(playername);
2877 SendShowFormspecMessage(player->peer_id, formspec, formname);
2881 u32 Server::hudAdd(Player *player, HudElement *form)
2886 u32 id = player->addHud(form);
2888 SendHUDAdd(player->peer_id, id, form);
2893 bool Server::hudRemove(Player *player, u32 id) {
2897 HudElement* todel = player->removeHud(id);
2904 SendHUDRemove(player->peer_id, id);
2908 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2913 SendHUDChange(player->peer_id, id, stat, data);
2917 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2922 SendHUDSetFlags(player->peer_id, flags, mask);
2923 player->hud_flags = flags;
2925 PlayerSAO* playersao = player->getPlayerSAO();
2927 if (playersao == NULL)
2930 m_script->player_event(playersao, "hud_changed");
2934 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2938 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2941 player->setHotbarItemcount(hotbar_itemcount);
2942 std::ostringstream os(std::ios::binary);
2943 writeS32(os, hotbar_itemcount);
2944 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2948 s32 Server::hudGetHotbarItemcount(Player *player)
2952 return player->getHotbarItemcount();
2955 void Server::hudSetHotbarImage(Player *player, std::string name)
2960 player->setHotbarImage(name);
2961 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2964 std::string Server::hudGetHotbarImage(Player *player)
2968 return player->getHotbarImage();
2971 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2976 player->setHotbarSelectedImage(name);
2977 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2980 std::string Server::hudGetHotbarSelectedImage(Player *player)
2985 return player->getHotbarSelectedImage();
2988 bool Server::setLocalPlayerAnimations(Player *player,
2989 v2s32 animation_frames[4], f32 frame_speed)
2994 player->setLocalAnimations(animation_frames, frame_speed);
2995 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2999 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3004 player->eye_offset_first = first;
3005 player->eye_offset_third = third;
3006 SendEyeOffset(player->peer_id, first, third);
3010 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3011 const std::string &type, const std::vector<std::string> ¶ms)
3016 player->setSky(bgcolor, type, params);
3017 SendSetSky(player->peer_id, bgcolor, type, params);
3021 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3027 player->overrideDayNightRatio(do_override, ratio);
3028 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3032 void Server::notifyPlayers(const std::wstring &msg)
3034 SendChatMessage(PEER_ID_INEXISTENT,msg);
3037 void Server::spawnParticle(const std::string &playername, v3f pos,
3038 v3f velocity, v3f acceleration,
3039 float expirationtime, float size, bool
3040 collisiondetection, bool vertical, const std::string &texture)
3042 // m_env will be NULL if the server is initializing
3046 u16 peer_id = PEER_ID_INEXISTENT;
3047 if (playername != "") {
3048 Player* player = m_env->getPlayer(playername.c_str());
3051 peer_id = player->peer_id;
3054 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3055 expirationtime, size, collisiondetection, vertical, texture);
3058 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3059 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3060 float minexptime, float maxexptime, float minsize, float maxsize,
3061 bool collisiondetection, bool vertical, const std::string &texture,
3062 const std::string &playername)
3064 // m_env will be NULL if the server is initializing
3068 u16 peer_id = PEER_ID_INEXISTENT;
3069 if (playername != "") {
3070 Player* player = m_env->getPlayer(playername.c_str());
3073 peer_id = player->peer_id;
3077 for(;;) // look for unused particlespawner id
3080 if (std::find(m_particlespawner_ids.begin(),
3081 m_particlespawner_ids.end(), id)
3082 == m_particlespawner_ids.end())
3084 m_particlespawner_ids.push_back(id);
3089 SendAddParticleSpawner(peer_id, amount, spawntime,
3090 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3091 minexptime, maxexptime, minsize, maxsize,
3092 collisiondetection, vertical, texture, id);
3097 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3099 // m_env will be NULL if the server is initializing
3101 throw ServerError("Can't delete particle spawners during initialisation!");
3103 u16 peer_id = PEER_ID_INEXISTENT;
3104 if (playername != "") {
3105 Player* player = m_env->getPlayer(playername.c_str());
3108 peer_id = player->peer_id;
3111 m_particlespawner_ids.erase(
3112 std::remove(m_particlespawner_ids.begin(),
3113 m_particlespawner_ids.end(), id),
3114 m_particlespawner_ids.end());
3115 SendDeleteParticleSpawner(peer_id, id);
3118 Inventory* Server::createDetachedInventory(const std::string &name)
3120 if(m_detached_inventories.count(name) > 0){
3121 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3122 delete m_detached_inventories[name];
3124 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3126 Inventory *inv = new Inventory(m_itemdef);
3128 m_detached_inventories[name] = inv;
3129 //TODO find a better way to do this
3130 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3134 // actions: time-reversed list
3135 // Return value: success/failure
3136 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3137 std::list<std::string> *log)
3139 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3140 ServerMap *map = (ServerMap*)(&m_env->getMap());
3142 // Fail if no actions to handle
3143 if(actions.empty()){
3144 log->push_back("Nothing to do.");
3151 for(std::list<RollbackAction>::const_iterator
3152 i = actions.begin();
3153 i != actions.end(); ++i)
3155 const RollbackAction &action = *i;
3157 bool success = action.applyRevert(map, this, this);
3160 std::ostringstream os;
3161 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3162 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3164 log->push_back(os.str());
3166 std::ostringstream os;
3167 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3168 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3170 log->push_back(os.str());
3174 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3175 <<" failed"<<std::endl;
3177 // Call it done if less than half failed
3178 return num_failed <= num_tried/2;
3181 // IGameDef interface
3183 IItemDefManager *Server::getItemDefManager()
3188 INodeDefManager *Server::getNodeDefManager()
3193 ICraftDefManager *Server::getCraftDefManager()
3197 ITextureSource *Server::getTextureSource()
3201 IShaderSource *Server::getShaderSource()
3205 scene::ISceneManager *Server::getSceneManager()
3210 u16 Server::allocateUnknownNodeId(const std::string &name)
3212 return m_nodedef->allocateDummy(name);
3215 ISoundManager *Server::getSoundManager()
3217 return &dummySoundManager;
3220 MtEventManager *Server::getEventManager()
3225 IWritableItemDefManager *Server::getWritableItemDefManager()
3230 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3235 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3240 const ModSpec *Server::getModSpec(const std::string &modname) const
3242 std::vector<ModSpec>::const_iterator it;
3243 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3244 const ModSpec &mod = *it;
3245 if (mod.name == modname)
3251 void Server::getModNames(std::vector<std::string> &modlist)
3253 std::vector<ModSpec>::iterator it;
3254 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3255 modlist.push_back(it->name);
3258 std::string Server::getBuiltinLuaPath()
3260 return porting::path_share + DIR_DELIM + "builtin";
3263 v3f Server::findSpawnPos()
3265 ServerMap &map = m_env->getServerMap();
3267 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3268 return nodeposf * BS;
3271 s16 water_level = map.getWaterLevel();
3273 bool is_good = false;
3275 // Try to find a good place a few times
3276 for(s32 i = 0; i < 1000 && !is_good; i++) {
3278 // We're going to try to throw the player to this position
3279 v2s16 nodepos2d = v2s16(
3280 -range + (myrand() % (range * 2)),
3281 -range + (myrand() % (range * 2)));
3283 // Get ground height at point
3284 s16 groundheight = map.findGroundLevel(nodepos2d);
3285 if (groundheight <= water_level) // Don't go underwater
3287 if (groundheight > water_level + 6) // Don't go to high places
3290 v3s16 nodepos(nodepos2d.X, groundheight, nodepos2d.Y);
3293 for (s32 i = 0; i < 10; i++) {
3294 v3s16 blockpos = getNodeBlockPos(nodepos);
3295 map.emergeBlock(blockpos, true);
3296 content_t c = map.getNodeNoEx(nodepos).getContent();
3297 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3299 if (air_count >= 2) {
3300 nodeposf = intToFloat(nodepos, BS);
3301 // Don't spawn the player outside map boundaries
3302 if (objectpos_over_limit(nodeposf))
3315 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3317 bool newplayer = false;
3320 Try to get an existing player
3322 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3324 // If player is already connected, cancel
3325 if(player != NULL && player->peer_id != 0)
3327 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3332 If player with the wanted peer_id already exists, cancel.
3334 if(m_env->getPlayer(peer_id) != NULL)
3336 infostream<<"emergePlayer(): Player with wrong name but same"
3337 " peer_id already exists"<<std::endl;
3341 // Load player if it isn't already loaded
3343 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3346 // Create player if it doesn't exist
3349 player = new RemotePlayer(this, name);
3350 // Set player position
3351 infostream<<"Server: Finding spawn place for player \""
3352 <<name<<"\""<<std::endl;
3353 v3f pos = findSpawnPos();
3354 player->setPosition(pos);
3356 // Make sure the player is saved
3357 player->setModified(true);
3359 // Add player to environment
3360 m_env->addPlayer(player);
3362 // If the player exists, ensure that they respawn inside legal bounds
3363 // This fixes an assert crash when the player can't be added
3364 // to the environment
3365 if (objectpos_over_limit(player->getPosition())) {
3366 actionstream << "Respawn position for player \""
3367 << name << "\" outside limits, resetting" << std::endl;
3368 v3f pos = findSpawnPos();
3369 player->setPosition(pos);
3373 // Create a new player active object
3374 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3375 getPlayerEffectivePrivs(player->getName()),
3378 player->protocol_version = proto_version;
3380 /* Clean up old HUD elements from previous sessions */
3383 /* Add object to environment */
3384 m_env->addActiveObject(playersao);
3388 m_script->on_newplayer(playersao);
3394 void dedicated_server_loop(Server &server, bool &kill)
3396 DSTACK(FUNCTION_NAME);
3398 verbosestream<<"dedicated_server_loop()"<<std::endl;
3400 IntervalLimiter m_profiler_interval;
3404 float steplen = g_settings->getFloat("dedicated_server_step");
3405 // This is kind of a hack but can be done like this
3406 // because server.step() is very light
3408 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3409 sleep_ms((int)(steplen*1000.0));
3411 server.step(steplen);
3413 if(server.getShutdownRequested() || kill)
3415 infostream<<"Dedicated server quitting"<<std::endl;
3417 if(g_settings->getBool("server_announce"))
3418 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3426 float profiler_print_interval =
3427 g_settings->getFloat("profiler_print_interval");
3428 if(profiler_print_interval != 0)
3430 if(m_profiler_interval.step(steplen, profiler_print_interval))
3432 infostream<<"Profiler:"<<std::endl;
3433 g_profiler->print(infostream);
3434 g_profiler->clear();