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 void Server::sendMediaAnnouncement(u16 peer_id)
2335 DSTACK(__FUNCTION_NAME);
2337 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2341 std::ostringstream os(std::ios_base::binary);
2343 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2344 pkt << (u16) m_media.size();
2346 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2347 i != m_media.end(); ++i) {
2348 pkt << i->first << i->second.sha1_digest;
2351 pkt << g_settings->get("remote_media");
2355 struct SendableMedia
2361 SendableMedia(const std::string &name_="", const std::string &path_="",
2362 const std::string &data_=""):
2369 void Server::sendRequestedMedia(u16 peer_id,
2370 const std::vector<std::string> &tosend)
2372 DSTACK(__FUNCTION_NAME);
2374 verbosestream<<"Server::sendRequestedMedia(): "
2375 <<"Sending files to client"<<std::endl;
2379 // Put 5kB in one bunch (this is not accurate)
2380 u32 bytes_per_bunch = 5000;
2382 std::vector< std::vector<SendableMedia> > file_bunches;
2383 file_bunches.push_back(std::vector<SendableMedia>());
2385 u32 file_size_bunch_total = 0;
2387 for(std::vector<std::string>::const_iterator i = tosend.begin();
2388 i != tosend.end(); ++i) {
2389 const std::string &name = *i;
2391 if(m_media.find(name) == m_media.end()) {
2392 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2393 <<"unknown file \""<<(name)<<"\""<<std::endl;
2397 //TODO get path + name
2398 std::string tpath = m_media[name].path;
2401 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2402 if(fis.good() == false){
2403 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2404 <<tpath<<"\" for reading"<<std::endl;
2407 std::ostringstream tmp_os(std::ios_base::binary);
2411 fis.read(buf, 1024);
2412 std::streamsize len = fis.gcount();
2413 tmp_os.write(buf, len);
2414 file_size_bunch_total += len;
2423 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2424 <<name<<"\""<<std::endl;
2427 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2428 <<tname<<"\""<<std::endl;*/
2430 file_bunches[file_bunches.size()-1].push_back(
2431 SendableMedia(name, tpath, tmp_os.str()));
2433 // Start next bunch if got enough data
2434 if(file_size_bunch_total >= bytes_per_bunch) {
2435 file_bunches.push_back(std::vector<SendableMedia>());
2436 file_size_bunch_total = 0;
2441 /* Create and send packets */
2443 u16 num_bunches = file_bunches.size();
2444 for(u16 i = 0; i < num_bunches; i++) {
2447 u16 total number of texture bunches
2448 u16 index of this bunch
2449 u32 number of files in this bunch
2458 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2459 pkt << num_bunches << i << (u32) file_bunches[i].size();
2461 for(std::vector<SendableMedia>::iterator
2462 j = file_bunches[i].begin();
2463 j != file_bunches[i].end(); ++j) {
2465 pkt.putLongString(j->data);
2468 verbosestream << "Server::sendRequestedMedia(): bunch "
2469 << i << "/" << num_bunches
2470 << " files=" << file_bunches[i].size()
2471 << " size=" << pkt.getSize() << std::endl;
2476 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2478 if(m_detached_inventories.count(name) == 0) {
2479 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2482 Inventory *inv = m_detached_inventories[name];
2483 std::ostringstream os(std::ios_base::binary);
2485 os << serializeString(name);
2489 std::string s = os.str();
2491 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2492 pkt.putRawString(s.c_str(), s.size());
2494 if (peer_id != PEER_ID_INEXISTENT) {
2498 m_clients.sendToAll(0, &pkt, true);
2502 void Server::sendDetachedInventories(u16 peer_id)
2504 DSTACK(__FUNCTION_NAME);
2506 for(std::map<std::string, Inventory*>::iterator
2507 i = m_detached_inventories.begin();
2508 i != m_detached_inventories.end(); i++) {
2509 const std::string &name = i->first;
2510 //Inventory *inv = i->second;
2511 sendDetachedInventory(name, peer_id);
2519 void Server::DiePlayer(u16 peer_id)
2521 DSTACK(__FUNCTION_NAME);
2523 PlayerSAO *playersao = getPlayerSAO(peer_id);
2526 infostream << "Server::DiePlayer(): Player "
2527 << playersao->getPlayer()->getName()
2528 << " dies" << std::endl;
2530 playersao->setHP(0);
2532 // Trigger scripted stuff
2533 m_script->on_dieplayer(playersao);
2535 SendPlayerHP(peer_id);
2536 SendDeathscreen(peer_id, false, v3f(0,0,0));
2539 void Server::RespawnPlayer(u16 peer_id)
2541 DSTACK(__FUNCTION_NAME);
2543 PlayerSAO *playersao = getPlayerSAO(peer_id);
2546 infostream << "Server::RespawnPlayer(): Player "
2547 << playersao->getPlayer()->getName()
2548 << " respawns" << std::endl;
2550 playersao->setHP(PLAYER_MAX_HP);
2551 playersao->setBreath(PLAYER_MAX_BREATH);
2553 SendPlayerHP(peer_id);
2554 SendPlayerBreath(peer_id);
2556 bool repositioned = m_script->on_respawnplayer(playersao);
2558 v3f pos = findSpawnPos();
2559 // setPos will send the new position to client
2560 playersao->setPos(pos);
2565 void Server::DenySudoAccess(u16 peer_id)
2567 DSTACK(__FUNCTION_NAME);
2569 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2574 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2575 const std::string &str_reason, bool reconnect)
2577 if (proto_ver >= 25) {
2578 SendAccessDenied(peer_id, reason, str_reason);
2580 std::wstring wreason = utf8_to_wide(
2581 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2582 accessDeniedStrings[(u8)reason]);
2583 SendAccessDenied_Legacy(peer_id, wreason);
2586 m_clients.event(peer_id, CSE_SetDenied);
2587 m_con.DisconnectPeer(peer_id);
2591 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2593 DSTACK(__FUNCTION_NAME);
2595 SendAccessDenied(peer_id, reason, custom_reason);
2596 m_clients.event(peer_id, CSE_SetDenied);
2597 m_con.DisconnectPeer(peer_id);
2600 // 13/03/15: remove this function when protocol version 25 will become
2601 // the minimum version for MT users, maybe in 1 year
2602 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2604 DSTACK(__FUNCTION_NAME);
2606 SendAccessDenied_Legacy(peer_id, reason);
2607 m_clients.event(peer_id, CSE_SetDenied);
2608 m_con.DisconnectPeer(peer_id);
2611 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2613 DSTACK(__FUNCTION_NAME);
2616 RemoteClient* client = getClient(peer_id, CS_Invalid);
2618 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2620 // Right now, the auth mechs don't change between login and sudo mode.
2621 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2622 client->allowed_sudo_mechs = sudo_auth_mechs;
2624 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2625 << g_settings->getFloat("dedicated_server_step")
2629 m_clients.event(peer_id, CSE_AuthAccept);
2631 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2633 // We only support SRP right now
2634 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2636 resp_pkt << sudo_auth_mechs;
2638 m_clients.event(peer_id, CSE_SudoSuccess);
2642 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2644 DSTACK(__FUNCTION_NAME);
2645 std::wstring message;
2648 Clear references to playing sounds
2650 for(std::map<s32, ServerPlayingSound>::iterator
2651 i = m_playing_sounds.begin();
2652 i != m_playing_sounds.end();)
2654 ServerPlayingSound &psound = i->second;
2655 psound.clients.erase(peer_id);
2656 if(psound.clients.empty())
2657 m_playing_sounds.erase(i++);
2662 Player *player = m_env->getPlayer(peer_id);
2664 // Collect information about leaving in chat
2666 if(player != NULL && reason != CDR_DENY)
2668 std::wstring name = narrow_to_wide(player->getName());
2671 message += L" left the game.";
2672 if(reason == CDR_TIMEOUT)
2673 message += L" (timed out)";
2677 /* Run scripts and remove from environment */
2681 PlayerSAO *playersao = player->getPlayerSAO();
2684 m_script->on_leaveplayer(playersao);
2686 playersao->disconnected();
2694 if(player != NULL && reason != CDR_DENY) {
2695 std::ostringstream os(std::ios_base::binary);
2696 std::vector<u16> clients = m_clients.getClientIDs();
2698 for(std::vector<u16>::iterator i = clients.begin();
2699 i != clients.end(); ++i) {
2701 Player *player = m_env->getPlayer(*i);
2705 // Get name of player
2706 os << player->getName() << " ";
2709 actionstream << player->getName() << " "
2710 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2711 << " List of players: " << os.str() << std::endl;
2715 JMutexAutoLock env_lock(m_env_mutex);
2716 m_clients.DeleteClient(peer_id);
2720 // Send leave chat message to all remaining clients
2721 if(message.length() != 0)
2722 SendChatMessage(PEER_ID_INEXISTENT,message);
2725 void Server::UpdateCrafting(Player* player)
2727 DSTACK(__FUNCTION_NAME);
2729 // Get a preview for crafting
2731 InventoryLocation loc;
2732 loc.setPlayer(player->getName());
2733 std::vector<ItemStack> output_replacements;
2734 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2735 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2737 // Put the new preview in
2738 InventoryList *plist = player->inventory.getList("craftpreview");
2739 sanity_check(plist);
2740 sanity_check(plist->getSize() >= 1);
2741 plist->changeItem(0, preview);
2744 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2746 RemoteClient *client = getClientNoEx(peer_id,state_min);
2748 throw ClientNotFoundException("Client not found");
2752 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2754 return m_clients.getClientNoEx(peer_id, state_min);
2757 std::string Server::getPlayerName(u16 peer_id)
2759 Player *player = m_env->getPlayer(peer_id);
2761 return "[id="+itos(peer_id)+"]";
2762 return player->getName();
2765 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2767 Player *player = m_env->getPlayer(peer_id);
2770 return player->getPlayerSAO();
2773 std::wstring Server::getStatusString()
2775 std::wostringstream os(std::ios_base::binary);
2778 os<<L"version="<<narrow_to_wide(g_version_string);
2780 os<<L", uptime="<<m_uptime.get();
2782 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2783 // Information about clients
2786 std::vector<u16> clients = m_clients.getClientIDs();
2787 for(std::vector<u16>::iterator i = clients.begin();
2788 i != clients.end(); ++i) {
2790 Player *player = m_env->getPlayer(*i);
2791 // Get name of player
2792 std::wstring name = L"unknown";
2794 name = narrow_to_wide(player->getName());
2795 // Add name to information string
2803 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2804 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2805 if(g_settings->get("motd") != "")
2806 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2810 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2812 std::set<std::string> privs;
2813 m_script->getAuth(name, NULL, &privs);
2817 bool Server::checkPriv(const std::string &name, const std::string &priv)
2819 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2820 return (privs.count(priv) != 0);
2823 void Server::reportPrivsModified(const std::string &name)
2826 std::vector<u16> clients = m_clients.getClientIDs();
2827 for(std::vector<u16>::iterator i = clients.begin();
2828 i != clients.end(); ++i) {
2829 Player *player = m_env->getPlayer(*i);
2830 reportPrivsModified(player->getName());
2833 Player *player = m_env->getPlayer(name.c_str());
2836 SendPlayerPrivileges(player->peer_id);
2837 PlayerSAO *sao = player->getPlayerSAO();
2840 sao->updatePrivileges(
2841 getPlayerEffectivePrivs(name),
2846 void Server::reportInventoryFormspecModified(const std::string &name)
2848 Player *player = m_env->getPlayer(name.c_str());
2851 SendPlayerInventoryFormspec(player->peer_id);
2854 void Server::setIpBanned(const std::string &ip, const std::string &name)
2856 m_banmanager->add(ip, name);
2859 void Server::unsetIpBanned(const std::string &ip_or_name)
2861 m_banmanager->remove(ip_or_name);
2864 std::string Server::getBanDescription(const std::string &ip_or_name)
2866 return m_banmanager->getBanDescription(ip_or_name);
2869 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2871 Player *player = m_env->getPlayer(name);
2875 if (player->peer_id == PEER_ID_INEXISTENT)
2878 SendChatMessage(player->peer_id, msg);
2881 bool Server::showFormspec(const char *playername, const std::string &formspec,
2882 const std::string &formname)
2884 Player *player = m_env->getPlayer(playername);
2888 SendShowFormspecMessage(player->peer_id, formspec, formname);
2892 u32 Server::hudAdd(Player *player, HudElement *form)
2897 u32 id = player->addHud(form);
2899 SendHUDAdd(player->peer_id, id, form);
2904 bool Server::hudRemove(Player *player, u32 id) {
2908 HudElement* todel = player->removeHud(id);
2915 SendHUDRemove(player->peer_id, id);
2919 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2924 SendHUDChange(player->peer_id, id, stat, data);
2928 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2933 SendHUDSetFlags(player->peer_id, flags, mask);
2934 player->hud_flags = flags;
2936 PlayerSAO* playersao = player->getPlayerSAO();
2938 if (playersao == NULL)
2941 m_script->player_event(playersao, "hud_changed");
2945 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2949 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2952 player->setHotbarItemcount(hotbar_itemcount);
2953 std::ostringstream os(std::ios::binary);
2954 writeS32(os, hotbar_itemcount);
2955 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2959 s32 Server::hudGetHotbarItemcount(Player *player)
2963 return player->getHotbarItemcount();
2966 void Server::hudSetHotbarImage(Player *player, std::string name)
2971 player->setHotbarImage(name);
2972 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2975 std::string Server::hudGetHotbarImage(Player *player)
2979 return player->getHotbarImage();
2982 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2987 player->setHotbarSelectedImage(name);
2988 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2991 std::string Server::hudGetHotbarSelectedImage(Player *player)
2996 return player->getHotbarSelectedImage();
2999 bool Server::setLocalPlayerAnimations(Player *player,
3000 v2s32 animation_frames[4], f32 frame_speed)
3005 player->setLocalAnimations(animation_frames, frame_speed);
3006 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3010 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3015 player->eye_offset_first = first;
3016 player->eye_offset_third = third;
3017 SendEyeOffset(player->peer_id, first, third);
3021 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3022 const std::string &type, const std::vector<std::string> ¶ms)
3027 player->setSky(bgcolor, type, params);
3028 SendSetSky(player->peer_id, bgcolor, type, params);
3032 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3038 player->overrideDayNightRatio(do_override, ratio);
3039 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3043 void Server::notifyPlayers(const std::wstring &msg)
3045 SendChatMessage(PEER_ID_INEXISTENT,msg);
3048 void Server::spawnParticle(const std::string &playername, v3f pos,
3049 v3f velocity, v3f acceleration,
3050 float expirationtime, float size, bool
3051 collisiondetection, bool vertical, const std::string &texture)
3053 u16 peer_id = PEER_ID_INEXISTENT;
3054 if (playername != "") {
3055 Player* player = m_env->getPlayer(playername.c_str());
3058 peer_id = player->peer_id;
3061 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3062 expirationtime, size, collisiondetection, vertical, texture);
3065 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3066 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3067 float minexptime, float maxexptime, float minsize, float maxsize,
3068 bool collisiondetection, bool vertical, const std::string &texture,
3069 const std::string &playername)
3071 u16 peer_id = PEER_ID_INEXISTENT;
3072 if (playername != "") {
3073 Player* player = m_env->getPlayer(playername.c_str());
3076 peer_id = player->peer_id;
3080 for(;;) // look for unused particlespawner id
3083 if (std::find(m_particlespawner_ids.begin(),
3084 m_particlespawner_ids.end(), id)
3085 == m_particlespawner_ids.end())
3087 m_particlespawner_ids.push_back(id);
3092 SendAddParticleSpawner(peer_id, amount, spawntime,
3093 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3094 minexptime, maxexptime, minsize, maxsize,
3095 collisiondetection, vertical, texture, id);
3100 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3102 u16 peer_id = PEER_ID_INEXISTENT;
3103 if (playername != "") {
3104 Player* player = m_env->getPlayer(playername.c_str());
3107 peer_id = player->peer_id;
3110 m_particlespawner_ids.erase(
3111 std::remove(m_particlespawner_ids.begin(),
3112 m_particlespawner_ids.end(), id),
3113 m_particlespawner_ids.end());
3114 SendDeleteParticleSpawner(peer_id, id);
3117 Inventory* Server::createDetachedInventory(const std::string &name)
3119 if(m_detached_inventories.count(name) > 0){
3120 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3121 delete m_detached_inventories[name];
3123 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3125 Inventory *inv = new Inventory(m_itemdef);
3127 m_detached_inventories[name] = inv;
3128 //TODO find a better way to do this
3129 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3133 // actions: time-reversed list
3134 // Return value: success/failure
3135 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3136 std::list<std::string> *log)
3138 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3139 ServerMap *map = (ServerMap*)(&m_env->getMap());
3141 // Fail if no actions to handle
3142 if(actions.empty()){
3143 log->push_back("Nothing to do.");
3150 for(std::list<RollbackAction>::const_iterator
3151 i = actions.begin();
3152 i != actions.end(); i++)
3154 const RollbackAction &action = *i;
3156 bool success = action.applyRevert(map, this, this);
3159 std::ostringstream os;
3160 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3161 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3163 log->push_back(os.str());
3165 std::ostringstream os;
3166 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3167 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3169 log->push_back(os.str());
3173 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3174 <<" failed"<<std::endl;
3176 // Call it done if less than half failed
3177 return num_failed <= num_tried/2;
3180 // IGameDef interface
3182 IItemDefManager *Server::getItemDefManager()
3187 INodeDefManager *Server::getNodeDefManager()
3192 ICraftDefManager *Server::getCraftDefManager()
3196 ITextureSource *Server::getTextureSource()
3200 IShaderSource *Server::getShaderSource()
3204 scene::ISceneManager *Server::getSceneManager()
3209 u16 Server::allocateUnknownNodeId(const std::string &name)
3211 return m_nodedef->allocateDummy(name);
3214 ISoundManager *Server::getSoundManager()
3216 return &dummySoundManager;
3219 MtEventManager *Server::getEventManager()
3224 IWritableItemDefManager *Server::getWritableItemDefManager()
3229 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3234 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3239 const ModSpec *Server::getModSpec(const std::string &modname) const
3241 std::vector<ModSpec>::const_iterator it;
3242 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3243 const ModSpec &mod = *it;
3244 if (mod.name == modname)
3250 void Server::getModNames(std::vector<std::string> &modlist)
3252 std::vector<ModSpec>::iterator it;
3253 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3254 modlist.push_back(it->name);
3257 std::string Server::getBuiltinLuaPath()
3259 return porting::path_share + DIR_DELIM + "builtin";
3262 v3f Server::findSpawnPos()
3264 ServerMap &map = m_env->getServerMap();
3266 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3267 return nodeposf * BS;
3270 // Default position is static_spawnpoint
3271 // We will return it if we don't found a good place
3272 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3274 s16 water_level = map.getWaterLevel();
3276 bool is_good = false;
3278 // Try to find a good place a few times
3279 for(s32 i = 0; i < 1000 && !is_good; i++) {
3281 // We're going to try to throw the player to this position
3282 v2s16 nodepos2d = v2s16(
3283 -range + (myrand() % (range * 2)),
3284 -range + (myrand() % (range * 2)));
3286 // Get ground height at point
3287 s16 groundheight = map.findGroundLevel(nodepos2d);
3288 if (groundheight <= water_level) // Don't go underwater
3290 if (groundheight > water_level + 6) // Don't go to high places
3293 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3296 for (s32 i = 0; i < 10; i++) {
3297 v3s16 blockpos = getNodeBlockPos(nodepos);
3298 map.emergeBlock(blockpos, true);
3299 content_t c = map.getNodeNoEx(nodepos).getContent();
3300 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3302 if (air_count >= 2){
3311 return intToFloat(nodepos, BS);
3314 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3316 bool newplayer = false;
3319 Try to get an existing player
3321 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3323 // If player is already connected, cancel
3324 if(player != NULL && player->peer_id != 0)
3326 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3331 If player with the wanted peer_id already exists, cancel.
3333 if(m_env->getPlayer(peer_id) != NULL)
3335 infostream<<"emergePlayer(): Player with wrong name but same"
3336 " peer_id already exists"<<std::endl;
3340 // Load player if it isn't already loaded
3342 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3345 // Create player if it doesn't exist
3348 player = new RemotePlayer(this, name);
3349 // Set player position
3350 infostream<<"Server: Finding spawn place for player \""
3351 <<name<<"\""<<std::endl;
3352 v3f pos = findSpawnPos();
3353 player->setPosition(pos);
3355 // Make sure the player is saved
3356 player->setModified(true);
3358 // Add player to environment
3359 m_env->addPlayer(player);
3362 // Create a new player active object
3363 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3364 getPlayerEffectivePrivs(player->getName()),
3367 player->protocol_version = proto_version;
3369 /* Clean up old HUD elements from previous sessions */
3372 /* Add object to environment */
3373 m_env->addActiveObject(playersao);
3377 m_script->on_newplayer(playersao);
3383 void dedicated_server_loop(Server &server, bool &kill)
3385 DSTACK(__FUNCTION_NAME);
3387 verbosestream<<"dedicated_server_loop()"<<std::endl;
3389 IntervalLimiter m_profiler_interval;
3393 float steplen = g_settings->getFloat("dedicated_server_step");
3394 // This is kind of a hack but can be done like this
3395 // because server.step() is very light
3397 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3398 sleep_ms((int)(steplen*1000.0));
3400 server.step(steplen);
3402 if(server.getShutdownRequested() || kill)
3404 infostream<<"Dedicated server quitting"<<std::endl;
3406 if(g_settings->getBool("server_announce"))
3407 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3415 float profiler_print_interval =
3416 g_settings->getFloat("profiler_print_interval");
3417 if(profiler_print_interval != 0)
3419 if(m_profiler_interval.step(steplen, profiler_print_interval))
3421 infostream<<"Profiler:"<<std::endl;
3422 g_profiler->print(infostream);
3423 g_profiler->clear();