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 void Server::onMapEditEvent(MapEditEvent *event)
1254 if(m_ignore_map_edit_events)
1256 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1258 MapEditEvent *e = event->clone();
1259 m_unsent_map_edit_queue.push(e);
1262 Inventory* Server::getInventory(const InventoryLocation &loc)
1265 case InventoryLocation::UNDEFINED:
1266 case InventoryLocation::CURRENT_PLAYER:
1268 case InventoryLocation::PLAYER:
1270 Player *player = m_env->getPlayer(loc.name.c_str());
1273 PlayerSAO *playersao = player->getPlayerSAO();
1276 return playersao->getInventory();
1279 case InventoryLocation::NODEMETA:
1281 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1284 return meta->getInventory();
1287 case InventoryLocation::DETACHED:
1289 if(m_detached_inventories.count(loc.name) == 0)
1291 return m_detached_inventories[loc.name];
1295 sanity_check(false); // abort
1300 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1303 case InventoryLocation::UNDEFINED:
1305 case InventoryLocation::PLAYER:
1310 Player *player = m_env->getPlayer(loc.name.c_str());
1313 PlayerSAO *playersao = player->getPlayerSAO();
1317 SendInventory(playersao);
1320 case InventoryLocation::NODEMETA:
1322 v3s16 blockpos = getNodeBlockPos(loc.p);
1324 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1326 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1328 setBlockNotSent(blockpos);
1331 case InventoryLocation::DETACHED:
1333 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1337 sanity_check(false); // abort
1342 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1344 std::vector<u16> clients = m_clients.getClientIDs();
1346 // Set the modified blocks unsent for all the clients
1347 for (std::vector<u16>::iterator i = clients.begin();
1348 i != clients.end(); ++i) {
1349 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1350 client->SetBlocksNotSent(block);
1355 void Server::peerAdded(con::Peer *peer)
1357 DSTACK(FUNCTION_NAME);
1358 verbosestream<<"Server::peerAdded(): peer->id="
1359 <<peer->id<<std::endl;
1362 c.type = con::PEER_ADDED;
1363 c.peer_id = peer->id;
1365 m_peer_change_queue.push(c);
1368 void Server::deletingPeer(con::Peer *peer, bool timeout)
1370 DSTACK(FUNCTION_NAME);
1371 verbosestream<<"Server::deletingPeer(): peer->id="
1372 <<peer->id<<", timeout="<<timeout<<std::endl;
1374 m_clients.event(peer->id, CSE_Disconnect);
1376 c.type = con::PEER_REMOVED;
1377 c.peer_id = peer->id;
1378 c.timeout = timeout;
1379 m_peer_change_queue.push(c);
1382 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1384 *retval = m_con.getPeerStat(peer_id,type);
1385 if (*retval == -1) return false;
1389 bool Server::getClientInfo(
1398 std::string* vers_string
1401 *state = m_clients.getClientState(peer_id);
1403 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1405 if (client == NULL) {
1410 *uptime = client->uptime();
1411 *ser_vers = client->serialization_version;
1412 *prot_vers = client->net_proto_version;
1414 *major = client->getMajor();
1415 *minor = client->getMinor();
1416 *patch = client->getPatch();
1417 *vers_string = client->getPatch();
1424 void Server::handlePeerChanges()
1426 while(m_peer_change_queue.size() > 0)
1428 con::PeerChange c = m_peer_change_queue.front();
1429 m_peer_change_queue.pop();
1431 verbosestream<<"Server: Handling peer change: "
1432 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1437 case con::PEER_ADDED:
1438 m_clients.CreateClient(c.peer_id);
1441 case con::PEER_REMOVED:
1442 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1446 FATAL_ERROR("Invalid peer change event received!");
1452 void Server::Send(NetworkPacket* pkt)
1454 m_clients.send(pkt->getPeerId(),
1455 clientCommandFactoryTable[pkt->getCommand()].channel,
1457 clientCommandFactoryTable[pkt->getCommand()].reliable);
1460 void Server::SendMovement(u16 peer_id)
1462 DSTACK(FUNCTION_NAME);
1463 std::ostringstream os(std::ios_base::binary);
1465 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1467 pkt << g_settings->getFloat("movement_acceleration_default");
1468 pkt << g_settings->getFloat("movement_acceleration_air");
1469 pkt << g_settings->getFloat("movement_acceleration_fast");
1470 pkt << g_settings->getFloat("movement_speed_walk");
1471 pkt << g_settings->getFloat("movement_speed_crouch");
1472 pkt << g_settings->getFloat("movement_speed_fast");
1473 pkt << g_settings->getFloat("movement_speed_climb");
1474 pkt << g_settings->getFloat("movement_speed_jump");
1475 pkt << g_settings->getFloat("movement_liquid_fluidity");
1476 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1477 pkt << g_settings->getFloat("movement_liquid_sink");
1478 pkt << g_settings->getFloat("movement_gravity");
1483 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1485 if (!g_settings->getBool("enable_damage"))
1488 u16 peer_id = playersao->getPeerID();
1489 bool is_alive = playersao->getHP() > 0;
1492 SendPlayerHP(peer_id);
1497 void Server::SendHP(u16 peer_id, u8 hp)
1499 DSTACK(FUNCTION_NAME);
1501 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1506 void Server::SendBreath(u16 peer_id, u16 breath)
1508 DSTACK(FUNCTION_NAME);
1510 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1511 pkt << (u16) breath;
1515 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1516 const std::string &custom_reason, bool reconnect)
1518 assert(reason < SERVER_ACCESSDENIED_MAX);
1520 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1522 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1523 pkt << custom_reason;
1524 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1525 reason == SERVER_ACCESSDENIED_CRASH)
1526 pkt << custom_reason << (u8)reconnect;
1530 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1532 DSTACK(FUNCTION_NAME);
1534 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1539 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1540 v3f camera_point_target)
1542 DSTACK(FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1545 pkt << set_camera_point_target << camera_point_target;
1549 void Server::SendItemDef(u16 peer_id,
1550 IItemDefManager *itemdef, u16 protocol_version)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1558 u32 length of the next item
1559 zlib-compressed serialized ItemDefManager
1561 std::ostringstream tmp_os(std::ios::binary);
1562 itemdef->serialize(tmp_os, protocol_version);
1563 std::ostringstream tmp_os2(std::ios::binary);
1564 compressZlib(tmp_os.str(), tmp_os2);
1565 pkt.putLongString(tmp_os2.str());
1568 verbosestream << "Server: Sending item definitions to id(" << peer_id
1569 << "): size=" << pkt.getSize() << std::endl;
1574 void Server::SendNodeDef(u16 peer_id,
1575 INodeDefManager *nodedef, u16 protocol_version)
1577 DSTACK(FUNCTION_NAME);
1579 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1583 u32 length of the next item
1584 zlib-compressed serialized NodeDefManager
1586 std::ostringstream tmp_os(std::ios::binary);
1587 nodedef->serialize(tmp_os, protocol_version);
1588 std::ostringstream tmp_os2(std::ios::binary);
1589 compressZlib(tmp_os.str(), tmp_os2);
1591 pkt.putLongString(tmp_os2.str());
1594 verbosestream << "Server: Sending node definitions to id(" << peer_id
1595 << "): size=" << pkt.getSize() << std::endl;
1601 Non-static send methods
1604 void Server::SendInventory(PlayerSAO* playerSAO)
1606 DSTACK(FUNCTION_NAME);
1608 UpdateCrafting(playerSAO->getPlayer());
1614 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1616 std::ostringstream os;
1617 playerSAO->getInventory()->serialize(os);
1619 std::string s = os.str();
1621 pkt.putRawString(s.c_str(), s.size());
1625 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1627 DSTACK(FUNCTION_NAME);
1629 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1632 if (peer_id != PEER_ID_INEXISTENT) {
1636 m_clients.sendToAll(0, &pkt, true);
1640 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1641 const std::string &formname)
1643 DSTACK(FUNCTION_NAME);
1645 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1647 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1653 // Spawns a particle on peer with peer_id
1654 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1655 float expirationtime, float size, bool collisiondetection,
1656 bool vertical, 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);
1667 if (peer_id != PEER_ID_INEXISTENT) {
1671 m_clients.sendToAll(0, &pkt, true);
1675 // Adds a ParticleSpawner on peer with peer_id
1676 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1677 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1678 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1680 DSTACK(FUNCTION_NAME);
1682 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1684 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1685 << minacc << maxacc << minexptime << maxexptime << minsize
1686 << maxsize << collisiondetection;
1688 pkt.putLongString(texture);
1690 pkt << id << vertical;
1692 if (peer_id != PEER_ID_INEXISTENT) {
1696 m_clients.sendToAll(0, &pkt, true);
1700 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1702 DSTACK(FUNCTION_NAME);
1704 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1706 // Ugly error in this packet
1709 if (peer_id != PEER_ID_INEXISTENT) {
1713 m_clients.sendToAll(0, &pkt, true);
1718 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1720 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1722 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1723 << form->text << form->number << form->item << form->dir
1724 << form->align << form->offset << form->world_pos << form->size;
1729 void Server::SendHUDRemove(u16 peer_id, u32 id)
1731 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1736 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1738 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1739 pkt << id << (u8) stat;
1743 case HUD_STAT_SCALE:
1744 case HUD_STAT_ALIGN:
1745 case HUD_STAT_OFFSET:
1746 pkt << *(v2f *) value;
1750 pkt << *(std::string *) value;
1752 case HUD_STAT_WORLD_POS:
1753 pkt << *(v3f *) value;
1756 pkt << *(v2s32 *) value;
1758 case HUD_STAT_NUMBER:
1762 pkt << *(u32 *) value;
1769 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1771 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1773 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1775 pkt << flags << mask;
1780 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1782 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1783 pkt << param << value;
1787 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1788 const std::string &type, const std::vector<std::string> ¶ms)
1790 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1791 pkt << bgcolor << type << (u16) params.size();
1793 for(size_t i=0; i<params.size(); i++)
1799 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1802 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1805 pkt << do_override << (u16) (ratio * 65535);
1810 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1812 DSTACK(FUNCTION_NAME);
1814 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1815 pkt << time << time_speed;
1817 if (peer_id == PEER_ID_INEXISTENT) {
1818 m_clients.sendToAll(0, &pkt, true);
1825 void Server::SendPlayerHP(u16 peer_id)
1827 DSTACK(FUNCTION_NAME);
1828 PlayerSAO *playersao = getPlayerSAO(peer_id);
1829 // In some rare case, if the player is disconnected
1830 // while Lua call l_punch, for example, this can be NULL
1834 SendHP(peer_id, playersao->getHP());
1835 m_script->player_event(playersao,"health_changed");
1837 // Send to other clients
1838 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1839 ActiveObjectMessage aom(playersao->getId(), true, str);
1840 playersao->m_messages_out.push(aom);
1843 void Server::SendPlayerBreath(u16 peer_id)
1845 DSTACK(FUNCTION_NAME);
1846 PlayerSAO *playersao = getPlayerSAO(peer_id);
1849 m_script->player_event(playersao, "breath_changed");
1850 SendBreath(peer_id, playersao->getBreath());
1853 void Server::SendMovePlayer(u16 peer_id)
1855 DSTACK(FUNCTION_NAME);
1856 Player *player = m_env->getPlayer(peer_id);
1859 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1860 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1863 v3f pos = player->getPosition();
1864 f32 pitch = player->getPitch();
1865 f32 yaw = player->getYaw();
1866 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1867 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1868 << " pitch=" << pitch
1876 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1878 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1881 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1882 << animation_frames[3] << animation_speed;
1887 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1889 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1890 pkt << first << third;
1893 void Server::SendPlayerPrivileges(u16 peer_id)
1895 Player *player = m_env->getPlayer(peer_id);
1897 if(player->peer_id == PEER_ID_INEXISTENT)
1900 std::set<std::string> privs;
1901 m_script->getAuth(player->getName(), NULL, &privs);
1903 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1904 pkt << (u16) privs.size();
1906 for(std::set<std::string>::const_iterator i = privs.begin();
1907 i != privs.end(); ++i) {
1914 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1916 Player *player = m_env->getPlayer(peer_id);
1918 if(player->peer_id == PEER_ID_INEXISTENT)
1921 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1922 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1926 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1928 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1929 pkt.putRawString(datas.c_str(), datas.size());
1931 return pkt.getSize();
1934 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1936 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1937 datas.size(), peer_id);
1939 pkt.putRawString(datas.c_str(), datas.size());
1941 m_clients.send(pkt.getPeerId(),
1942 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1947 s32 Server::playSound(const SimpleSoundSpec &spec,
1948 const ServerSoundParams ¶ms)
1950 // Find out initial position of sound
1951 bool pos_exists = false;
1952 v3f pos = params.getPos(m_env, &pos_exists);
1953 // If position is not found while it should be, cancel sound
1954 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1957 // Filter destination clients
1958 std::vector<u16> dst_clients;
1959 if(params.to_player != "")
1961 Player *player = m_env->getPlayer(params.to_player.c_str());
1963 infostream<<"Server::playSound: Player \""<<params.to_player
1964 <<"\" not found"<<std::endl;
1967 if(player->peer_id == PEER_ID_INEXISTENT){
1968 infostream<<"Server::playSound: Player \""<<params.to_player
1969 <<"\" not connected"<<std::endl;
1972 dst_clients.push_back(player->peer_id);
1975 std::vector<u16> clients = m_clients.getClientIDs();
1977 for(std::vector<u16>::iterator
1978 i = clients.begin(); i != clients.end(); ++i) {
1979 Player *player = m_env->getPlayer(*i);
1984 if(player->getPosition().getDistanceFrom(pos) >
1985 params.max_hear_distance)
1988 dst_clients.push_back(*i);
1992 if(dst_clients.empty())
1996 s32 id = m_next_sound_id++;
1997 // The sound will exist as a reference in m_playing_sounds
1998 m_playing_sounds[id] = ServerPlayingSound();
1999 ServerPlayingSound &psound = m_playing_sounds[id];
2000 psound.params = params;
2002 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2003 pkt << id << spec.name << (float) (spec.gain * params.gain)
2004 << (u8) params.type << pos << params.object << params.loop;
2006 for(std::vector<u16>::iterator i = dst_clients.begin();
2007 i != dst_clients.end(); ++i) {
2008 psound.clients.insert(*i);
2009 m_clients.send(*i, 0, &pkt, true);
2013 void Server::stopSound(s32 handle)
2015 // Get sound reference
2016 std::map<s32, ServerPlayingSound>::iterator i =
2017 m_playing_sounds.find(handle);
2018 if(i == m_playing_sounds.end())
2020 ServerPlayingSound &psound = i->second;
2022 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2025 for(std::set<u16>::iterator i = psound.clients.begin();
2026 i != psound.clients.end(); ++i) {
2028 m_clients.send(*i, 0, &pkt, true);
2030 // Remove sound reference
2031 m_playing_sounds.erase(i);
2034 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2035 std::vector<u16> *far_players, float far_d_nodes)
2037 float maxd = far_d_nodes*BS;
2038 v3f p_f = intToFloat(p, BS);
2040 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2043 std::vector<u16> clients = m_clients.getClientIDs();
2044 for(std::vector<u16>::iterator i = clients.begin();
2045 i != clients.end(); ++i) {
2048 if(Player *player = m_env->getPlayer(*i)) {
2049 // If player is far away, only set modified blocks not sent
2050 v3f player_pos = player->getPosition();
2051 if(player_pos.getDistanceFrom(p_f) > maxd) {
2052 far_players->push_back(*i);
2059 m_clients.send(*i, 0, &pkt, true);
2063 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2064 std::vector<u16> *far_players, float far_d_nodes,
2065 bool remove_metadata)
2067 float maxd = far_d_nodes*BS;
2068 v3f p_f = intToFloat(p, BS);
2070 std::vector<u16> clients = m_clients.getClientIDs();
2071 for(std::vector<u16>::iterator i = clients.begin();
2072 i != clients.end(); ++i) {
2076 if(Player *player = m_env->getPlayer(*i)) {
2077 // If player is far away, only set modified blocks not sent
2078 v3f player_pos = player->getPosition();
2079 if(player_pos.getDistanceFrom(p_f) > maxd) {
2080 far_players->push_back(*i);
2086 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2088 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2090 pkt << p << n.param0 << n.param1 << n.param2
2091 << (u8) (remove_metadata ? 0 : 1);
2093 if (!remove_metadata) {
2094 if (client->net_proto_version <= 21) {
2095 // Old clients always clear metadata; fix it
2096 // by sending the full block again.
2097 client->SetBlockNotSent(getNodeBlockPos(p));
2104 if (pkt.getSize() > 0)
2105 m_clients.send(*i, 0, &pkt, true);
2109 void Server::setBlockNotSent(v3s16 p)
2111 std::vector<u16> clients = m_clients.getClientIDs();
2113 for(std::vector<u16>::iterator i = clients.begin();
2114 i != clients.end(); ++i) {
2115 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2116 client->SetBlockNotSent(p);
2121 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2123 DSTACK(FUNCTION_NAME);
2125 v3s16 p = block->getPos();
2128 Create a packet with the block in the right format
2131 std::ostringstream os(std::ios_base::binary);
2132 block->serialize(os, ver, false);
2133 block->serializeNetworkSpecific(os, net_proto_version);
2134 std::string s = os.str();
2136 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2139 pkt.putRawString(s.c_str(), s.size());
2143 void Server::SendBlocks(float dtime)
2145 DSTACK(FUNCTION_NAME);
2147 MutexAutoLock envlock(m_env_mutex);
2148 //TODO check if one big lock could be faster then multiple small ones
2150 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2152 std::vector<PrioritySortedBlockTransfer> queue;
2154 s32 total_sending = 0;
2157 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2159 std::vector<u16> clients = m_clients.getClientIDs();
2162 for(std::vector<u16>::iterator i = clients.begin();
2163 i != clients.end(); ++i) {
2164 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2169 total_sending += client->SendingCount();
2170 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2176 // Lowest priority number comes first.
2177 // Lowest is most important.
2178 std::sort(queue.begin(), queue.end());
2181 for(u32 i=0; i<queue.size(); i++)
2183 //TODO: Calculate limit dynamically
2184 if(total_sending >= g_settings->getS32
2185 ("max_simultaneous_block_sends_server_total"))
2188 PrioritySortedBlockTransfer q = queue[i];
2190 MapBlock *block = NULL;
2193 block = m_env->getMap().getBlockNoCreate(q.pos);
2195 catch(InvalidPositionException &e)
2200 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2205 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2207 client->SentBlock(q.pos);
2213 void Server::fillMediaCache()
2215 DSTACK(FUNCTION_NAME);
2217 infostream<<"Server: Calculating media file checksums"<<std::endl;
2219 // Collect all media file paths
2220 std::vector<std::string> paths;
2221 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2222 i != m_mods.end(); ++i) {
2223 const ModSpec &mod = *i;
2224 paths.push_back(mod.path + DIR_DELIM + "textures");
2225 paths.push_back(mod.path + DIR_DELIM + "sounds");
2226 paths.push_back(mod.path + DIR_DELIM + "media");
2227 paths.push_back(mod.path + DIR_DELIM + "models");
2229 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2231 // Collect media file information from paths into cache
2232 for(std::vector<std::string>::iterator i = paths.begin();
2233 i != paths.end(); ++i) {
2234 std::string mediapath = *i;
2235 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2236 for (u32 j = 0; j < dirlist.size(); j++) {
2237 if (dirlist[j].dir) // Ignode dirs
2239 std::string filename = dirlist[j].name;
2240 // If name contains illegal characters, ignore the file
2241 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2242 infostream<<"Server: ignoring illegal file name: \""
2243 << filename << "\"" << std::endl;
2246 // If name is not in a supported format, ignore it
2247 const char *supported_ext[] = {
2248 ".png", ".jpg", ".bmp", ".tga",
2249 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2251 ".x", ".b3d", ".md2", ".obj",
2254 if (removeStringEnd(filename, supported_ext) == ""){
2255 infostream << "Server: ignoring unsupported file extension: \""
2256 << filename << "\"" << std::endl;
2259 // Ok, attempt to load the file and add to cache
2260 std::string filepath = mediapath + DIR_DELIM + filename;
2262 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2264 errorstream << "Server::fillMediaCache(): Could not open \""
2265 << filename << "\" for reading" << std::endl;
2268 std::ostringstream tmp_os(std::ios_base::binary);
2272 fis.read(buf, 1024);
2273 std::streamsize len = fis.gcount();
2274 tmp_os.write(buf, len);
2283 errorstream<<"Server::fillMediaCache(): Failed to read \""
2284 << filename << "\"" << std::endl;
2287 if(tmp_os.str().length() == 0) {
2288 errorstream << "Server::fillMediaCache(): Empty file \""
2289 << filepath << "\"" << std::endl;
2294 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2296 unsigned char *digest = sha1.getDigest();
2297 std::string sha1_base64 = base64_encode(digest, 20);
2298 std::string sha1_hex = hex_encode((char*)digest, 20);
2302 m_media[filename] = MediaInfo(filepath, sha1_base64);
2303 verbosestream << "Server: " << sha1_hex << " is " << filename
2309 void Server::sendMediaAnnouncement(u16 peer_id)
2311 DSTACK(FUNCTION_NAME);
2313 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2317 std::ostringstream os(std::ios_base::binary);
2319 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2320 pkt << (u16) m_media.size();
2322 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2323 i != m_media.end(); ++i) {
2324 pkt << i->first << i->second.sha1_digest;
2327 pkt << g_settings->get("remote_media");
2331 struct SendableMedia
2337 SendableMedia(const std::string &name_="", const std::string &path_="",
2338 const std::string &data_=""):
2345 void Server::sendRequestedMedia(u16 peer_id,
2346 const std::vector<std::string> &tosend)
2348 DSTACK(FUNCTION_NAME);
2350 verbosestream<<"Server::sendRequestedMedia(): "
2351 <<"Sending files to client"<<std::endl;
2355 // Put 5kB in one bunch (this is not accurate)
2356 u32 bytes_per_bunch = 5000;
2358 std::vector< std::vector<SendableMedia> > file_bunches;
2359 file_bunches.push_back(std::vector<SendableMedia>());
2361 u32 file_size_bunch_total = 0;
2363 for(std::vector<std::string>::const_iterator i = tosend.begin();
2364 i != tosend.end(); ++i) {
2365 const std::string &name = *i;
2367 if(m_media.find(name) == m_media.end()) {
2368 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2369 <<"unknown file \""<<(name)<<"\""<<std::endl;
2373 //TODO get path + name
2374 std::string tpath = m_media[name].path;
2377 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2378 if(fis.good() == false){
2379 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2380 <<tpath<<"\" for reading"<<std::endl;
2383 std::ostringstream tmp_os(std::ios_base::binary);
2387 fis.read(buf, 1024);
2388 std::streamsize len = fis.gcount();
2389 tmp_os.write(buf, len);
2390 file_size_bunch_total += len;
2399 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2400 <<name<<"\""<<std::endl;
2403 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2404 <<tname<<"\""<<std::endl;*/
2406 file_bunches[file_bunches.size()-1].push_back(
2407 SendableMedia(name, tpath, tmp_os.str()));
2409 // Start next bunch if got enough data
2410 if(file_size_bunch_total >= bytes_per_bunch) {
2411 file_bunches.push_back(std::vector<SendableMedia>());
2412 file_size_bunch_total = 0;
2417 /* Create and send packets */
2419 u16 num_bunches = file_bunches.size();
2420 for(u16 i = 0; i < num_bunches; i++) {
2423 u16 total number of texture bunches
2424 u16 index of this bunch
2425 u32 number of files in this bunch
2434 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2435 pkt << num_bunches << i << (u32) file_bunches[i].size();
2437 for(std::vector<SendableMedia>::iterator
2438 j = file_bunches[i].begin();
2439 j != file_bunches[i].end(); ++j) {
2441 pkt.putLongString(j->data);
2444 verbosestream << "Server::sendRequestedMedia(): bunch "
2445 << i << "/" << num_bunches
2446 << " files=" << file_bunches[i].size()
2447 << " size=" << pkt.getSize() << std::endl;
2452 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2454 if(m_detached_inventories.count(name) == 0) {
2455 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2458 Inventory *inv = m_detached_inventories[name];
2459 std::ostringstream os(std::ios_base::binary);
2461 os << serializeString(name);
2465 std::string s = os.str();
2467 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2468 pkt.putRawString(s.c_str(), s.size());
2470 if (peer_id != PEER_ID_INEXISTENT) {
2474 m_clients.sendToAll(0, &pkt, true);
2478 void Server::sendDetachedInventories(u16 peer_id)
2480 DSTACK(FUNCTION_NAME);
2482 for(std::map<std::string, Inventory*>::iterator
2483 i = m_detached_inventories.begin();
2484 i != m_detached_inventories.end(); ++i) {
2485 const std::string &name = i->first;
2486 //Inventory *inv = i->second;
2487 sendDetachedInventory(name, peer_id);
2495 void Server::DiePlayer(u16 peer_id)
2497 DSTACK(FUNCTION_NAME);
2499 PlayerSAO *playersao = getPlayerSAO(peer_id);
2502 infostream << "Server::DiePlayer(): Player "
2503 << playersao->getPlayer()->getName()
2504 << " dies" << std::endl;
2506 playersao->setHP(0);
2508 // Trigger scripted stuff
2509 m_script->on_dieplayer(playersao);
2511 SendPlayerHP(peer_id);
2512 SendDeathscreen(peer_id, false, v3f(0,0,0));
2515 void Server::RespawnPlayer(u16 peer_id)
2517 DSTACK(FUNCTION_NAME);
2519 PlayerSAO *playersao = getPlayerSAO(peer_id);
2522 infostream << "Server::RespawnPlayer(): Player "
2523 << playersao->getPlayer()->getName()
2524 << " respawns" << std::endl;
2526 playersao->setHP(PLAYER_MAX_HP);
2527 playersao->setBreath(PLAYER_MAX_BREATH);
2529 SendPlayerHP(peer_id);
2530 SendPlayerBreath(peer_id);
2532 bool repositioned = m_script->on_respawnplayer(playersao);
2534 v3f pos = findSpawnPos();
2535 // setPos will send the new position to client
2536 playersao->setPos(pos);
2541 void Server::DenySudoAccess(u16 peer_id)
2543 DSTACK(FUNCTION_NAME);
2545 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2550 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2551 const std::string &str_reason, bool reconnect)
2553 if (proto_ver >= 25) {
2554 SendAccessDenied(peer_id, reason, str_reason);
2556 std::wstring wreason = utf8_to_wide(
2557 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2558 accessDeniedStrings[(u8)reason]);
2559 SendAccessDenied_Legacy(peer_id, wreason);
2562 m_clients.event(peer_id, CSE_SetDenied);
2563 m_con.DisconnectPeer(peer_id);
2567 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2569 DSTACK(FUNCTION_NAME);
2571 SendAccessDenied(peer_id, reason, custom_reason);
2572 m_clients.event(peer_id, CSE_SetDenied);
2573 m_con.DisconnectPeer(peer_id);
2576 // 13/03/15: remove this function when protocol version 25 will become
2577 // the minimum version for MT users, maybe in 1 year
2578 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2580 DSTACK(FUNCTION_NAME);
2582 SendAccessDenied_Legacy(peer_id, reason);
2583 m_clients.event(peer_id, CSE_SetDenied);
2584 m_con.DisconnectPeer(peer_id);
2587 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2589 DSTACK(FUNCTION_NAME);
2592 RemoteClient* client = getClient(peer_id, CS_Invalid);
2594 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2596 // Right now, the auth mechs don't change between login and sudo mode.
2597 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2598 client->allowed_sudo_mechs = sudo_auth_mechs;
2600 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2601 << g_settings->getFloat("dedicated_server_step")
2605 m_clients.event(peer_id, CSE_AuthAccept);
2607 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2609 // We only support SRP right now
2610 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2612 resp_pkt << sudo_auth_mechs;
2614 m_clients.event(peer_id, CSE_SudoSuccess);
2618 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2620 DSTACK(FUNCTION_NAME);
2621 std::wstring message;
2624 Clear references to playing sounds
2626 for(std::map<s32, ServerPlayingSound>::iterator
2627 i = m_playing_sounds.begin();
2628 i != m_playing_sounds.end();)
2630 ServerPlayingSound &psound = i->second;
2631 psound.clients.erase(peer_id);
2632 if(psound.clients.empty())
2633 m_playing_sounds.erase(i++);
2638 Player *player = m_env->getPlayer(peer_id);
2640 // Collect information about leaving in chat
2642 if(player != NULL && reason != CDR_DENY)
2644 std::wstring name = narrow_to_wide(player->getName());
2647 message += L" left the game.";
2648 if(reason == CDR_TIMEOUT)
2649 message += L" (timed out)";
2653 /* Run scripts and remove from environment */
2657 PlayerSAO *playersao = player->getPlayerSAO();
2660 m_script->on_leaveplayer(playersao);
2662 playersao->disconnected();
2670 if(player != NULL && reason != CDR_DENY) {
2671 std::ostringstream os(std::ios_base::binary);
2672 std::vector<u16> clients = m_clients.getClientIDs();
2674 for(std::vector<u16>::iterator i = clients.begin();
2675 i != clients.end(); ++i) {
2677 Player *player = m_env->getPlayer(*i);
2681 // Get name of player
2682 os << player->getName() << " ";
2685 actionstream << player->getName() << " "
2686 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2687 << " List of players: " << os.str() << std::endl;
2691 MutexAutoLock env_lock(m_env_mutex);
2692 m_clients.DeleteClient(peer_id);
2696 // Send leave chat message to all remaining clients
2697 if(message.length() != 0)
2698 SendChatMessage(PEER_ID_INEXISTENT,message);
2701 void Server::UpdateCrafting(Player* player)
2703 DSTACK(FUNCTION_NAME);
2705 // Get a preview for crafting
2707 InventoryLocation loc;
2708 loc.setPlayer(player->getName());
2709 std::vector<ItemStack> output_replacements;
2710 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2711 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2713 // Put the new preview in
2714 InventoryList *plist = player->inventory.getList("craftpreview");
2715 sanity_check(plist);
2716 sanity_check(plist->getSize() >= 1);
2717 plist->changeItem(0, preview);
2720 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2722 RemoteClient *client = getClientNoEx(peer_id,state_min);
2724 throw ClientNotFoundException("Client not found");
2728 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2730 return m_clients.getClientNoEx(peer_id, state_min);
2733 std::string Server::getPlayerName(u16 peer_id)
2735 Player *player = m_env->getPlayer(peer_id);
2737 return "[id="+itos(peer_id)+"]";
2738 return player->getName();
2741 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2743 Player *player = m_env->getPlayer(peer_id);
2746 return player->getPlayerSAO();
2749 std::wstring Server::getStatusString()
2751 std::wostringstream os(std::ios_base::binary);
2754 os<<L"version="<<narrow_to_wide(g_version_string);
2756 os<<L", uptime="<<m_uptime.get();
2758 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2759 // Information about clients
2762 std::vector<u16> clients = m_clients.getClientIDs();
2763 for(std::vector<u16>::iterator i = clients.begin();
2764 i != clients.end(); ++i) {
2766 Player *player = m_env->getPlayer(*i);
2767 // Get name of player
2768 std::wstring name = L"unknown";
2770 name = narrow_to_wide(player->getName());
2771 // Add name to information string
2779 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2780 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2781 if(g_settings->get("motd") != "")
2782 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2786 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2788 std::set<std::string> privs;
2789 m_script->getAuth(name, NULL, &privs);
2793 bool Server::checkPriv(const std::string &name, const std::string &priv)
2795 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2796 return (privs.count(priv) != 0);
2799 void Server::reportPrivsModified(const std::string &name)
2802 std::vector<u16> clients = m_clients.getClientIDs();
2803 for(std::vector<u16>::iterator i = clients.begin();
2804 i != clients.end(); ++i) {
2805 Player *player = m_env->getPlayer(*i);
2806 reportPrivsModified(player->getName());
2809 Player *player = m_env->getPlayer(name.c_str());
2812 SendPlayerPrivileges(player->peer_id);
2813 PlayerSAO *sao = player->getPlayerSAO();
2816 sao->updatePrivileges(
2817 getPlayerEffectivePrivs(name),
2822 void Server::reportInventoryFormspecModified(const std::string &name)
2824 Player *player = m_env->getPlayer(name.c_str());
2827 SendPlayerInventoryFormspec(player->peer_id);
2830 void Server::setIpBanned(const std::string &ip, const std::string &name)
2832 m_banmanager->add(ip, name);
2835 void Server::unsetIpBanned(const std::string &ip_or_name)
2837 m_banmanager->remove(ip_or_name);
2840 std::string Server::getBanDescription(const std::string &ip_or_name)
2842 return m_banmanager->getBanDescription(ip_or_name);
2845 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2847 // m_env will be NULL if the server is initializing
2851 Player *player = m_env->getPlayer(name);
2855 if (player->peer_id == PEER_ID_INEXISTENT)
2858 SendChatMessage(player->peer_id, msg);
2861 bool Server::showFormspec(const char *playername, const std::string &formspec,
2862 const std::string &formname)
2864 // m_env will be NULL if the server is initializing
2868 Player *player = m_env->getPlayer(playername);
2872 SendShowFormspecMessage(player->peer_id, formspec, formname);
2876 u32 Server::hudAdd(Player *player, HudElement *form)
2881 u32 id = player->addHud(form);
2883 SendHUDAdd(player->peer_id, id, form);
2888 bool Server::hudRemove(Player *player, u32 id) {
2892 HudElement* todel = player->removeHud(id);
2899 SendHUDRemove(player->peer_id, id);
2903 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2908 SendHUDChange(player->peer_id, id, stat, data);
2912 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2917 SendHUDSetFlags(player->peer_id, flags, mask);
2918 player->hud_flags = flags;
2920 PlayerSAO* playersao = player->getPlayerSAO();
2922 if (playersao == NULL)
2925 m_script->player_event(playersao, "hud_changed");
2929 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2933 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2936 player->setHotbarItemcount(hotbar_itemcount);
2937 std::ostringstream os(std::ios::binary);
2938 writeS32(os, hotbar_itemcount);
2939 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2943 s32 Server::hudGetHotbarItemcount(Player *player)
2947 return player->getHotbarItemcount();
2950 void Server::hudSetHotbarImage(Player *player, std::string name)
2955 player->setHotbarImage(name);
2956 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2959 std::string Server::hudGetHotbarImage(Player *player)
2963 return player->getHotbarImage();
2966 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2971 player->setHotbarSelectedImage(name);
2972 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2975 std::string Server::hudGetHotbarSelectedImage(Player *player)
2980 return player->getHotbarSelectedImage();
2983 bool Server::setLocalPlayerAnimations(Player *player,
2984 v2s32 animation_frames[4], f32 frame_speed)
2989 player->setLocalAnimations(animation_frames, frame_speed);
2990 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2994 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2999 player->eye_offset_first = first;
3000 player->eye_offset_third = third;
3001 SendEyeOffset(player->peer_id, first, third);
3005 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3006 const std::string &type, const std::vector<std::string> ¶ms)
3011 player->setSky(bgcolor, type, params);
3012 SendSetSky(player->peer_id, bgcolor, type, params);
3016 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3022 player->overrideDayNightRatio(do_override, ratio);
3023 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3027 void Server::notifyPlayers(const std::wstring &msg)
3029 SendChatMessage(PEER_ID_INEXISTENT,msg);
3032 void Server::spawnParticle(const std::string &playername, v3f pos,
3033 v3f velocity, v3f acceleration,
3034 float expirationtime, float size, bool
3035 collisiondetection, bool vertical, const std::string &texture)
3037 // m_env will be NULL if the server is initializing
3041 u16 peer_id = PEER_ID_INEXISTENT;
3042 if (playername != "") {
3043 Player* player = m_env->getPlayer(playername.c_str());
3046 peer_id = player->peer_id;
3049 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3050 expirationtime, size, collisiondetection, vertical, texture);
3053 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3054 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3055 float minexptime, float maxexptime, float minsize, float maxsize,
3056 bool collisiondetection, bool vertical, const std::string &texture,
3057 const std::string &playername)
3059 // m_env will be NULL if the server is initializing
3063 u16 peer_id = PEER_ID_INEXISTENT;
3064 if (playername != "") {
3065 Player* player = m_env->getPlayer(playername.c_str());
3068 peer_id = player->peer_id;
3072 for(;;) // look for unused particlespawner id
3075 if (std::find(m_particlespawner_ids.begin(),
3076 m_particlespawner_ids.end(), id)
3077 == m_particlespawner_ids.end())
3079 m_particlespawner_ids.push_back(id);
3084 SendAddParticleSpawner(peer_id, amount, spawntime,
3085 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3086 minexptime, maxexptime, minsize, maxsize,
3087 collisiondetection, vertical, texture, id);
3092 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3094 // m_env will be NULL if the server is initializing
3096 throw ServerError("Can't delete particle spawners during initialisation!");
3098 u16 peer_id = PEER_ID_INEXISTENT;
3099 if (playername != "") {
3100 Player* player = m_env->getPlayer(playername.c_str());
3103 peer_id = player->peer_id;
3106 m_particlespawner_ids.erase(
3107 std::remove(m_particlespawner_ids.begin(),
3108 m_particlespawner_ids.end(), id),
3109 m_particlespawner_ids.end());
3110 SendDeleteParticleSpawner(peer_id, id);
3113 Inventory* Server::createDetachedInventory(const std::string &name)
3115 if(m_detached_inventories.count(name) > 0){
3116 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3117 delete m_detached_inventories[name];
3119 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3121 Inventory *inv = new Inventory(m_itemdef);
3123 m_detached_inventories[name] = inv;
3124 //TODO find a better way to do this
3125 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3129 // actions: time-reversed list
3130 // Return value: success/failure
3131 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3132 std::list<std::string> *log)
3134 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3135 ServerMap *map = (ServerMap*)(&m_env->getMap());
3137 // Fail if no actions to handle
3138 if(actions.empty()){
3139 log->push_back("Nothing to do.");
3146 for(std::list<RollbackAction>::const_iterator
3147 i = actions.begin();
3148 i != actions.end(); ++i)
3150 const RollbackAction &action = *i;
3152 bool success = action.applyRevert(map, this, this);
3155 std::ostringstream os;
3156 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3157 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3159 log->push_back(os.str());
3161 std::ostringstream os;
3162 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3163 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3165 log->push_back(os.str());
3169 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3170 <<" failed"<<std::endl;
3172 // Call it done if less than half failed
3173 return num_failed <= num_tried/2;
3176 // IGameDef interface
3178 IItemDefManager *Server::getItemDefManager()
3183 INodeDefManager *Server::getNodeDefManager()
3188 ICraftDefManager *Server::getCraftDefManager()
3192 ITextureSource *Server::getTextureSource()
3196 IShaderSource *Server::getShaderSource()
3200 scene::ISceneManager *Server::getSceneManager()
3205 u16 Server::allocateUnknownNodeId(const std::string &name)
3207 return m_nodedef->allocateDummy(name);
3210 ISoundManager *Server::getSoundManager()
3212 return &dummySoundManager;
3215 MtEventManager *Server::getEventManager()
3220 IWritableItemDefManager *Server::getWritableItemDefManager()
3225 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3230 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3235 const ModSpec *Server::getModSpec(const std::string &modname) const
3237 std::vector<ModSpec>::const_iterator it;
3238 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3239 const ModSpec &mod = *it;
3240 if (mod.name == modname)
3246 void Server::getModNames(std::vector<std::string> &modlist)
3248 std::vector<ModSpec>::iterator it;
3249 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3250 modlist.push_back(it->name);
3253 std::string Server::getBuiltinLuaPath()
3255 return porting::path_share + DIR_DELIM + "builtin";
3258 v3f Server::findSpawnPos()
3260 ServerMap &map = m_env->getServerMap();
3262 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3263 return nodeposf * BS;
3266 s16 water_level = map.getWaterLevel();
3268 bool is_good = false;
3270 // Try to find a good place a few times
3271 for(s32 i = 0; i < 1000 && !is_good; i++) {
3273 // We're going to try to throw the player to this position
3274 v2s16 nodepos2d = v2s16(
3275 -range + (myrand() % (range * 2)),
3276 -range + (myrand() % (range * 2)));
3278 // Get ground height at point
3279 s16 groundheight = map.findGroundLevel(nodepos2d);
3280 if (groundheight <= water_level) // Don't go underwater
3282 if (groundheight > water_level + 6) // Don't go to high places
3285 v3s16 nodepos(nodepos2d.X, groundheight, nodepos2d.Y);
3288 for (s32 i = 0; i < 10; i++) {
3289 v3s16 blockpos = getNodeBlockPos(nodepos);
3290 map.emergeBlock(blockpos, true);
3291 content_t c = map.getNodeNoEx(nodepos).getContent();
3292 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3294 if (air_count >= 2) {
3295 nodeposf = intToFloat(nodepos, BS);
3296 // Don't spawn the player outside map boundaries
3297 if (objectpos_over_limit(nodeposf))
3310 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3312 bool newplayer = false;
3315 Try to get an existing player
3317 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3319 // If player is already connected, cancel
3320 if(player != NULL && player->peer_id != 0)
3322 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3327 If player with the wanted peer_id already exists, cancel.
3329 if(m_env->getPlayer(peer_id) != NULL)
3331 infostream<<"emergePlayer(): Player with wrong name but same"
3332 " peer_id already exists"<<std::endl;
3336 // Load player if it isn't already loaded
3338 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3341 // Create player if it doesn't exist
3344 player = new RemotePlayer(this, name);
3345 // Set player position
3346 infostream<<"Server: Finding spawn place for player \""
3347 <<name<<"\""<<std::endl;
3348 v3f pos = findSpawnPos();
3349 player->setPosition(pos);
3351 // Make sure the player is saved
3352 player->setModified(true);
3354 // Add player to environment
3355 m_env->addPlayer(player);
3357 // If the player exists, ensure that they respawn inside legal bounds
3358 // This fixes an assert crash when the player can't be added
3359 // to the environment
3360 if (objectpos_over_limit(player->getPosition())) {
3361 actionstream << "Respawn position for player \""
3362 << name << "\" outside limits, resetting" << std::endl;
3363 v3f pos = findSpawnPos();
3364 player->setPosition(pos);
3368 // Create a new player active object
3369 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3370 getPlayerEffectivePrivs(player->getName()),
3373 player->protocol_version = proto_version;
3375 /* Clean up old HUD elements from previous sessions */
3378 /* Add object to environment */
3379 m_env->addActiveObject(playersao);
3383 m_script->on_newplayer(playersao);
3389 void dedicated_server_loop(Server &server, bool &kill)
3391 DSTACK(FUNCTION_NAME);
3393 verbosestream<<"dedicated_server_loop()"<<std::endl;
3395 IntervalLimiter m_profiler_interval;
3399 float steplen = g_settings->getFloat("dedicated_server_step");
3400 // This is kind of a hack but can be done like this
3401 // because server.step() is very light
3403 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3404 sleep_ms((int)(steplen*1000.0));
3406 server.step(steplen);
3408 if(server.getShutdownRequested() || kill)
3410 infostream<<"Dedicated server quitting"<<std::endl;
3412 if(g_settings->getBool("server_announce"))
3413 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3421 float profiler_print_interval =
3422 g_settings->getFloat("profiler_print_interval");
3423 if(profiler_print_interval != 0)
3425 if(m_profiler_interval.step(steplen, profiler_print_interval))
3427 infostream<<"Profiler:"<<std::endl;
3428 g_profiler->print(infostream);
3429 g_profiler->clear();