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 "jthread/jmutexautolock.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 JThread
80 ServerThread(Server *server):
89 void * ServerThread::Thread()
91 log_register_thread("ServerThread");
93 DSTACK(__FUNCTION_NAME);
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
100 porting::setThreadName("ServerThread");
102 while(!StopRequested())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
107 m_server->AsyncRunStep();
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
165 const std::string &path_world,
166 const SubgameSpec &gamespec,
167 bool simple_singleplayer_mode,
170 m_path_world(path_world),
171 m_gamespec(gamespec),
172 m_simple_singleplayer_mode(simple_singleplayer_mode),
173 m_async_fatal_error(""),
182 m_enable_rollback_recording(false),
185 m_itemdef(createItemDefManager()),
186 m_nodedef(createNodeDefManager()),
187 m_craftdef(createCraftDefManager()),
188 m_event(new EventManager()),
190 m_time_of_day_send_timer(0),
193 m_shutdown_requested(false),
194 m_shutdown_ask_reconnect(false),
195 m_ignore_map_edit_events(false),
196 m_ignore_map_edit_events_peer_id(0),
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Create world if it doesn't exist
226 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
227 throw ServerError("Failed to initialize world");
229 // Create server thread
230 m_thread = new ServerThread(this);
232 // Create emerge manager
233 m_emerge = new EmergeManager(this);
235 // Create ban manager
236 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
237 m_banmanager = new BanManager(ban_path);
239 ModConfiguration modconf(m_path_world);
240 m_mods = modconf.getMods();
241 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
242 // complain about mods with unsatisfied dependencies
243 if(!modconf.isConsistent()) {
244 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
245 it != unsatisfied_mods.end(); ++it) {
247 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
248 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
249 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
250 errorstream << " \"" << *dep_it << "\"";
251 errorstream << std::endl;
255 Settings worldmt_settings;
256 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
257 worldmt_settings.readConfigFile(worldmt.c_str());
258 std::vector<std::string> names = worldmt_settings.getNames();
259 std::set<std::string> load_mod_names;
260 for(std::vector<std::string>::iterator it = names.begin();
261 it != names.end(); ++it) {
262 std::string name = *it;
263 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
264 load_mod_names.insert(name.substr(9));
266 // complain about mods declared to be loaded, but not found
267 for(std::vector<ModSpec>::iterator it = m_mods.begin();
268 it != m_mods.end(); ++it)
269 load_mod_names.erase((*it).name);
270 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
271 it != unsatisfied_mods.end(); ++it)
272 load_mod_names.erase((*it).name);
273 if(!load_mod_names.empty()) {
274 errorstream << "The following mods could not be found:";
275 for(std::set<std::string>::iterator it = load_mod_names.begin();
276 it != load_mod_names.end(); ++it)
277 errorstream << " \"" << (*it) << "\"";
278 errorstream << std::endl;
282 JMutexAutoLock envlock(m_env_mutex);
284 // Load mapgen params from Settings
285 m_emerge->loadMapgenParams();
287 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
288 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
290 // Initialize scripting
291 infostream<<"Server: Initializing Lua"<<std::endl;
293 m_script = new GameScripting(this);
295 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
296 std::string error_msg;
298 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
299 throw ModError("Failed to load and run " + script_path
300 + "\nError from Lua:\n" + error_msg);
303 infostream << "Server: Loading mods: ";
304 for(std::vector<ModSpec>::iterator i = m_mods.begin();
305 i != m_mods.end(); i++) {
306 const ModSpec &mod = *i;
307 infostream << mod.name << " ";
309 infostream << std::endl;
310 // Load and run "mod" scripts
311 for (std::vector<ModSpec>::iterator i = m_mods.begin();
312 i != m_mods.end(); i++) {
313 const ModSpec &mod = *i;
314 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
315 std::ostringstream err;
316 err << "Error loading mod \"" << mod.name
317 << "\": mod_name does not follow naming conventions: "
318 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
319 errorstream << err.str().c_str();
320 throw ModError(err.str());
322 std::string script_path = mod.path + DIR_DELIM "init.lua";
323 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
324 << script_path << "\"]" << std::endl;
325 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
326 errorstream << "Server: Failed to load and run "
327 << script_path << std::endl;
328 throw ModError("Failed to load and run " + script_path
329 + "\nError from Lua:\n" + error_msg);
333 // Read Textures and calculate sha1 sums
336 // Apply item aliases in the node definition manager
337 m_nodedef->updateAliases(m_itemdef);
339 // Apply texture overrides from texturepack/override.txt
340 std::string texture_path = g_settings->get("texture_path");
341 if (texture_path != "" && fs::IsDir(texture_path))
342 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
344 m_nodedef->setNodeRegistrationStatus(true);
346 // Perform pending node name resolutions
347 m_nodedef->runNodeResolveCallbacks();
349 // init the recipe hashes to speed up crafting
350 m_craftdef->initHashes(this);
352 // Initialize Environment
353 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
355 m_clients.setEnv(m_env);
357 // Initialize mapgens
358 m_emerge->initMapgens();
360 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
361 if (m_enable_rollback_recording) {
362 // Create rollback manager
363 m_rollback = new RollbackManager(m_path_world, this);
366 // Give environment reference to scripting api
367 m_script->initializeEnvironment(m_env);
369 // Register us to receive map edit events
370 servermap->addEventReceiver(this);
372 // If file exists, load environment metadata
373 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
375 infostream<<"Server: Loading environment metadata"<<std::endl;
379 // Add some test ActiveBlockModifiers to environment
380 add_legacy_abms(m_env, m_nodedef);
382 m_liquid_transform_every = g_settings->getFloat("liquid_update");
387 infostream<<"Server destructing"<<std::endl;
389 // Send shutdown message
390 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
393 JMutexAutoLock envlock(m_env_mutex);
395 // Execute script shutdown hooks
396 m_script->on_shutdown();
398 infostream << "Server: Saving players" << std::endl;
399 m_env->saveLoadedPlayers();
401 infostream << "Server: Kicking players" << std::endl;
402 std::string kick_msg;
403 bool reconnect = false;
404 if (getShutdownRequested()) {
405 reconnect = m_shutdown_ask_reconnect;
406 kick_msg = m_shutdown_msg;
408 if (kick_msg == "") {
409 kick_msg = g_settings->get("kick_msg_shutdown");
411 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
412 kick_msg, reconnect);
414 infostream << "Server: Saving environment metadata" << std::endl;
422 // stop all emerge threads before deleting players that may have
423 // requested blocks to be emerged
424 m_emerge->stopThreads();
426 // Delete things in the reverse order of creation
429 // N.B. the EmergeManager should be deleted after the Environment since Map
430 // depends on EmergeManager to write its current params to the map meta
439 // Deinitialize scripting
440 infostream<<"Server: Deinitializing scripting"<<std::endl;
443 // Delete detached inventories
444 for (std::map<std::string, Inventory*>::iterator
445 i = m_detached_inventories.begin();
446 i != m_detached_inventories.end(); i++) {
451 void Server::start(Address bind_addr)
453 DSTACK(__FUNCTION_NAME);
455 m_bind_addr = bind_addr;
457 infostream<<"Starting server on "
458 << bind_addr.serializeString() <<"..."<<std::endl;
460 // Stop thread if already running
463 // Initialize connection
464 m_con.SetTimeoutMs(30);
465 m_con.Serve(bind_addr);
470 // ASCII art for the win!
472 <<" .__ __ __ "<<std::endl
473 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
474 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
475 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
476 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
477 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
478 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
479 actionstream<<"Server for gameid=\""<<m_gamespec.id
480 <<"\" listening on "<<bind_addr.serializeString()<<":"
481 <<bind_addr.getPort() << "."<<std::endl;
486 DSTACK(__FUNCTION_NAME);
488 infostream<<"Server: Stopping and waiting threads"<<std::endl;
490 // Stop threads (set run=false first so both start stopping)
492 //m_emergethread.setRun(false);
494 //m_emergethread.stop();
496 infostream<<"Server: Threads stopped"<<std::endl;
499 void Server::step(float dtime)
501 DSTACK(__FUNCTION_NAME);
506 JMutexAutoLock lock(m_step_dtime_mutex);
507 m_step_dtime += dtime;
509 // Throw if fatal error occurred in thread
510 std::string async_err = m_async_fatal_error.get();
511 if(async_err != "") {
512 if (m_simple_singleplayer_mode) {
513 throw ServerError(async_err);
516 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
517 g_settings->get("kick_msg_crash"),
518 g_settings->getBool("ask_reconnect_on_crash"));
519 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
520 << "Please fix the following error:" << std::endl
521 << async_err << std::endl;
522 FATAL_ERROR(async_err.c_str());
527 void Server::AsyncRunStep(bool initial_step)
529 DSTACK(__FUNCTION_NAME);
531 g_profiler->add("Server::AsyncRunStep (num)", 1);
535 JMutexAutoLock lock1(m_step_dtime_mutex);
536 dtime = m_step_dtime;
540 // Send blocks to clients
544 if((dtime < 0.001) && (initial_step == false))
547 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
549 //infostream<<"Server steps "<<dtime<<std::endl;
550 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
553 JMutexAutoLock lock1(m_step_dtime_mutex);
554 m_step_dtime -= dtime;
561 m_uptime.set(m_uptime.get() + dtime);
567 Update time of day and overall game time
569 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
572 Send to clients at constant intervals
575 m_time_of_day_send_timer -= dtime;
576 if(m_time_of_day_send_timer < 0.0) {
577 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
578 u16 time = m_env->getTimeOfDay();
579 float time_speed = g_settings->getFloat("time_speed");
580 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
584 JMutexAutoLock lock(m_env_mutex);
585 // Figure out and report maximum lag to environment
586 float max_lag = m_env->getMaxLagEstimate();
587 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
589 if(dtime > 0.1 && dtime > max_lag * 2.0)
590 infostream<<"Server: Maximum lag peaked to "<<dtime
594 m_env->reportMaxLagEstimate(max_lag);
596 ScopeProfiler sp(g_profiler, "SEnv step");
597 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
601 static const float map_timer_and_unload_dtime = 2.92;
602 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
604 JMutexAutoLock lock(m_env_mutex);
605 // Run Map's timers and unload unused data
606 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
607 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
608 g_settings->getFloat("server_unload_unused_data_timeout"));
615 /* Transform liquids */
616 m_liquid_transform_timer += dtime;
617 if(m_liquid_transform_timer >= m_liquid_transform_every)
619 m_liquid_transform_timer -= m_liquid_transform_every;
621 JMutexAutoLock lock(m_env_mutex);
623 ScopeProfiler sp(g_profiler, "Server: liquid transform");
625 std::map<v3s16, MapBlock*> modified_blocks;
626 m_env->getMap().transformLiquids(modified_blocks);
631 core::map<v3s16, MapBlock*> lighting_modified_blocks;
632 ServerMap &map = ((ServerMap&)m_env->getMap());
633 map.updateLighting(modified_blocks, lighting_modified_blocks);
635 // Add blocks modified by lighting to modified_blocks
636 for(core::map<v3s16, MapBlock*>::Iterator
637 i = lighting_modified_blocks.getIterator();
638 i.atEnd() == false; i++)
640 MapBlock *block = i.getNode()->getValue();
641 modified_blocks.insert(block->getPos(), block);
645 Set the modified blocks unsent for all the clients
647 if(!modified_blocks.empty())
649 SetBlocksNotSent(modified_blocks);
652 m_clients.step(dtime);
654 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
656 // send masterserver announce
658 float &counter = m_masterserver_timer;
659 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
660 g_settings->getBool("server_announce"))
662 ServerList::sendAnnounce(counter ? "update" : "start",
663 m_bind_addr.getPort(),
664 m_clients.getPlayerNames(),
666 m_env->getGameTime(),
669 m_emerge->params.mg_name,
678 Check added and deleted active objects
681 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
682 JMutexAutoLock envlock(m_env_mutex);
685 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
686 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
688 // Radius inside which objects are active
689 s16 radius = g_settings->getS16("active_object_send_range_blocks");
690 s16 player_radius = g_settings->getS16("player_transfer_distance");
692 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
693 !g_settings->getBool("unlimited_player_transfer_distance"))
694 player_radius = radius;
696 radius *= MAP_BLOCKSIZE;
697 player_radius *= MAP_BLOCKSIZE;
699 for(std::map<u16, RemoteClient*>::iterator
701 i != clients.end(); ++i)
703 RemoteClient *client = i->second;
705 // If definitions and textures have not been sent, don't
706 // send objects either
707 if (client->getState() < CS_DefinitionsSent)
710 Player *player = m_env->getPlayer(client->peer_id);
713 // This can happen if the client timeouts somehow
714 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
716 <<" has no associated player"<<std::endl;*/
719 v3s16 pos = floatToInt(player->getPosition(), BS);
721 std::set<u16> removed_objects;
722 std::set<u16> added_objects;
723 m_env->getRemovedActiveObjects(pos, radius, player_radius,
724 client->m_known_objects, removed_objects);
725 m_env->getAddedActiveObjects(pos, radius, player_radius,
726 client->m_known_objects, added_objects);
728 // Ignore if nothing happened
729 if(removed_objects.empty() && added_objects.empty())
731 //infostream<<"active objects: none changed"<<std::endl;
735 std::string data_buffer;
739 // Handle removed objects
740 writeU16((u8*)buf, removed_objects.size());
741 data_buffer.append(buf, 2);
742 for(std::set<u16>::iterator
743 i = removed_objects.begin();
744 i != removed_objects.end(); ++i)
748 ServerActiveObject* obj = m_env->getActiveObject(id);
750 // Add to data buffer for sending
751 writeU16((u8*)buf, id);
752 data_buffer.append(buf, 2);
754 // Remove from known objects
755 client->m_known_objects.erase(id);
757 if(obj && obj->m_known_by_count > 0)
758 obj->m_known_by_count--;
761 // Handle added objects
762 writeU16((u8*)buf, added_objects.size());
763 data_buffer.append(buf, 2);
764 for(std::set<u16>::iterator
765 i = added_objects.begin();
766 i != added_objects.end(); ++i)
770 ServerActiveObject* obj = m_env->getActiveObject(id);
773 u8 type = ACTIVEOBJECT_TYPE_INVALID;
775 infostream<<"WARNING: "<<__FUNCTION_NAME
776 <<": NULL object"<<std::endl;
778 type = obj->getSendType();
780 // Add to data buffer for sending
781 writeU16((u8*)buf, id);
782 data_buffer.append(buf, 2);
783 writeU8((u8*)buf, type);
784 data_buffer.append(buf, 1);
787 data_buffer.append(serializeLongString(
788 obj->getClientInitializationData(client->net_proto_version)));
790 data_buffer.append(serializeLongString(""));
792 // Add to known objects
793 client->m_known_objects.insert(id);
796 obj->m_known_by_count++;
799 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
800 verbosestream << "Server: Sent object remove/add: "
801 << removed_objects.size() << " removed, "
802 << added_objects.size() << " added, "
803 << "packet size is " << pktSize << std::endl;
812 JMutexAutoLock envlock(m_env_mutex);
813 ScopeProfiler sp(g_profiler, "Server: sending object messages");
816 // Value = data sent by object
817 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
819 // Get active object messages from environment
821 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
825 std::vector<ActiveObjectMessage>* message_list = NULL;
826 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
827 n = buffered_messages.find(aom.id);
828 if (n == buffered_messages.end()) {
829 message_list = new std::vector<ActiveObjectMessage>;
830 buffered_messages[aom.id] = message_list;
833 message_list = n->second;
835 message_list->push_back(aom);
839 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
840 // Route data to every client
841 for (std::map<u16, RemoteClient*>::iterator
843 i != clients.end(); ++i) {
844 RemoteClient *client = i->second;
845 std::string reliable_data;
846 std::string unreliable_data;
847 // Go through all objects in message buffer
848 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
849 j = buffered_messages.begin();
850 j != buffered_messages.end(); ++j) {
851 // If object is not known by client, skip it
853 if (client->m_known_objects.find(id) == client->m_known_objects.end())
856 // Get message list of object
857 std::vector<ActiveObjectMessage>* list = j->second;
858 // Go through every message
859 for (std::vector<ActiveObjectMessage>::iterator
860 k = list->begin(); k != list->end(); ++k) {
861 // Compose the full new data with header
862 ActiveObjectMessage aom = *k;
863 std::string new_data;
866 writeU16((u8*)&buf[0], aom.id);
867 new_data.append(buf, 2);
869 new_data += serializeString(aom.datastring);
870 // Add data to buffer
872 reliable_data += new_data;
874 unreliable_data += new_data;
878 reliable_data and unreliable_data are now ready.
881 if(reliable_data.size() > 0) {
882 SendActiveObjectMessages(client->peer_id, reliable_data);
885 if(unreliable_data.size() > 0) {
886 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
891 // Clear buffered_messages
892 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
893 i = buffered_messages.begin();
894 i != buffered_messages.end(); ++i) {
900 Send queued-for-sending map edit events.
903 // We will be accessing the environment
904 JMutexAutoLock lock(m_env_mutex);
906 // Don't send too many at a time
909 // Single change sending is disabled if queue size is not small
910 bool disable_single_change_sending = false;
911 if(m_unsent_map_edit_queue.size() >= 4)
912 disable_single_change_sending = true;
914 int event_count = m_unsent_map_edit_queue.size();
916 // We'll log the amount of each
919 while(m_unsent_map_edit_queue.size() != 0)
921 MapEditEvent* event = m_unsent_map_edit_queue.front();
922 m_unsent_map_edit_queue.pop();
924 // Players far away from the change are stored here.
925 // Instead of sending the changes, MapBlocks are set not sent
927 std::vector<u16> far_players;
929 switch (event->type) {
932 prof.add("MEET_ADDNODE", 1);
933 sendAddNode(event->p, event->n, event->already_known_by_peer,
934 &far_players, disable_single_change_sending ? 5 : 30,
935 event->type == MEET_ADDNODE);
937 case MEET_REMOVENODE:
938 prof.add("MEET_REMOVENODE", 1);
939 sendRemoveNode(event->p, event->already_known_by_peer,
940 &far_players, disable_single_change_sending ? 5 : 30);
942 case MEET_BLOCK_NODE_METADATA_CHANGED:
943 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
944 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
945 setBlockNotSent(event->p);
948 infostream << "Server: MEET_OTHER" << std::endl;
949 prof.add("MEET_OTHER", 1);
950 for(std::set<v3s16>::iterator
951 i = event->modified_blocks.begin();
952 i != event->modified_blocks.end(); ++i) {
957 prof.add("unknown", 1);
958 infostream << "WARNING: Server: Unknown MapEditEvent "
959 << ((u32)event->type) << std::endl;
964 Set blocks not sent to far players
966 if(!far_players.empty()) {
967 // Convert list format to that wanted by SetBlocksNotSent
968 std::map<v3s16, MapBlock*> modified_blocks2;
969 for(std::set<v3s16>::iterator
970 i = event->modified_blocks.begin();
971 i != event->modified_blocks.end(); ++i) {
972 modified_blocks2[*i] =
973 m_env->getMap().getBlockNoCreateNoEx(*i);
976 // Set blocks not sent
977 for(std::vector<u16>::iterator
978 i = far_players.begin();
979 i != far_players.end(); ++i) {
980 if(RemoteClient *client = getClient(*i))
981 client->SetBlocksNotSent(modified_blocks2);
987 /*// Don't send too many at a time
989 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
993 if(event_count >= 5){
994 infostream<<"Server: MapEditEvents:"<<std::endl;
995 prof.print(infostream);
996 } else if(event_count != 0){
997 verbosestream<<"Server: MapEditEvents:"<<std::endl;
998 prof.print(verbosestream);
1004 Trigger emergethread (it somehow gets to a non-triggered but
1005 bysy state sometimes)
1008 float &counter = m_emergethread_trigger_timer;
1014 m_emerge->startThreads();
1018 // Save map, players and auth stuff
1020 float &counter = m_savemap_timer;
1022 if(counter >= g_settings->getFloat("server_map_save_interval"))
1025 JMutexAutoLock lock(m_env_mutex);
1027 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1030 if (m_banmanager->isModified()) {
1031 m_banmanager->save();
1034 // Save changed parts of map
1035 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1038 m_env->saveLoadedPlayers();
1040 // Save environment metadata
1046 void Server::Receive()
1048 DSTACK(__FUNCTION_NAME);
1049 SharedBuffer<u8> data;
1053 m_con.Receive(&pkt);
1054 peer_id = pkt.getPeerId();
1057 catch(con::InvalidIncomingDataException &e) {
1058 infostream<<"Server::Receive(): "
1059 "InvalidIncomingDataException: what()="
1060 <<e.what()<<std::endl;
1062 catch(SerializationError &e) {
1063 infostream<<"Server::Receive(): "
1064 "SerializationError: what()="
1065 <<e.what()<<std::endl;
1067 catch(ClientStateError &e) {
1068 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1069 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1070 L"Try reconnecting or updating your client");
1072 catch(con::PeerNotFoundException &e) {
1077 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1079 std::string playername = "";
1080 PlayerSAO *playersao = NULL;
1083 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1084 if (client != NULL) {
1085 playername = client->getName();
1086 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1088 } catch (std::exception &e) {
1094 RemotePlayer *player =
1095 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1097 // If failed, cancel
1098 if ((playersao == NULL) || (player == NULL)) {
1099 if (player && player->peer_id != 0) {
1100 actionstream << "Server: Failed to emerge player \"" << playername
1101 << "\" (player allocated to an another client)" << std::endl;
1102 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1103 L"name. If your client closed unexpectedly, try again in "
1106 errorstream << "Server: " << playername << ": Failed to emerge player"
1108 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1114 Send complete position information
1116 SendMovePlayer(peer_id);
1119 SendPlayerPrivileges(peer_id);
1121 // Send inventory formspec
1122 SendPlayerInventoryFormspec(peer_id);
1125 SendInventory(playersao);
1128 SendPlayerHPOrDie(playersao);
1131 SendPlayerBreath(peer_id);
1133 // Show death screen if necessary
1134 if(player->isDead())
1135 SendDeathscreen(peer_id, false, v3f(0,0,0));
1137 // Note things in chat if not in simple singleplayer mode
1138 if(!m_simple_singleplayer_mode) {
1139 // Send information about server to player in chat
1140 SendChatMessage(peer_id, getStatusString());
1142 // Send information about joining in chat
1144 std::wstring name = L"unknown";
1145 Player *player = m_env->getPlayer(peer_id);
1147 name = narrow_to_wide(player->getName());
1149 std::wstring message;
1152 message += L" joined the game.";
1153 SendChatMessage(PEER_ID_INEXISTENT,message);
1156 Address addr = getPeerAddress(player->peer_id);
1157 std::string ip_str = addr.serializeString();
1158 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1163 std::vector<std::string> names = m_clients.getPlayerNames();
1165 actionstream<<player->getName() <<" joins game. List of players: ";
1167 for (std::vector<std::string>::iterator i = names.begin();
1168 i != names.end(); i++) {
1169 actionstream << *i << " ";
1172 actionstream << player->getName() <<std::endl;
1177 inline void Server::handleCommand(NetworkPacket* pkt)
1179 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1180 (this->*opHandle.handler)(pkt);
1183 void Server::ProcessData(NetworkPacket *pkt)
1185 DSTACK(__FUNCTION_NAME);
1186 // Environment is locked first.
1187 JMutexAutoLock envlock(m_env_mutex);
1189 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1190 u32 peer_id = pkt->getPeerId();
1193 Address address = getPeerAddress(peer_id);
1194 std::string addr_s = address.serializeString();
1196 if(m_banmanager->isIpBanned(addr_s)) {
1197 std::string ban_name = m_banmanager->getBanName(addr_s);
1198 infostream << "Server: A banned client tried to connect from "
1199 << addr_s << "; banned name was "
1200 << ban_name << std::endl;
1201 // This actually doesn't seem to transfer to the client
1202 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1203 + utf8_to_wide(ban_name));
1207 catch(con::PeerNotFoundException &e) {
1209 * no peer for this packet found
1210 * most common reason is peer timeout, e.g. peer didn't
1211 * respond for some time, your server was overloaded or
1214 infostream << "Server::ProcessData(): Canceling: peer "
1215 << peer_id << " not found" << std::endl;
1220 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1222 // Command must be handled into ToServerCommandHandler
1223 if (command >= TOSERVER_NUM_MSG_TYPES) {
1224 infostream << "Server: Ignoring unknown command "
1225 << command << std::endl;
1229 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1234 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1236 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1237 errorstream << "Server::ProcessData(): Cancelling: Peer"
1238 " serialization format invalid or not initialized."
1239 " Skipping incoming command=" << command << std::endl;
1243 /* Handle commands related to client startup */
1244 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1249 if (m_clients.getClientState(peer_id) < CS_Active) {
1250 if (command == TOSERVER_PLAYERPOS) return;
1252 errorstream << "Got packet command: " << command << " for peer id "
1253 << peer_id << " but client isn't active yet. Dropping packet "
1259 } catch (SendFailedException &e) {
1260 errorstream << "Server::ProcessData(): SendFailedException: "
1261 << "what=" << e.what()
1263 } catch (PacketError &e) {
1264 actionstream << "Server::ProcessData(): PacketError: "
1265 << "what=" << e.what()
1270 void Server::setTimeOfDay(u32 time)
1272 m_env->setTimeOfDay(time);
1273 m_time_of_day_send_timer = 0;
1276 void Server::onMapEditEvent(MapEditEvent *event)
1278 if(m_ignore_map_edit_events)
1280 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1282 MapEditEvent *e = event->clone();
1283 m_unsent_map_edit_queue.push(e);
1286 Inventory* Server::getInventory(const InventoryLocation &loc)
1289 case InventoryLocation::UNDEFINED:
1290 case InventoryLocation::CURRENT_PLAYER:
1292 case InventoryLocation::PLAYER:
1294 Player *player = m_env->getPlayer(loc.name.c_str());
1297 PlayerSAO *playersao = player->getPlayerSAO();
1300 return playersao->getInventory();
1303 case InventoryLocation::NODEMETA:
1305 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1308 return meta->getInventory();
1311 case InventoryLocation::DETACHED:
1313 if(m_detached_inventories.count(loc.name) == 0)
1315 return m_detached_inventories[loc.name];
1319 sanity_check(false); // abort
1324 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1327 case InventoryLocation::UNDEFINED:
1329 case InventoryLocation::PLAYER:
1334 Player *player = m_env->getPlayer(loc.name.c_str());
1337 PlayerSAO *playersao = player->getPlayerSAO();
1341 SendInventory(playersao);
1344 case InventoryLocation::NODEMETA:
1346 v3s16 blockpos = getNodeBlockPos(loc.p);
1348 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1350 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1352 setBlockNotSent(blockpos);
1355 case InventoryLocation::DETACHED:
1357 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1361 sanity_check(false); // abort
1366 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1368 std::vector<u16> clients = m_clients.getClientIDs();
1370 // Set the modified blocks unsent for all the clients
1371 for (std::vector<u16>::iterator i = clients.begin();
1372 i != clients.end(); ++i) {
1373 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1374 client->SetBlocksNotSent(block);
1379 void Server::peerAdded(con::Peer *peer)
1381 DSTACK(__FUNCTION_NAME);
1382 verbosestream<<"Server::peerAdded(): peer->id="
1383 <<peer->id<<std::endl;
1386 c.type = con::PEER_ADDED;
1387 c.peer_id = peer->id;
1389 m_peer_change_queue.push(c);
1392 void Server::deletingPeer(con::Peer *peer, bool timeout)
1394 DSTACK(__FUNCTION_NAME);
1395 verbosestream<<"Server::deletingPeer(): peer->id="
1396 <<peer->id<<", timeout="<<timeout<<std::endl;
1398 m_clients.event(peer->id, CSE_Disconnect);
1400 c.type = con::PEER_REMOVED;
1401 c.peer_id = peer->id;
1402 c.timeout = timeout;
1403 m_peer_change_queue.push(c);
1406 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1408 *retval = m_con.getPeerStat(peer_id,type);
1409 if (*retval == -1) return false;
1413 bool Server::getClientInfo(
1422 std::string* vers_string
1425 *state = m_clients.getClientState(peer_id);
1427 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1429 if (client == NULL) {
1434 *uptime = client->uptime();
1435 *ser_vers = client->serialization_version;
1436 *prot_vers = client->net_proto_version;
1438 *major = client->getMajor();
1439 *minor = client->getMinor();
1440 *patch = client->getPatch();
1441 *vers_string = client->getPatch();
1448 void Server::handlePeerChanges()
1450 while(m_peer_change_queue.size() > 0)
1452 con::PeerChange c = m_peer_change_queue.front();
1453 m_peer_change_queue.pop();
1455 verbosestream<<"Server: Handling peer change: "
1456 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1461 case con::PEER_ADDED:
1462 m_clients.CreateClient(c.peer_id);
1465 case con::PEER_REMOVED:
1466 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1470 FATAL_ERROR("Invalid peer change event received!");
1476 void Server::Send(NetworkPacket* pkt)
1478 m_clients.send(pkt->getPeerId(),
1479 clientCommandFactoryTable[pkt->getCommand()].channel,
1481 clientCommandFactoryTable[pkt->getCommand()].reliable);
1484 void Server::SendMovement(u16 peer_id)
1486 DSTACK(__FUNCTION_NAME);
1487 std::ostringstream os(std::ios_base::binary);
1489 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1491 pkt << g_settings->getFloat("movement_acceleration_default");
1492 pkt << g_settings->getFloat("movement_acceleration_air");
1493 pkt << g_settings->getFloat("movement_acceleration_fast");
1494 pkt << g_settings->getFloat("movement_speed_walk");
1495 pkt << g_settings->getFloat("movement_speed_crouch");
1496 pkt << g_settings->getFloat("movement_speed_fast");
1497 pkt << g_settings->getFloat("movement_speed_climb");
1498 pkt << g_settings->getFloat("movement_speed_jump");
1499 pkt << g_settings->getFloat("movement_liquid_fluidity");
1500 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1501 pkt << g_settings->getFloat("movement_liquid_sink");
1502 pkt << g_settings->getFloat("movement_gravity");
1507 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1509 if (!g_settings->getBool("enable_damage"))
1512 u16 peer_id = playersao->getPeerID();
1513 bool is_alive = playersao->getHP() > 0;
1516 SendPlayerHP(peer_id);
1521 void Server::SendHP(u16 peer_id, u8 hp)
1523 DSTACK(__FUNCTION_NAME);
1525 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1530 void Server::SendBreath(u16 peer_id, u16 breath)
1532 DSTACK(__FUNCTION_NAME);
1534 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1535 pkt << (u16) breath;
1539 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1540 const std::string &custom_reason, bool reconnect)
1542 assert(reason < SERVER_ACCESSDENIED_MAX);
1544 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1546 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1547 pkt << custom_reason;
1548 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1549 reason == SERVER_ACCESSDENIED_CRASH)
1550 pkt << custom_reason << (u8)reconnect;
1554 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1556 DSTACK(__FUNCTION_NAME);
1558 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1563 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1564 v3f camera_point_target)
1566 DSTACK(__FUNCTION_NAME);
1568 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1569 pkt << set_camera_point_target << camera_point_target;
1573 void Server::SendItemDef(u16 peer_id,
1574 IItemDefManager *itemdef, u16 protocol_version)
1576 DSTACK(__FUNCTION_NAME);
1578 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1582 u32 length of the next item
1583 zlib-compressed serialized ItemDefManager
1585 std::ostringstream tmp_os(std::ios::binary);
1586 itemdef->serialize(tmp_os, protocol_version);
1587 std::ostringstream tmp_os2(std::ios::binary);
1588 compressZlib(tmp_os.str(), tmp_os2);
1589 pkt.putLongString(tmp_os2.str());
1592 verbosestream << "Server: Sending item definitions to id(" << peer_id
1593 << "): size=" << pkt.getSize() << std::endl;
1598 void Server::SendNodeDef(u16 peer_id,
1599 INodeDefManager *nodedef, u16 protocol_version)
1601 DSTACK(__FUNCTION_NAME);
1603 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1607 u32 length of the next item
1608 zlib-compressed serialized NodeDefManager
1610 std::ostringstream tmp_os(std::ios::binary);
1611 nodedef->serialize(tmp_os, protocol_version);
1612 std::ostringstream tmp_os2(std::ios::binary);
1613 compressZlib(tmp_os.str(), tmp_os2);
1615 pkt.putLongString(tmp_os2.str());
1618 verbosestream << "Server: Sending node definitions to id(" << peer_id
1619 << "): size=" << pkt.getSize() << std::endl;
1625 Non-static send methods
1628 void Server::SendInventory(PlayerSAO* playerSAO)
1630 DSTACK(__FUNCTION_NAME);
1632 UpdateCrafting(playerSAO->getPlayer());
1638 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1640 std::ostringstream os;
1641 playerSAO->getInventory()->serialize(os);
1643 std::string s = os.str();
1645 pkt.putRawString(s.c_str(), s.size());
1649 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1651 DSTACK(__FUNCTION_NAME);
1653 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1656 if (peer_id != PEER_ID_INEXISTENT) {
1660 m_clients.sendToAll(0, &pkt, true);
1664 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1665 const std::string &formname)
1667 DSTACK(__FUNCTION_NAME);
1669 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1671 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1677 // Spawns a particle on peer with peer_id
1678 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1679 float expirationtime, float size, bool collisiondetection,
1680 bool vertical, std::string texture)
1682 DSTACK(__FUNCTION_NAME);
1684 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1686 pkt << pos << velocity << acceleration << expirationtime
1687 << size << collisiondetection;
1688 pkt.putLongString(texture);
1691 if (peer_id != PEER_ID_INEXISTENT) {
1695 m_clients.sendToAll(0, &pkt, true);
1699 // Adds a ParticleSpawner on peer with peer_id
1700 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1701 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1702 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1704 DSTACK(__FUNCTION_NAME);
1706 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1708 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1709 << minacc << maxacc << minexptime << maxexptime << minsize
1710 << maxsize << collisiondetection;
1712 pkt.putLongString(texture);
1714 pkt << id << vertical;
1716 if (peer_id != PEER_ID_INEXISTENT) {
1720 m_clients.sendToAll(0, &pkt, true);
1724 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1726 DSTACK(__FUNCTION_NAME);
1728 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1730 // Ugly error in this packet
1733 if (peer_id != PEER_ID_INEXISTENT) {
1737 m_clients.sendToAll(0, &pkt, true);
1742 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1744 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1746 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1747 << form->text << form->number << form->item << form->dir
1748 << form->align << form->offset << form->world_pos << form->size;
1753 void Server::SendHUDRemove(u16 peer_id, u32 id)
1755 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1760 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1762 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1763 pkt << id << (u8) stat;
1767 case HUD_STAT_SCALE:
1768 case HUD_STAT_ALIGN:
1769 case HUD_STAT_OFFSET:
1770 pkt << *(v2f *) value;
1774 pkt << *(std::string *) value;
1776 case HUD_STAT_WORLD_POS:
1777 pkt << *(v3f *) value;
1780 pkt << *(v2s32 *) value;
1782 case HUD_STAT_NUMBER:
1786 pkt << *(u32 *) value;
1793 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1795 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1797 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1799 pkt << flags << mask;
1804 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1806 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1807 pkt << param << value;
1811 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1812 const std::string &type, const std::vector<std::string> ¶ms)
1814 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1815 pkt << bgcolor << type << (u16) params.size();
1817 for(size_t i=0; i<params.size(); i++)
1823 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1826 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1829 pkt << do_override << (u16) (ratio * 65535);
1834 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1836 DSTACK(__FUNCTION_NAME);
1838 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1839 pkt << time << time_speed;
1841 if (peer_id == PEER_ID_INEXISTENT) {
1842 m_clients.sendToAll(0, &pkt, true);
1849 void Server::SendPlayerHP(u16 peer_id)
1851 DSTACK(__FUNCTION_NAME);
1852 PlayerSAO *playersao = getPlayerSAO(peer_id);
1853 // In some rare case, if the player is disconnected
1854 // while Lua call l_punch, for example, this can be NULL
1858 SendHP(peer_id, playersao->getHP());
1859 m_script->player_event(playersao,"health_changed");
1861 // Send to other clients
1862 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1863 ActiveObjectMessage aom(playersao->getId(), true, str);
1864 playersao->m_messages_out.push(aom);
1867 void Server::SendPlayerBreath(u16 peer_id)
1869 DSTACK(__FUNCTION_NAME);
1870 PlayerSAO *playersao = getPlayerSAO(peer_id);
1873 m_script->player_event(playersao, "breath_changed");
1874 SendBreath(peer_id, playersao->getBreath());
1877 void Server::SendMovePlayer(u16 peer_id)
1879 DSTACK(__FUNCTION_NAME);
1880 Player *player = m_env->getPlayer(peer_id);
1883 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1884 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1887 v3f pos = player->getPosition();
1888 f32 pitch = player->getPitch();
1889 f32 yaw = player->getYaw();
1890 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1891 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1892 << " pitch=" << pitch
1900 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1902 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1905 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1906 << animation_frames[3] << animation_speed;
1911 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1913 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1914 pkt << first << third;
1917 void Server::SendPlayerPrivileges(u16 peer_id)
1919 Player *player = m_env->getPlayer(peer_id);
1921 if(player->peer_id == PEER_ID_INEXISTENT)
1924 std::set<std::string> privs;
1925 m_script->getAuth(player->getName(), NULL, &privs);
1927 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1928 pkt << (u16) privs.size();
1930 for(std::set<std::string>::const_iterator i = privs.begin();
1931 i != privs.end(); i++) {
1938 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1940 Player *player = m_env->getPlayer(peer_id);
1942 if(player->peer_id == PEER_ID_INEXISTENT)
1945 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1946 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1950 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1952 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1953 pkt.putRawString(datas.c_str(), datas.size());
1955 return pkt.getSize();
1958 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1960 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1961 datas.size(), peer_id);
1963 pkt.putRawString(datas.c_str(), datas.size());
1965 m_clients.send(pkt.getPeerId(),
1966 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1971 s32 Server::playSound(const SimpleSoundSpec &spec,
1972 const ServerSoundParams ¶ms)
1974 // Find out initial position of sound
1975 bool pos_exists = false;
1976 v3f pos = params.getPos(m_env, &pos_exists);
1977 // If position is not found while it should be, cancel sound
1978 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1981 // Filter destination clients
1982 std::vector<u16> dst_clients;
1983 if(params.to_player != "")
1985 Player *player = m_env->getPlayer(params.to_player.c_str());
1987 infostream<<"Server::playSound: Player \""<<params.to_player
1988 <<"\" not found"<<std::endl;
1991 if(player->peer_id == PEER_ID_INEXISTENT){
1992 infostream<<"Server::playSound: Player \""<<params.to_player
1993 <<"\" not connected"<<std::endl;
1996 dst_clients.push_back(player->peer_id);
1999 std::vector<u16> clients = m_clients.getClientIDs();
2001 for(std::vector<u16>::iterator
2002 i = clients.begin(); i != clients.end(); ++i) {
2003 Player *player = m_env->getPlayer(*i);
2008 if(player->getPosition().getDistanceFrom(pos) >
2009 params.max_hear_distance)
2012 dst_clients.push_back(*i);
2016 if(dst_clients.empty())
2020 s32 id = m_next_sound_id++;
2021 // The sound will exist as a reference in m_playing_sounds
2022 m_playing_sounds[id] = ServerPlayingSound();
2023 ServerPlayingSound &psound = m_playing_sounds[id];
2024 psound.params = params;
2026 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2027 pkt << id << spec.name << (float) (spec.gain * params.gain)
2028 << (u8) params.type << pos << params.object << params.loop;
2030 for(std::vector<u16>::iterator i = dst_clients.begin();
2031 i != dst_clients.end(); i++) {
2032 psound.clients.insert(*i);
2033 m_clients.send(*i, 0, &pkt, true);
2037 void Server::stopSound(s32 handle)
2039 // Get sound reference
2040 std::map<s32, ServerPlayingSound>::iterator i =
2041 m_playing_sounds.find(handle);
2042 if(i == m_playing_sounds.end())
2044 ServerPlayingSound &psound = i->second;
2046 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2049 for(std::set<u16>::iterator i = psound.clients.begin();
2050 i != psound.clients.end(); i++) {
2052 m_clients.send(*i, 0, &pkt, true);
2054 // Remove sound reference
2055 m_playing_sounds.erase(i);
2058 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2059 std::vector<u16> *far_players, float far_d_nodes)
2061 float maxd = far_d_nodes*BS;
2062 v3f p_f = intToFloat(p, BS);
2064 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2067 std::vector<u16> clients = m_clients.getClientIDs();
2068 for(std::vector<u16>::iterator i = clients.begin();
2069 i != clients.end(); ++i) {
2072 if(Player *player = m_env->getPlayer(*i)) {
2073 // If player is far away, only set modified blocks not sent
2074 v3f player_pos = player->getPosition();
2075 if(player_pos.getDistanceFrom(p_f) > maxd) {
2076 far_players->push_back(*i);
2083 m_clients.send(*i, 0, &pkt, true);
2087 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2088 std::vector<u16> *far_players, float far_d_nodes,
2089 bool remove_metadata)
2091 float maxd = far_d_nodes*BS;
2092 v3f p_f = intToFloat(p, BS);
2094 std::vector<u16> clients = m_clients.getClientIDs();
2095 for(std::vector<u16>::iterator i = clients.begin();
2096 i != clients.end(); ++i) {
2100 if(Player *player = m_env->getPlayer(*i)) {
2101 // If player is far away, only set modified blocks not sent
2102 v3f player_pos = player->getPosition();
2103 if(player_pos.getDistanceFrom(p_f) > maxd) {
2104 far_players->push_back(*i);
2110 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2112 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2114 pkt << p << n.param0 << n.param1 << n.param2
2115 << (u8) (remove_metadata ? 0 : 1);
2117 if (!remove_metadata) {
2118 if (client->net_proto_version <= 21) {
2119 // Old clients always clear metadata; fix it
2120 // by sending the full block again.
2121 client->SetBlockNotSent(p);
2128 if (pkt.getSize() > 0)
2129 m_clients.send(*i, 0, &pkt, true);
2133 void Server::setBlockNotSent(v3s16 p)
2135 std::vector<u16> clients = m_clients.getClientIDs();
2137 for(std::vector<u16>::iterator i = clients.begin();
2138 i != clients.end(); ++i) {
2139 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2140 client->SetBlockNotSent(p);
2145 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2147 DSTACK(__FUNCTION_NAME);
2149 v3s16 p = block->getPos();
2152 Create a packet with the block in the right format
2155 std::ostringstream os(std::ios_base::binary);
2156 block->serialize(os, ver, false);
2157 block->serializeNetworkSpecific(os, net_proto_version);
2158 std::string s = os.str();
2160 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2163 pkt.putRawString(s.c_str(), s.size());
2167 void Server::SendBlocks(float dtime)
2169 DSTACK(__FUNCTION_NAME);
2171 JMutexAutoLock envlock(m_env_mutex);
2172 //TODO check if one big lock could be faster then multiple small ones
2174 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2176 std::vector<PrioritySortedBlockTransfer> queue;
2178 s32 total_sending = 0;
2181 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2183 std::vector<u16> clients = m_clients.getClientIDs();
2186 for(std::vector<u16>::iterator i = clients.begin();
2187 i != clients.end(); ++i) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2193 total_sending += client->SendingCount();
2194 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2200 // Lowest priority number comes first.
2201 // Lowest is most important.
2202 std::sort(queue.begin(), queue.end());
2205 for(u32 i=0; i<queue.size(); i++)
2207 //TODO: Calculate limit dynamically
2208 if(total_sending >= g_settings->getS32
2209 ("max_simultaneous_block_sends_server_total"))
2212 PrioritySortedBlockTransfer q = queue[i];
2214 MapBlock *block = NULL;
2217 block = m_env->getMap().getBlockNoCreate(q.pos);
2219 catch(InvalidPositionException &e)
2224 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2229 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2231 client->SentBlock(q.pos);
2237 void Server::fillMediaCache()
2239 DSTACK(__FUNCTION_NAME);
2241 infostream<<"Server: Calculating media file checksums"<<std::endl;
2243 // Collect all media file paths
2244 std::vector<std::string> paths;
2245 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2246 i != m_mods.end(); i++) {
2247 const ModSpec &mod = *i;
2248 paths.push_back(mod.path + DIR_DELIM + "textures");
2249 paths.push_back(mod.path + DIR_DELIM + "sounds");
2250 paths.push_back(mod.path + DIR_DELIM + "media");
2251 paths.push_back(mod.path + DIR_DELIM + "models");
2253 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2255 // Collect media file information from paths into cache
2256 for(std::vector<std::string>::iterator i = paths.begin();
2257 i != paths.end(); i++) {
2258 std::string mediapath = *i;
2259 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2260 for (u32 j = 0; j < dirlist.size(); j++) {
2261 if (dirlist[j].dir) // Ignode dirs
2263 std::string filename = dirlist[j].name;
2264 // If name contains illegal characters, ignore the file
2265 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2266 infostream<<"Server: ignoring illegal file name: \""
2267 << filename << "\"" << std::endl;
2270 // If name is not in a supported format, ignore it
2271 const char *supported_ext[] = {
2272 ".png", ".jpg", ".bmp", ".tga",
2273 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2275 ".x", ".b3d", ".md2", ".obj",
2278 if (removeStringEnd(filename, supported_ext) == ""){
2279 infostream << "Server: ignoring unsupported file extension: \""
2280 << filename << "\"" << std::endl;
2283 // Ok, attempt to load the file and add to cache
2284 std::string filepath = mediapath + DIR_DELIM + filename;
2286 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2288 errorstream << "Server::fillMediaCache(): Could not open \""
2289 << filename << "\" for reading" << std::endl;
2292 std::ostringstream tmp_os(std::ios_base::binary);
2296 fis.read(buf, 1024);
2297 std::streamsize len = fis.gcount();
2298 tmp_os.write(buf, len);
2307 errorstream<<"Server::fillMediaCache(): Failed to read \""
2308 << filename << "\"" << std::endl;
2311 if(tmp_os.str().length() == 0) {
2312 errorstream << "Server::fillMediaCache(): Empty file \""
2313 << filepath << "\"" << std::endl;
2318 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2320 unsigned char *digest = sha1.getDigest();
2321 std::string sha1_base64 = base64_encode(digest, 20);
2322 std::string sha1_hex = hex_encode((char*)digest, 20);
2326 m_media[filename] = MediaInfo(filepath, sha1_base64);
2327 verbosestream << "Server: " << sha1_hex << " is " << filename
2333 struct SendableMediaAnnouncement
2336 std::string sha1_digest;
2338 SendableMediaAnnouncement(const std::string &name_="",
2339 const std::string &sha1_digest_=""):
2341 sha1_digest(sha1_digest_)
2345 void Server::sendMediaAnnouncement(u16 peer_id)
2347 DSTACK(__FUNCTION_NAME);
2349 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2352 std::vector<SendableMediaAnnouncement> file_announcements;
2354 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2355 i != m_media.end(); i++){
2357 file_announcements.push_back(
2358 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2362 std::ostringstream os(std::ios_base::binary);
2364 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2365 pkt << (u16) file_announcements.size();
2367 for (std::vector<SendableMediaAnnouncement>::iterator
2368 j = file_announcements.begin();
2369 j != file_announcements.end(); ++j) {
2370 pkt << j->name << j->sha1_digest;
2373 pkt << g_settings->get("remote_media");
2377 struct SendableMedia
2383 SendableMedia(const std::string &name_="", const std::string &path_="",
2384 const std::string &data_=""):
2391 void Server::sendRequestedMedia(u16 peer_id,
2392 const std::vector<std::string> &tosend)
2394 DSTACK(__FUNCTION_NAME);
2396 verbosestream<<"Server::sendRequestedMedia(): "
2397 <<"Sending files to client"<<std::endl;
2401 // Put 5kB in one bunch (this is not accurate)
2402 u32 bytes_per_bunch = 5000;
2404 std::vector< std::vector<SendableMedia> > file_bunches;
2405 file_bunches.push_back(std::vector<SendableMedia>());
2407 u32 file_size_bunch_total = 0;
2409 for(std::vector<std::string>::const_iterator i = tosend.begin();
2410 i != tosend.end(); ++i) {
2411 const std::string &name = *i;
2413 if(m_media.find(name) == m_media.end()) {
2414 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2415 <<"unknown file \""<<(name)<<"\""<<std::endl;
2419 //TODO get path + name
2420 std::string tpath = m_media[name].path;
2423 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2424 if(fis.good() == false){
2425 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2426 <<tpath<<"\" for reading"<<std::endl;
2429 std::ostringstream tmp_os(std::ios_base::binary);
2433 fis.read(buf, 1024);
2434 std::streamsize len = fis.gcount();
2435 tmp_os.write(buf, len);
2436 file_size_bunch_total += len;
2445 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2446 <<name<<"\""<<std::endl;
2449 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2450 <<tname<<"\""<<std::endl;*/
2452 file_bunches[file_bunches.size()-1].push_back(
2453 SendableMedia(name, tpath, tmp_os.str()));
2455 // Start next bunch if got enough data
2456 if(file_size_bunch_total >= bytes_per_bunch) {
2457 file_bunches.push_back(std::vector<SendableMedia>());
2458 file_size_bunch_total = 0;
2463 /* Create and send packets */
2465 u16 num_bunches = file_bunches.size();
2466 for(u16 i = 0; i < num_bunches; i++) {
2469 u16 total number of texture bunches
2470 u16 index of this bunch
2471 u32 number of files in this bunch
2480 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2481 pkt << num_bunches << i << (u32) file_bunches[i].size();
2483 for(std::vector<SendableMedia>::iterator
2484 j = file_bunches[i].begin();
2485 j != file_bunches[i].end(); ++j) {
2487 pkt.putLongString(j->data);
2490 verbosestream << "Server::sendRequestedMedia(): bunch "
2491 << i << "/" << num_bunches
2492 << " files=" << file_bunches[i].size()
2493 << " size=" << pkt.getSize() << std::endl;
2498 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2500 if(m_detached_inventories.count(name) == 0) {
2501 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2504 Inventory *inv = m_detached_inventories[name];
2505 std::ostringstream os(std::ios_base::binary);
2507 os << serializeString(name);
2511 std::string s = os.str();
2513 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2514 pkt.putRawString(s.c_str(), s.size());
2516 if (peer_id != PEER_ID_INEXISTENT) {
2520 m_clients.sendToAll(0, &pkt, true);
2524 void Server::sendDetachedInventories(u16 peer_id)
2526 DSTACK(__FUNCTION_NAME);
2528 for(std::map<std::string, Inventory*>::iterator
2529 i = m_detached_inventories.begin();
2530 i != m_detached_inventories.end(); i++) {
2531 const std::string &name = i->first;
2532 //Inventory *inv = i->second;
2533 sendDetachedInventory(name, peer_id);
2541 void Server::DiePlayer(u16 peer_id)
2543 DSTACK(__FUNCTION_NAME);
2545 PlayerSAO *playersao = getPlayerSAO(peer_id);
2548 infostream << "Server::DiePlayer(): Player "
2549 << playersao->getPlayer()->getName()
2550 << " dies" << std::endl;
2552 playersao->setHP(0);
2554 // Trigger scripted stuff
2555 m_script->on_dieplayer(playersao);
2557 SendPlayerHP(peer_id);
2558 SendDeathscreen(peer_id, false, v3f(0,0,0));
2561 void Server::RespawnPlayer(u16 peer_id)
2563 DSTACK(__FUNCTION_NAME);
2565 PlayerSAO *playersao = getPlayerSAO(peer_id);
2568 infostream << "Server::RespawnPlayer(): Player "
2569 << playersao->getPlayer()->getName()
2570 << " respawns" << std::endl;
2572 playersao->setHP(PLAYER_MAX_HP);
2573 playersao->setBreath(PLAYER_MAX_BREATH);
2575 SendPlayerHP(peer_id);
2576 SendPlayerBreath(peer_id);
2578 bool repositioned = m_script->on_respawnplayer(playersao);
2580 v3f pos = findSpawnPos();
2581 // setPos will send the new position to client
2582 playersao->setPos(pos);
2587 void Server::DenySudoAccess(u16 peer_id)
2589 DSTACK(__FUNCTION_NAME);
2591 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2596 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2597 const std::string &str_reason, bool reconnect)
2599 if (proto_ver >= 25) {
2600 SendAccessDenied(peer_id, reason, str_reason);
2602 std::wstring wreason = utf8_to_wide(
2603 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2604 accessDeniedStrings[(u8)reason]);
2605 SendAccessDenied_Legacy(peer_id, wreason);
2608 m_clients.event(peer_id, CSE_SetDenied);
2609 m_con.DisconnectPeer(peer_id);
2613 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2615 DSTACK(__FUNCTION_NAME);
2617 SendAccessDenied(peer_id, reason, custom_reason);
2618 m_clients.event(peer_id, CSE_SetDenied);
2619 m_con.DisconnectPeer(peer_id);
2622 // 13/03/15: remove this function when protocol version 25 will become
2623 // the minimum version for MT users, maybe in 1 year
2624 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2626 DSTACK(__FUNCTION_NAME);
2628 SendAccessDenied_Legacy(peer_id, reason);
2629 m_clients.event(peer_id, CSE_SetDenied);
2630 m_con.DisconnectPeer(peer_id);
2633 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2635 DSTACK(__FUNCTION_NAME);
2638 RemoteClient* client = getClient(peer_id, CS_Invalid);
2640 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2642 // Right now, the auth mechs don't change between login and sudo mode.
2643 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2644 client->allowed_sudo_mechs = sudo_auth_mechs;
2646 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2647 << g_settings->getFloat("dedicated_server_step")
2651 m_clients.event(peer_id, CSE_AuthAccept);
2653 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2655 // We only support SRP right now
2656 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2658 resp_pkt << sudo_auth_mechs;
2660 m_clients.event(peer_id, CSE_SudoSuccess);
2664 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2666 DSTACK(__FUNCTION_NAME);
2667 std::wstring message;
2670 Clear references to playing sounds
2672 for(std::map<s32, ServerPlayingSound>::iterator
2673 i = m_playing_sounds.begin();
2674 i != m_playing_sounds.end();)
2676 ServerPlayingSound &psound = i->second;
2677 psound.clients.erase(peer_id);
2678 if(psound.clients.empty())
2679 m_playing_sounds.erase(i++);
2684 Player *player = m_env->getPlayer(peer_id);
2686 // Collect information about leaving in chat
2688 if(player != NULL && reason != CDR_DENY)
2690 std::wstring name = narrow_to_wide(player->getName());
2693 message += L" left the game.";
2694 if(reason == CDR_TIMEOUT)
2695 message += L" (timed out)";
2699 /* Run scripts and remove from environment */
2703 PlayerSAO *playersao = player->getPlayerSAO();
2706 m_script->on_leaveplayer(playersao);
2708 playersao->disconnected();
2716 if(player != NULL && reason != CDR_DENY) {
2717 std::ostringstream os(std::ios_base::binary);
2718 std::vector<u16> clients = m_clients.getClientIDs();
2720 for(std::vector<u16>::iterator i = clients.begin();
2721 i != clients.end(); ++i) {
2723 Player *player = m_env->getPlayer(*i);
2727 // Get name of player
2728 os << player->getName() << " ";
2731 actionstream << player->getName() << " "
2732 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2733 << " List of players: " << os.str() << std::endl;
2737 JMutexAutoLock env_lock(m_env_mutex);
2738 m_clients.DeleteClient(peer_id);
2742 // Send leave chat message to all remaining clients
2743 if(message.length() != 0)
2744 SendChatMessage(PEER_ID_INEXISTENT,message);
2747 void Server::UpdateCrafting(Player* player)
2749 DSTACK(__FUNCTION_NAME);
2751 // Get a preview for crafting
2753 InventoryLocation loc;
2754 loc.setPlayer(player->getName());
2755 std::vector<ItemStack> output_replacements;
2756 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2757 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2759 // Put the new preview in
2760 InventoryList *plist = player->inventory.getList("craftpreview");
2761 sanity_check(plist);
2762 sanity_check(plist->getSize() >= 1);
2763 plist->changeItem(0, preview);
2766 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2768 RemoteClient *client = getClientNoEx(peer_id,state_min);
2770 throw ClientNotFoundException("Client not found");
2774 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2776 return m_clients.getClientNoEx(peer_id, state_min);
2779 std::string Server::getPlayerName(u16 peer_id)
2781 Player *player = m_env->getPlayer(peer_id);
2783 return "[id="+itos(peer_id)+"]";
2784 return player->getName();
2787 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2789 Player *player = m_env->getPlayer(peer_id);
2792 return player->getPlayerSAO();
2795 std::wstring Server::getStatusString()
2797 std::wostringstream os(std::ios_base::binary);
2800 os<<L"version="<<narrow_to_wide(g_version_string);
2802 os<<L", uptime="<<m_uptime.get();
2804 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2805 // Information about clients
2808 std::vector<u16> clients = m_clients.getClientIDs();
2809 for(std::vector<u16>::iterator i = clients.begin();
2810 i != clients.end(); ++i) {
2812 Player *player = m_env->getPlayer(*i);
2813 // Get name of player
2814 std::wstring name = L"unknown";
2816 name = narrow_to_wide(player->getName());
2817 // Add name to information string
2825 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2826 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2827 if(g_settings->get("motd") != "")
2828 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2832 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2834 std::set<std::string> privs;
2835 m_script->getAuth(name, NULL, &privs);
2839 bool Server::checkPriv(const std::string &name, const std::string &priv)
2841 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2842 return (privs.count(priv) != 0);
2845 void Server::reportPrivsModified(const std::string &name)
2848 std::vector<u16> clients = m_clients.getClientIDs();
2849 for(std::vector<u16>::iterator i = clients.begin();
2850 i != clients.end(); ++i) {
2851 Player *player = m_env->getPlayer(*i);
2852 reportPrivsModified(player->getName());
2855 Player *player = m_env->getPlayer(name.c_str());
2858 SendPlayerPrivileges(player->peer_id);
2859 PlayerSAO *sao = player->getPlayerSAO();
2862 sao->updatePrivileges(
2863 getPlayerEffectivePrivs(name),
2868 void Server::reportInventoryFormspecModified(const std::string &name)
2870 Player *player = m_env->getPlayer(name.c_str());
2873 SendPlayerInventoryFormspec(player->peer_id);
2876 void Server::setIpBanned(const std::string &ip, const std::string &name)
2878 m_banmanager->add(ip, name);
2881 void Server::unsetIpBanned(const std::string &ip_or_name)
2883 m_banmanager->remove(ip_or_name);
2886 std::string Server::getBanDescription(const std::string &ip_or_name)
2888 return m_banmanager->getBanDescription(ip_or_name);
2891 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2893 Player *player = m_env->getPlayer(name);
2897 if (player->peer_id == PEER_ID_INEXISTENT)
2900 SendChatMessage(player->peer_id, msg);
2903 bool Server::showFormspec(const char *playername, const std::string &formspec,
2904 const std::string &formname)
2906 Player *player = m_env->getPlayer(playername);
2910 SendShowFormspecMessage(player->peer_id, formspec, formname);
2914 u32 Server::hudAdd(Player *player, HudElement *form)
2919 u32 id = player->addHud(form);
2921 SendHUDAdd(player->peer_id, id, form);
2926 bool Server::hudRemove(Player *player, u32 id) {
2930 HudElement* todel = player->removeHud(id);
2937 SendHUDRemove(player->peer_id, id);
2941 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2946 SendHUDChange(player->peer_id, id, stat, data);
2950 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2955 SendHUDSetFlags(player->peer_id, flags, mask);
2956 player->hud_flags = flags;
2958 PlayerSAO* playersao = player->getPlayerSAO();
2960 if (playersao == NULL)
2963 m_script->player_event(playersao, "hud_changed");
2967 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2971 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2974 player->setHotbarItemcount(hotbar_itemcount);
2975 std::ostringstream os(std::ios::binary);
2976 writeS32(os, hotbar_itemcount);
2977 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2981 s32 Server::hudGetHotbarItemcount(Player *player)
2985 return player->getHotbarItemcount();
2988 void Server::hudSetHotbarImage(Player *player, std::string name)
2993 player->setHotbarImage(name);
2994 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2997 std::string Server::hudGetHotbarImage(Player *player)
3001 return player->getHotbarImage();
3004 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3009 player->setHotbarSelectedImage(name);
3010 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3013 std::string Server::hudGetHotbarSelectedImage(Player *player)
3018 return player->getHotbarSelectedImage();
3021 bool Server::setLocalPlayerAnimations(Player *player,
3022 v2s32 animation_frames[4], f32 frame_speed)
3027 player->setLocalAnimations(animation_frames, frame_speed);
3028 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3032 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3037 player->eye_offset_first = first;
3038 player->eye_offset_third = third;
3039 SendEyeOffset(player->peer_id, first, third);
3043 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3044 const std::string &type, const std::vector<std::string> ¶ms)
3049 player->setSky(bgcolor, type, params);
3050 SendSetSky(player->peer_id, bgcolor, type, params);
3054 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3060 player->overrideDayNightRatio(do_override, ratio);
3061 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3065 void Server::notifyPlayers(const std::wstring &msg)
3067 SendChatMessage(PEER_ID_INEXISTENT,msg);
3070 void Server::spawnParticle(const char *playername, v3f pos,
3071 v3f velocity, v3f acceleration,
3072 float expirationtime, float size, bool
3073 collisiondetection, bool vertical, const std::string &texture)
3075 Player *player = m_env->getPlayer(playername);
3078 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3079 expirationtime, size, collisiondetection, vertical, texture);
3082 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3083 float expirationtime, float size,
3084 bool collisiondetection, bool vertical, const std::string &texture)
3086 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3087 expirationtime, size, collisiondetection, vertical, texture);
3090 u32 Server::addParticleSpawner(const char *playername, u16 amount, float spawntime,
3091 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3092 float minexptime, float maxexptime, float minsize, float maxsize,
3093 bool collisiondetection, bool vertical, const std::string &texture)
3095 Player *player = m_env->getPlayer(playername);
3100 for(;;) // look for unused particlespawner id
3103 if (std::find(m_particlespawner_ids.begin(),
3104 m_particlespawner_ids.end(), id)
3105 == m_particlespawner_ids.end())
3107 m_particlespawner_ids.push_back(id);
3112 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3113 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3114 minexptime, maxexptime, minsize, maxsize,
3115 collisiondetection, vertical, texture, id);
3120 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3121 v3f minpos, v3f maxpos,
3122 v3f minvel, v3f maxvel,
3123 v3f minacc, v3f maxacc,
3124 float minexptime, float maxexptime,
3125 float minsize, float maxsize,
3126 bool collisiondetection, bool vertical, const std::string &texture)
3129 for(;;) // look for unused particlespawner id
3132 if (std::find(m_particlespawner_ids.begin(),
3133 m_particlespawner_ids.end(), id)
3134 == m_particlespawner_ids.end())
3136 m_particlespawner_ids.push_back(id);
3141 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3142 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3143 minexptime, maxexptime, minsize, maxsize,
3144 collisiondetection, vertical, texture, id);
3149 void Server::deleteParticleSpawner(const char *playername, u32 id)
3151 Player *player = m_env->getPlayer(playername);
3155 m_particlespawner_ids.erase(
3156 std::remove(m_particlespawner_ids.begin(),
3157 m_particlespawner_ids.end(), id),
3158 m_particlespawner_ids.end());
3159 SendDeleteParticleSpawner(player->peer_id, id);
3162 void Server::deleteParticleSpawnerAll(u32 id)
3164 m_particlespawner_ids.erase(
3165 std::remove(m_particlespawner_ids.begin(),
3166 m_particlespawner_ids.end(), id),
3167 m_particlespawner_ids.end());
3168 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3171 Inventory* Server::createDetachedInventory(const std::string &name)
3173 if(m_detached_inventories.count(name) > 0){
3174 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3175 delete m_detached_inventories[name];
3177 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3179 Inventory *inv = new Inventory(m_itemdef);
3181 m_detached_inventories[name] = inv;
3182 //TODO find a better way to do this
3183 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3187 // actions: time-reversed list
3188 // Return value: success/failure
3189 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3190 std::list<std::string> *log)
3192 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3193 ServerMap *map = (ServerMap*)(&m_env->getMap());
3195 // Fail if no actions to handle
3196 if(actions.empty()){
3197 log->push_back("Nothing to do.");
3204 for(std::list<RollbackAction>::const_iterator
3205 i = actions.begin();
3206 i != actions.end(); i++)
3208 const RollbackAction &action = *i;
3210 bool success = action.applyRevert(map, this, this);
3213 std::ostringstream os;
3214 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3215 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3217 log->push_back(os.str());
3219 std::ostringstream os;
3220 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3221 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3223 log->push_back(os.str());
3227 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3228 <<" failed"<<std::endl;
3230 // Call it done if less than half failed
3231 return num_failed <= num_tried/2;
3234 // IGameDef interface
3236 IItemDefManager *Server::getItemDefManager()
3241 INodeDefManager *Server::getNodeDefManager()
3246 ICraftDefManager *Server::getCraftDefManager()
3250 ITextureSource *Server::getTextureSource()
3254 IShaderSource *Server::getShaderSource()
3258 scene::ISceneManager *Server::getSceneManager()
3263 u16 Server::allocateUnknownNodeId(const std::string &name)
3265 return m_nodedef->allocateDummy(name);
3268 ISoundManager *Server::getSoundManager()
3270 return &dummySoundManager;
3273 MtEventManager *Server::getEventManager()
3278 IWritableItemDefManager *Server::getWritableItemDefManager()
3283 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3288 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3293 const ModSpec *Server::getModSpec(const std::string &modname) const
3295 std::vector<ModSpec>::const_iterator it;
3296 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3297 const ModSpec &mod = *it;
3298 if (mod.name == modname)
3304 void Server::getModNames(std::vector<std::string> &modlist)
3306 std::vector<ModSpec>::iterator it;
3307 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3308 modlist.push_back(it->name);
3311 std::string Server::getBuiltinLuaPath()
3313 return porting::path_share + DIR_DELIM + "builtin";
3316 v3f Server::findSpawnPos()
3318 ServerMap &map = m_env->getServerMap();
3320 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3321 return nodeposf * BS;
3324 // Default position is static_spawnpoint
3325 // We will return it if we don't found a good place
3326 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3328 s16 water_level = map.getWaterLevel();
3330 bool is_good = false;
3332 // Try to find a good place a few times
3333 for(s32 i = 0; i < 1000 && !is_good; i++) {
3335 // We're going to try to throw the player to this position
3336 v2s16 nodepos2d = v2s16(
3337 -range + (myrand() % (range * 2)),
3338 -range + (myrand() % (range * 2)));
3340 // Get ground height at point
3341 s16 groundheight = map.findGroundLevel(nodepos2d);
3342 if (groundheight <= water_level) // Don't go underwater
3344 if (groundheight > water_level + 6) // Don't go to high places
3347 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3350 for (s32 i = 0; i < 10; i++) {
3351 v3s16 blockpos = getNodeBlockPos(nodepos);
3352 map.emergeBlock(blockpos, true);
3353 content_t c = map.getNodeNoEx(nodepos).getContent();
3354 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3356 if (air_count >= 2){
3365 return intToFloat(nodepos, BS);
3368 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3370 bool newplayer = false;
3373 Try to get an existing player
3375 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3377 // If player is already connected, cancel
3378 if(player != NULL && player->peer_id != 0)
3380 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3385 If player with the wanted peer_id already exists, cancel.
3387 if(m_env->getPlayer(peer_id) != NULL)
3389 infostream<<"emergePlayer(): Player with wrong name but same"
3390 " peer_id already exists"<<std::endl;
3394 // Load player if it isn't already loaded
3396 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3399 // Create player if it doesn't exist
3402 player = new RemotePlayer(this, name);
3403 // Set player position
3404 infostream<<"Server: Finding spawn place for player \""
3405 <<name<<"\""<<std::endl;
3406 v3f pos = findSpawnPos();
3407 player->setPosition(pos);
3409 // Make sure the player is saved
3410 player->setModified(true);
3412 // Add player to environment
3413 m_env->addPlayer(player);
3416 // Create a new player active object
3417 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3418 getPlayerEffectivePrivs(player->getName()),
3421 player->protocol_version = proto_version;
3423 /* Clean up old HUD elements from previous sessions */
3426 /* Add object to environment */
3427 m_env->addActiveObject(playersao);
3431 m_script->on_newplayer(playersao);
3437 void dedicated_server_loop(Server &server, bool &kill)
3439 DSTACK(__FUNCTION_NAME);
3441 verbosestream<<"dedicated_server_loop()"<<std::endl;
3443 IntervalLimiter m_profiler_interval;
3447 float steplen = g_settings->getFloat("dedicated_server_step");
3448 // This is kind of a hack but can be done like this
3449 // because server.step() is very light
3451 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3452 sleep_ms((int)(steplen*1000.0));
3454 server.step(steplen);
3456 if(server.getShutdownRequested() || kill)
3458 infostream<<"Dedicated server quitting"<<std::endl;
3460 if(g_settings->getBool("server_announce"))
3461 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3469 float profiler_print_interval =
3470 g_settings->getFloat("profiler_print_interval");
3471 if(profiler_print_interval != 0)
3473 if(m_profiler_interval.step(steplen, profiler_print_interval))
3475 infostream<<"Profiler:"<<std::endl;
3476 g_profiler->print(infostream);
3477 g_profiler->clear();