3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(__FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER(errorstream)
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
153 m_path_world(path_world),
154 m_gamespec(gamespec),
155 m_simple_singleplayer_mode(simple_singleplayer_mode),
156 m_async_fatal_error(""),
165 m_enable_rollback_recording(false),
168 m_itemdef(createItemDefManager()),
169 m_nodedef(createNodeDefManager()),
170 m_craftdef(createCraftDefManager()),
171 m_event(new EventManager()),
173 m_time_of_day_send_timer(0),
176 m_shutdown_requested(false),
177 m_shutdown_ask_reconnect(false),
178 m_ignore_map_edit_events(false),
179 m_ignore_map_edit_events_peer_id(0),
183 m_liquid_transform_timer = 0.0;
184 m_liquid_transform_every = 1.0;
185 m_print_info_timer = 0.0;
186 m_masterserver_timer = 0.0;
187 m_objectdata_timer = 0.0;
188 m_emergethread_trigger_timer = 0.0;
189 m_savemap_timer = 0.0;
192 m_lag = g_settings->getFloat("dedicated_server_step");
195 throw ServerError("Supplied empty world path");
197 if(!gamespec.isValid())
198 throw ServerError("Supplied invalid gamespec");
200 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
201 if(m_simple_singleplayer_mode)
202 infostream<<" in simple singleplayer mode"<<std::endl;
204 infostream<<std::endl;
205 infostream<<"- world: "<<m_path_world<<std::endl;
206 infostream<<"- game: "<<m_gamespec.path<<std::endl;
208 // Create world if it doesn't exist
209 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
210 throw ServerError("Failed to initialize world");
212 // Create server thread
213 m_thread = new ServerThread(this);
215 // Create emerge manager
216 m_emerge = new EmergeManager(this);
218 // Create ban manager
219 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
220 m_banmanager = new BanManager(ban_path);
222 ModConfiguration modconf(m_path_world);
223 m_mods = modconf.getMods();
224 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
225 // complain about mods with unsatisfied dependencies
226 if(!modconf.isConsistent()) {
227 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
228 it != unsatisfied_mods.end(); ++it) {
230 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
231 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
232 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
233 errorstream << " \"" << *dep_it << "\"";
234 errorstream << std::endl;
238 Settings worldmt_settings;
239 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
240 worldmt_settings.readConfigFile(worldmt.c_str());
241 std::vector<std::string> names = worldmt_settings.getNames();
242 std::set<std::string> load_mod_names;
243 for(std::vector<std::string>::iterator it = names.begin();
244 it != names.end(); ++it) {
245 std::string name = *it;
246 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
247 load_mod_names.insert(name.substr(9));
249 // complain about mods declared to be loaded, but not found
250 for(std::vector<ModSpec>::iterator it = m_mods.begin();
251 it != m_mods.end(); ++it)
252 load_mod_names.erase((*it).name);
253 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
254 it != unsatisfied_mods.end(); ++it)
255 load_mod_names.erase((*it).name);
256 if(!load_mod_names.empty()) {
257 errorstream << "The following mods could not be found:";
258 for(std::set<std::string>::iterator it = load_mod_names.begin();
259 it != load_mod_names.end(); ++it)
260 errorstream << " \"" << (*it) << "\"";
261 errorstream << std::endl;
265 MutexAutoLock envlock(m_env_mutex);
267 // Load mapgen params from Settings
268 m_emerge->loadMapgenParams();
270 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
271 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
273 // Initialize scripting
274 infostream<<"Server: Initializing Lua"<<std::endl;
276 m_script = new GameScripting(this);
278 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
279 std::string error_msg;
281 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
282 throw ModError("Failed to load and run " + script_path
283 + "\nError from Lua:\n" + error_msg);
286 infostream << "Server: Loading mods: ";
287 for(std::vector<ModSpec>::iterator i = m_mods.begin();
288 i != m_mods.end(); i++) {
289 const ModSpec &mod = *i;
290 infostream << mod.name << " ";
292 infostream << std::endl;
293 // Load and run "mod" scripts
294 for (std::vector<ModSpec>::iterator i = m_mods.begin();
295 i != m_mods.end(); i++) {
296 const ModSpec &mod = *i;
297 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
298 std::ostringstream err;
299 err << "Error loading mod \"" << mod.name
300 << "\": mod_name does not follow naming conventions: "
301 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
302 errorstream << err.str().c_str();
303 throw ModError(err.str());
305 std::string script_path = mod.path + DIR_DELIM "init.lua";
306 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
307 << script_path << "\"]" << std::endl;
308 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
309 errorstream << "Server: Failed to load and run "
310 << script_path << std::endl;
311 throw ModError("Failed to load and run " + script_path
312 + "\nError from Lua:\n" + error_msg);
316 // Read Textures and calculate sha1 sums
319 // Apply item aliases in the node definition manager
320 m_nodedef->updateAliases(m_itemdef);
322 // Apply texture overrides from texturepack/override.txt
323 std::string texture_path = g_settings->get("texture_path");
324 if (texture_path != "" && fs::IsDir(texture_path))
325 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
327 m_nodedef->setNodeRegistrationStatus(true);
329 // Perform pending node name resolutions
330 m_nodedef->runNodeResolveCallbacks();
332 // init the recipe hashes to speed up crafting
333 m_craftdef->initHashes(this);
335 // Initialize Environment
336 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
338 m_clients.setEnv(m_env);
340 // Initialize mapgens
341 m_emerge->initMapgens();
343 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
344 if (m_enable_rollback_recording) {
345 // Create rollback manager
346 m_rollback = new RollbackManager(m_path_world, this);
349 // Give environment reference to scripting api
350 m_script->initializeEnvironment(m_env);
352 // Register us to receive map edit events
353 servermap->addEventReceiver(this);
355 // If file exists, load environment metadata
356 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
358 infostream<<"Server: Loading environment metadata"<<std::endl;
362 // Add some test ActiveBlockModifiers to environment
363 add_legacy_abms(m_env, m_nodedef);
365 m_liquid_transform_every = g_settings->getFloat("liquid_update");
370 infostream<<"Server destructing"<<std::endl;
372 // Send shutdown message
373 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
376 MutexAutoLock envlock(m_env_mutex);
378 // Execute script shutdown hooks
379 m_script->on_shutdown();
381 infostream << "Server: Saving players" << std::endl;
382 m_env->saveLoadedPlayers();
384 infostream << "Server: Kicking players" << std::endl;
385 std::string kick_msg;
386 bool reconnect = false;
387 if (getShutdownRequested()) {
388 reconnect = m_shutdown_ask_reconnect;
389 kick_msg = m_shutdown_msg;
391 if (kick_msg == "") {
392 kick_msg = g_settings->get("kick_msg_shutdown");
394 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
395 kick_msg, reconnect);
397 infostream << "Server: Saving environment metadata" << std::endl;
405 // stop all emerge threads before deleting players that may have
406 // requested blocks to be emerged
407 m_emerge->stopThreads();
409 // Delete things in the reverse order of creation
412 // N.B. the EmergeManager should be deleted after the Environment since Map
413 // depends on EmergeManager to write its current params to the map meta
422 // Deinitialize scripting
423 infostream<<"Server: Deinitializing scripting"<<std::endl;
426 // Delete detached inventories
427 for (std::map<std::string, Inventory*>::iterator
428 i = m_detached_inventories.begin();
429 i != m_detached_inventories.end(); i++) {
434 void Server::start(Address bind_addr)
436 DSTACK(__FUNCTION_NAME);
438 m_bind_addr = bind_addr;
440 infostream<<"Starting server on "
441 << bind_addr.serializeString() <<"..."<<std::endl;
443 // Stop thread if already running
446 // Initialize connection
447 m_con.SetTimeoutMs(30);
448 m_con.Serve(bind_addr);
453 // ASCII art for the win!
455 <<" .__ __ __ "<<std::endl
456 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
457 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
458 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
459 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
460 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
461 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
462 actionstream<<"Server for gameid=\""<<m_gamespec.id
463 <<"\" listening on "<<bind_addr.serializeString()<<":"
464 <<bind_addr.getPort() << "."<<std::endl;
469 DSTACK(__FUNCTION_NAME);
471 infostream<<"Server: Stopping and waiting threads"<<std::endl;
473 // Stop threads (set run=false first so both start stopping)
475 //m_emergethread.setRun(false);
477 //m_emergethread.stop();
479 infostream<<"Server: Threads stopped"<<std::endl;
482 void Server::step(float dtime)
484 DSTACK(__FUNCTION_NAME);
489 MutexAutoLock lock(m_step_dtime_mutex);
490 m_step_dtime += dtime;
492 // Throw if fatal error occurred in thread
493 std::string async_err = m_async_fatal_error.get();
494 if(async_err != "") {
495 if (m_simple_singleplayer_mode) {
496 throw ServerError(async_err);
499 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
500 g_settings->get("kick_msg_crash"),
501 g_settings->getBool("ask_reconnect_on_crash"));
502 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
503 << "Please fix the following error:" << std::endl
504 << async_err << std::endl;
505 FATAL_ERROR(async_err.c_str());
510 void Server::AsyncRunStep(bool initial_step)
512 DSTACK(__FUNCTION_NAME);
514 g_profiler->add("Server::AsyncRunStep (num)", 1);
518 MutexAutoLock lock1(m_step_dtime_mutex);
519 dtime = m_step_dtime;
523 // Send blocks to clients
527 if((dtime < 0.001) && (initial_step == false))
530 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
532 //infostream<<"Server steps "<<dtime<<std::endl;
533 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
536 MutexAutoLock lock1(m_step_dtime_mutex);
537 m_step_dtime -= dtime;
544 m_uptime.set(m_uptime.get() + dtime);
550 Update time of day and overall game time
552 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
555 Send to clients at constant intervals
558 m_time_of_day_send_timer -= dtime;
559 if(m_time_of_day_send_timer < 0.0) {
560 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
561 u16 time = m_env->getTimeOfDay();
562 float time_speed = g_settings->getFloat("time_speed");
563 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
567 MutexAutoLock lock(m_env_mutex);
568 // Figure out and report maximum lag to environment
569 float max_lag = m_env->getMaxLagEstimate();
570 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
572 if(dtime > 0.1 && dtime > max_lag * 2.0)
573 infostream<<"Server: Maximum lag peaked to "<<dtime
577 m_env->reportMaxLagEstimate(max_lag);
579 ScopeProfiler sp(g_profiler, "SEnv step");
580 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
584 static const float map_timer_and_unload_dtime = 2.92;
585 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
587 MutexAutoLock lock(m_env_mutex);
588 // Run Map's timers and unload unused data
589 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
590 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
591 g_settings->getFloat("server_unload_unused_data_timeout"),
599 /* Transform liquids */
600 m_liquid_transform_timer += dtime;
601 if(m_liquid_transform_timer >= m_liquid_transform_every)
603 m_liquid_transform_timer -= m_liquid_transform_every;
605 MutexAutoLock lock(m_env_mutex);
607 ScopeProfiler sp(g_profiler, "Server: liquid transform");
609 std::map<v3s16, MapBlock*> modified_blocks;
610 m_env->getMap().transformLiquids(modified_blocks);
615 core::map<v3s16, MapBlock*> lighting_modified_blocks;
616 ServerMap &map = ((ServerMap&)m_env->getMap());
617 map.updateLighting(modified_blocks, lighting_modified_blocks);
619 // Add blocks modified by lighting to modified_blocks
620 for(core::map<v3s16, MapBlock*>::Iterator
621 i = lighting_modified_blocks.getIterator();
622 i.atEnd() == false; i++)
624 MapBlock *block = i.getNode()->getValue();
625 modified_blocks.insert(block->getPos(), block);
629 Set the modified blocks unsent for all the clients
631 if(!modified_blocks.empty())
633 SetBlocksNotSent(modified_blocks);
636 m_clients.step(dtime);
638 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
640 // send masterserver announce
642 float &counter = m_masterserver_timer;
643 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
644 g_settings->getBool("server_announce"))
646 ServerList::sendAnnounce(counter ? "update" : "start",
647 m_bind_addr.getPort(),
648 m_clients.getPlayerNames(),
650 m_env->getGameTime(),
653 m_emerge->params.mg_name,
662 Check added and deleted active objects
665 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
666 MutexAutoLock envlock(m_env_mutex);
669 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
670 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
672 // Radius inside which objects are active
673 s16 radius = g_settings->getS16("active_object_send_range_blocks");
674 s16 player_radius = g_settings->getS16("player_transfer_distance");
676 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
677 !g_settings->getBool("unlimited_player_transfer_distance"))
678 player_radius = radius;
680 radius *= MAP_BLOCKSIZE;
681 player_radius *= MAP_BLOCKSIZE;
683 for(std::map<u16, RemoteClient*>::iterator
685 i != clients.end(); ++i)
687 RemoteClient *client = i->second;
689 // If definitions and textures have not been sent, don't
690 // send objects either
691 if (client->getState() < CS_DefinitionsSent)
694 Player *player = m_env->getPlayer(client->peer_id);
697 // This can happen if the client timeouts somehow
698 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
700 <<" has no associated player"<<std::endl;*/
703 v3s16 pos = floatToInt(player->getPosition(), BS);
705 std::set<u16> removed_objects;
706 std::set<u16> added_objects;
707 m_env->getRemovedActiveObjects(pos, radius, player_radius,
708 client->m_known_objects, removed_objects);
709 m_env->getAddedActiveObjects(pos, radius, player_radius,
710 client->m_known_objects, added_objects);
712 // Ignore if nothing happened
713 if(removed_objects.empty() && added_objects.empty())
715 //infostream<<"active objects: none changed"<<std::endl;
719 std::string data_buffer;
723 // Handle removed objects
724 writeU16((u8*)buf, removed_objects.size());
725 data_buffer.append(buf, 2);
726 for(std::set<u16>::iterator
727 i = removed_objects.begin();
728 i != removed_objects.end(); ++i)
732 ServerActiveObject* obj = m_env->getActiveObject(id);
734 // Add to data buffer for sending
735 writeU16((u8*)buf, id);
736 data_buffer.append(buf, 2);
738 // Remove from known objects
739 client->m_known_objects.erase(id);
741 if(obj && obj->m_known_by_count > 0)
742 obj->m_known_by_count--;
745 // Handle added objects
746 writeU16((u8*)buf, added_objects.size());
747 data_buffer.append(buf, 2);
748 for(std::set<u16>::iterator
749 i = added_objects.begin();
750 i != added_objects.end(); ++i)
754 ServerActiveObject* obj = m_env->getActiveObject(id);
757 u8 type = ACTIVEOBJECT_TYPE_INVALID;
759 infostream<<"WARNING: "<<__FUNCTION_NAME
760 <<": NULL object"<<std::endl;
762 type = obj->getSendType();
764 // Add to data buffer for sending
765 writeU16((u8*)buf, id);
766 data_buffer.append(buf, 2);
767 writeU8((u8*)buf, type);
768 data_buffer.append(buf, 1);
771 data_buffer.append(serializeLongString(
772 obj->getClientInitializationData(client->net_proto_version)));
774 data_buffer.append(serializeLongString(""));
776 // Add to known objects
777 client->m_known_objects.insert(id);
780 obj->m_known_by_count++;
783 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
784 verbosestream << "Server: Sent object remove/add: "
785 << removed_objects.size() << " removed, "
786 << added_objects.size() << " added, "
787 << "packet size is " << pktSize << std::endl;
796 MutexAutoLock envlock(m_env_mutex);
797 ScopeProfiler sp(g_profiler, "Server: sending object messages");
800 // Value = data sent by object
801 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
803 // Get active object messages from environment
805 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
809 std::vector<ActiveObjectMessage>* message_list = NULL;
810 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
811 n = buffered_messages.find(aom.id);
812 if (n == buffered_messages.end()) {
813 message_list = new std::vector<ActiveObjectMessage>;
814 buffered_messages[aom.id] = message_list;
817 message_list = n->second;
819 message_list->push_back(aom);
823 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
824 // Route data to every client
825 for (std::map<u16, RemoteClient*>::iterator
827 i != clients.end(); ++i) {
828 RemoteClient *client = i->second;
829 std::string reliable_data;
830 std::string unreliable_data;
831 // Go through all objects in message buffer
832 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
833 j = buffered_messages.begin();
834 j != buffered_messages.end(); ++j) {
835 // If object is not known by client, skip it
837 if (client->m_known_objects.find(id) == client->m_known_objects.end())
840 // Get message list of object
841 std::vector<ActiveObjectMessage>* list = j->second;
842 // Go through every message
843 for (std::vector<ActiveObjectMessage>::iterator
844 k = list->begin(); k != list->end(); ++k) {
845 // Compose the full new data with header
846 ActiveObjectMessage aom = *k;
847 std::string new_data;
850 writeU16((u8*)&buf[0], aom.id);
851 new_data.append(buf, 2);
853 new_data += serializeString(aom.datastring);
854 // Add data to buffer
856 reliable_data += new_data;
858 unreliable_data += new_data;
862 reliable_data and unreliable_data are now ready.
865 if(reliable_data.size() > 0) {
866 SendActiveObjectMessages(client->peer_id, reliable_data);
869 if(unreliable_data.size() > 0) {
870 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
875 // Clear buffered_messages
876 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
877 i = buffered_messages.begin();
878 i != buffered_messages.end(); ++i) {
884 Send queued-for-sending map edit events.
887 // We will be accessing the environment
888 MutexAutoLock lock(m_env_mutex);
890 // Don't send too many at a time
893 // Single change sending is disabled if queue size is not small
894 bool disable_single_change_sending = false;
895 if(m_unsent_map_edit_queue.size() >= 4)
896 disable_single_change_sending = true;
898 int event_count = m_unsent_map_edit_queue.size();
900 // We'll log the amount of each
903 while(m_unsent_map_edit_queue.size() != 0)
905 MapEditEvent* event = m_unsent_map_edit_queue.front();
906 m_unsent_map_edit_queue.pop();
908 // Players far away from the change are stored here.
909 // Instead of sending the changes, MapBlocks are set not sent
911 std::vector<u16> far_players;
913 switch (event->type) {
916 prof.add("MEET_ADDNODE", 1);
917 sendAddNode(event->p, event->n, event->already_known_by_peer,
918 &far_players, disable_single_change_sending ? 5 : 30,
919 event->type == MEET_ADDNODE);
921 case MEET_REMOVENODE:
922 prof.add("MEET_REMOVENODE", 1);
923 sendRemoveNode(event->p, event->already_known_by_peer,
924 &far_players, disable_single_change_sending ? 5 : 30);
926 case MEET_BLOCK_NODE_METADATA_CHANGED:
927 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
928 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
929 setBlockNotSent(event->p);
932 infostream << "Server: MEET_OTHER" << std::endl;
933 prof.add("MEET_OTHER", 1);
934 for(std::set<v3s16>::iterator
935 i = event->modified_blocks.begin();
936 i != event->modified_blocks.end(); ++i) {
941 prof.add("unknown", 1);
942 infostream << "WARNING: Server: Unknown MapEditEvent "
943 << ((u32)event->type) << std::endl;
948 Set blocks not sent to far players
950 if(!far_players.empty()) {
951 // Convert list format to that wanted by SetBlocksNotSent
952 std::map<v3s16, MapBlock*> modified_blocks2;
953 for(std::set<v3s16>::iterator
954 i = event->modified_blocks.begin();
955 i != event->modified_blocks.end(); ++i) {
956 modified_blocks2[*i] =
957 m_env->getMap().getBlockNoCreateNoEx(*i);
960 // Set blocks not sent
961 for(std::vector<u16>::iterator
962 i = far_players.begin();
963 i != far_players.end(); ++i) {
964 if(RemoteClient *client = getClient(*i))
965 client->SetBlocksNotSent(modified_blocks2);
971 /*// Don't send too many at a time
973 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
977 if(event_count >= 5){
978 infostream<<"Server: MapEditEvents:"<<std::endl;
979 prof.print(infostream);
980 } else if(event_count != 0){
981 verbosestream<<"Server: MapEditEvents:"<<std::endl;
982 prof.print(verbosestream);
988 Trigger emergethread (it somehow gets to a non-triggered but
989 bysy state sometimes)
992 float &counter = m_emergethread_trigger_timer;
998 m_emerge->startThreads();
1002 // Save map, players and auth stuff
1004 float &counter = m_savemap_timer;
1006 if(counter >= g_settings->getFloat("server_map_save_interval"))
1009 MutexAutoLock lock(m_env_mutex);
1011 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1014 if (m_banmanager->isModified()) {
1015 m_banmanager->save();
1018 // Save changed parts of map
1019 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1022 m_env->saveLoadedPlayers();
1024 // Save environment metadata
1030 void Server::Receive()
1032 DSTACK(__FUNCTION_NAME);
1033 SharedBuffer<u8> data;
1037 m_con.Receive(&pkt);
1038 peer_id = pkt.getPeerId();
1041 catch(con::InvalidIncomingDataException &e) {
1042 infostream<<"Server::Receive(): "
1043 "InvalidIncomingDataException: what()="
1044 <<e.what()<<std::endl;
1046 catch(SerializationError &e) {
1047 infostream<<"Server::Receive(): "
1048 "SerializationError: what()="
1049 <<e.what()<<std::endl;
1051 catch(ClientStateError &e) {
1052 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1053 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1054 L"Try reconnecting or updating your client");
1056 catch(con::PeerNotFoundException &e) {
1061 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1063 std::string playername = "";
1064 PlayerSAO *playersao = NULL;
1067 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1068 if (client != NULL) {
1069 playername = client->getName();
1070 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1072 } catch (std::exception &e) {
1078 RemotePlayer *player =
1079 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1081 // If failed, cancel
1082 if ((playersao == NULL) || (player == NULL)) {
1083 if (player && player->peer_id != 0) {
1084 actionstream << "Server: Failed to emerge player \"" << playername
1085 << "\" (player allocated to an another client)" << std::endl;
1086 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1087 L"name. If your client closed unexpectedly, try again in "
1090 errorstream << "Server: " << playername << ": Failed to emerge player"
1092 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1098 Send complete position information
1100 SendMovePlayer(peer_id);
1103 SendPlayerPrivileges(peer_id);
1105 // Send inventory formspec
1106 SendPlayerInventoryFormspec(peer_id);
1109 SendInventory(playersao);
1112 SendPlayerHPOrDie(playersao);
1115 SendPlayerBreath(peer_id);
1117 // Show death screen if necessary
1118 if(player->isDead())
1119 SendDeathscreen(peer_id, false, v3f(0,0,0));
1121 // Note things in chat if not in simple singleplayer mode
1122 if(!m_simple_singleplayer_mode) {
1123 // Send information about server to player in chat
1124 SendChatMessage(peer_id, getStatusString());
1126 // Send information about joining in chat
1128 std::wstring name = L"unknown";
1129 Player *player = m_env->getPlayer(peer_id);
1131 name = narrow_to_wide(player->getName());
1133 std::wstring message;
1136 message += L" joined the game.";
1137 SendChatMessage(PEER_ID_INEXISTENT,message);
1140 Address addr = getPeerAddress(player->peer_id);
1141 std::string ip_str = addr.serializeString();
1142 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1147 std::vector<std::string> names = m_clients.getPlayerNames();
1149 actionstream<<player->getName() <<" joins game. List of players: ";
1151 for (std::vector<std::string>::iterator i = names.begin();
1152 i != names.end(); i++) {
1153 actionstream << *i << " ";
1156 actionstream << player->getName() <<std::endl;
1161 inline void Server::handleCommand(NetworkPacket* pkt)
1163 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1164 (this->*opHandle.handler)(pkt);
1167 void Server::ProcessData(NetworkPacket *pkt)
1169 DSTACK(__FUNCTION_NAME);
1170 // Environment is locked first.
1171 MutexAutoLock envlock(m_env_mutex);
1173 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1174 u32 peer_id = pkt->getPeerId();
1177 Address address = getPeerAddress(peer_id);
1178 std::string addr_s = address.serializeString();
1180 if(m_banmanager->isIpBanned(addr_s)) {
1181 std::string ban_name = m_banmanager->getBanName(addr_s);
1182 infostream << "Server: A banned client tried to connect from "
1183 << addr_s << "; banned name was "
1184 << ban_name << std::endl;
1185 // This actually doesn't seem to transfer to the client
1186 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1187 + utf8_to_wide(ban_name));
1191 catch(con::PeerNotFoundException &e) {
1193 * no peer for this packet found
1194 * most common reason is peer timeout, e.g. peer didn't
1195 * respond for some time, your server was overloaded or
1198 infostream << "Server::ProcessData(): Canceling: peer "
1199 << peer_id << " not found" << std::endl;
1204 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1206 // Command must be handled into ToServerCommandHandler
1207 if (command >= TOSERVER_NUM_MSG_TYPES) {
1208 infostream << "Server: Ignoring unknown command "
1209 << command << std::endl;
1213 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1218 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1220 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1221 errorstream << "Server::ProcessData(): Cancelling: Peer"
1222 " serialization format invalid or not initialized."
1223 " Skipping incoming command=" << command << std::endl;
1227 /* Handle commands related to client startup */
1228 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1233 if (m_clients.getClientState(peer_id) < CS_Active) {
1234 if (command == TOSERVER_PLAYERPOS) return;
1236 errorstream << "Got packet command: " << command << " for peer id "
1237 << peer_id << " but client isn't active yet. Dropping packet "
1243 } catch (SendFailedException &e) {
1244 errorstream << "Server::ProcessData(): SendFailedException: "
1245 << "what=" << e.what()
1247 } catch (PacketError &e) {
1248 actionstream << "Server::ProcessData(): PacketError: "
1249 << "what=" << e.what()
1254 void Server::setTimeOfDay(u32 time)
1256 m_env->setTimeOfDay(time);
1257 m_time_of_day_send_timer = 0;
1260 void Server::onMapEditEvent(MapEditEvent *event)
1262 if(m_ignore_map_edit_events)
1264 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1266 MapEditEvent *e = event->clone();
1267 m_unsent_map_edit_queue.push(e);
1270 Inventory* Server::getInventory(const InventoryLocation &loc)
1273 case InventoryLocation::UNDEFINED:
1274 case InventoryLocation::CURRENT_PLAYER:
1276 case InventoryLocation::PLAYER:
1278 Player *player = m_env->getPlayer(loc.name.c_str());
1281 PlayerSAO *playersao = player->getPlayerSAO();
1284 return playersao->getInventory();
1287 case InventoryLocation::NODEMETA:
1289 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1292 return meta->getInventory();
1295 case InventoryLocation::DETACHED:
1297 if(m_detached_inventories.count(loc.name) == 0)
1299 return m_detached_inventories[loc.name];
1303 sanity_check(false); // abort
1308 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1311 case InventoryLocation::UNDEFINED:
1313 case InventoryLocation::PLAYER:
1318 Player *player = m_env->getPlayer(loc.name.c_str());
1321 PlayerSAO *playersao = player->getPlayerSAO();
1325 SendInventory(playersao);
1328 case InventoryLocation::NODEMETA:
1330 v3s16 blockpos = getNodeBlockPos(loc.p);
1332 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1334 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1336 setBlockNotSent(blockpos);
1339 case InventoryLocation::DETACHED:
1341 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1345 sanity_check(false); // abort
1350 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1352 std::vector<u16> clients = m_clients.getClientIDs();
1354 // Set the modified blocks unsent for all the clients
1355 for (std::vector<u16>::iterator i = clients.begin();
1356 i != clients.end(); ++i) {
1357 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1358 client->SetBlocksNotSent(block);
1363 void Server::peerAdded(con::Peer *peer)
1365 DSTACK(__FUNCTION_NAME);
1366 verbosestream<<"Server::peerAdded(): peer->id="
1367 <<peer->id<<std::endl;
1370 c.type = con::PEER_ADDED;
1371 c.peer_id = peer->id;
1373 m_peer_change_queue.push(c);
1376 void Server::deletingPeer(con::Peer *peer, bool timeout)
1378 DSTACK(__FUNCTION_NAME);
1379 verbosestream<<"Server::deletingPeer(): peer->id="
1380 <<peer->id<<", timeout="<<timeout<<std::endl;
1382 m_clients.event(peer->id, CSE_Disconnect);
1384 c.type = con::PEER_REMOVED;
1385 c.peer_id = peer->id;
1386 c.timeout = timeout;
1387 m_peer_change_queue.push(c);
1390 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1392 *retval = m_con.getPeerStat(peer_id,type);
1393 if (*retval == -1) return false;
1397 bool Server::getClientInfo(
1406 std::string* vers_string
1409 *state = m_clients.getClientState(peer_id);
1411 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1413 if (client == NULL) {
1418 *uptime = client->uptime();
1419 *ser_vers = client->serialization_version;
1420 *prot_vers = client->net_proto_version;
1422 *major = client->getMajor();
1423 *minor = client->getMinor();
1424 *patch = client->getPatch();
1425 *vers_string = client->getPatch();
1432 void Server::handlePeerChanges()
1434 while(m_peer_change_queue.size() > 0)
1436 con::PeerChange c = m_peer_change_queue.front();
1437 m_peer_change_queue.pop();
1439 verbosestream<<"Server: Handling peer change: "
1440 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1445 case con::PEER_ADDED:
1446 m_clients.CreateClient(c.peer_id);
1449 case con::PEER_REMOVED:
1450 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1454 FATAL_ERROR("Invalid peer change event received!");
1460 void Server::Send(NetworkPacket* pkt)
1462 m_clients.send(pkt->getPeerId(),
1463 clientCommandFactoryTable[pkt->getCommand()].channel,
1465 clientCommandFactoryTable[pkt->getCommand()].reliable);
1468 void Server::SendMovement(u16 peer_id)
1470 DSTACK(__FUNCTION_NAME);
1471 std::ostringstream os(std::ios_base::binary);
1473 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1475 pkt << g_settings->getFloat("movement_acceleration_default");
1476 pkt << g_settings->getFloat("movement_acceleration_air");
1477 pkt << g_settings->getFloat("movement_acceleration_fast");
1478 pkt << g_settings->getFloat("movement_speed_walk");
1479 pkt << g_settings->getFloat("movement_speed_crouch");
1480 pkt << g_settings->getFloat("movement_speed_fast");
1481 pkt << g_settings->getFloat("movement_speed_climb");
1482 pkt << g_settings->getFloat("movement_speed_jump");
1483 pkt << g_settings->getFloat("movement_liquid_fluidity");
1484 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1485 pkt << g_settings->getFloat("movement_liquid_sink");
1486 pkt << g_settings->getFloat("movement_gravity");
1491 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1493 if (!g_settings->getBool("enable_damage"))
1496 u16 peer_id = playersao->getPeerID();
1497 bool is_alive = playersao->getHP() > 0;
1500 SendPlayerHP(peer_id);
1505 void Server::SendHP(u16 peer_id, u8 hp)
1507 DSTACK(__FUNCTION_NAME);
1509 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1514 void Server::SendBreath(u16 peer_id, u16 breath)
1516 DSTACK(__FUNCTION_NAME);
1518 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1519 pkt << (u16) breath;
1523 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1524 const std::string &custom_reason, bool reconnect)
1526 assert(reason < SERVER_ACCESSDENIED_MAX);
1528 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1530 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1531 pkt << custom_reason;
1532 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1533 reason == SERVER_ACCESSDENIED_CRASH)
1534 pkt << custom_reason << (u8)reconnect;
1538 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1540 DSTACK(__FUNCTION_NAME);
1542 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1547 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1548 v3f camera_point_target)
1550 DSTACK(__FUNCTION_NAME);
1552 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1553 pkt << set_camera_point_target << camera_point_target;
1557 void Server::SendItemDef(u16 peer_id,
1558 IItemDefManager *itemdef, u16 protocol_version)
1560 DSTACK(__FUNCTION_NAME);
1562 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1566 u32 length of the next item
1567 zlib-compressed serialized ItemDefManager
1569 std::ostringstream tmp_os(std::ios::binary);
1570 itemdef->serialize(tmp_os, protocol_version);
1571 std::ostringstream tmp_os2(std::ios::binary);
1572 compressZlib(tmp_os.str(), tmp_os2);
1573 pkt.putLongString(tmp_os2.str());
1576 verbosestream << "Server: Sending item definitions to id(" << peer_id
1577 << "): size=" << pkt.getSize() << std::endl;
1582 void Server::SendNodeDef(u16 peer_id,
1583 INodeDefManager *nodedef, u16 protocol_version)
1585 DSTACK(__FUNCTION_NAME);
1587 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1591 u32 length of the next item
1592 zlib-compressed serialized NodeDefManager
1594 std::ostringstream tmp_os(std::ios::binary);
1595 nodedef->serialize(tmp_os, protocol_version);
1596 std::ostringstream tmp_os2(std::ios::binary);
1597 compressZlib(tmp_os.str(), tmp_os2);
1599 pkt.putLongString(tmp_os2.str());
1602 verbosestream << "Server: Sending node definitions to id(" << peer_id
1603 << "): size=" << pkt.getSize() << std::endl;
1609 Non-static send methods
1612 void Server::SendInventory(PlayerSAO* playerSAO)
1614 DSTACK(__FUNCTION_NAME);
1616 UpdateCrafting(playerSAO->getPlayer());
1622 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1624 std::ostringstream os;
1625 playerSAO->getInventory()->serialize(os);
1627 std::string s = os.str();
1629 pkt.putRawString(s.c_str(), s.size());
1633 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1635 DSTACK(__FUNCTION_NAME);
1637 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1640 if (peer_id != PEER_ID_INEXISTENT) {
1644 m_clients.sendToAll(0, &pkt, true);
1648 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1649 const std::string &formname)
1651 DSTACK(__FUNCTION_NAME);
1653 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1655 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1661 // Spawns a particle on peer with peer_id
1662 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1663 float expirationtime, float size, bool collisiondetection,
1664 bool vertical, std::string texture)
1666 DSTACK(__FUNCTION_NAME);
1668 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1670 pkt << pos << velocity << acceleration << expirationtime
1671 << size << collisiondetection;
1672 pkt.putLongString(texture);
1675 if (peer_id != PEER_ID_INEXISTENT) {
1679 m_clients.sendToAll(0, &pkt, true);
1683 // Adds a ParticleSpawner on peer with peer_id
1684 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1685 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1686 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1688 DSTACK(__FUNCTION_NAME);
1690 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1692 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1693 << minacc << maxacc << minexptime << maxexptime << minsize
1694 << maxsize << collisiondetection;
1696 pkt.putLongString(texture);
1698 pkt << id << vertical;
1700 if (peer_id != PEER_ID_INEXISTENT) {
1704 m_clients.sendToAll(0, &pkt, true);
1708 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1710 DSTACK(__FUNCTION_NAME);
1712 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1714 // Ugly error in this packet
1717 if (peer_id != PEER_ID_INEXISTENT) {
1721 m_clients.sendToAll(0, &pkt, true);
1726 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1728 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1730 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1731 << form->text << form->number << form->item << form->dir
1732 << form->align << form->offset << form->world_pos << form->size;
1737 void Server::SendHUDRemove(u16 peer_id, u32 id)
1739 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1744 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1746 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1747 pkt << id << (u8) stat;
1751 case HUD_STAT_SCALE:
1752 case HUD_STAT_ALIGN:
1753 case HUD_STAT_OFFSET:
1754 pkt << *(v2f *) value;
1758 pkt << *(std::string *) value;
1760 case HUD_STAT_WORLD_POS:
1761 pkt << *(v3f *) value;
1764 pkt << *(v2s32 *) value;
1766 case HUD_STAT_NUMBER:
1770 pkt << *(u32 *) value;
1777 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1779 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1781 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1783 pkt << flags << mask;
1788 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1790 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1791 pkt << param << value;
1795 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1796 const std::string &type, const std::vector<std::string> ¶ms)
1798 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1799 pkt << bgcolor << type << (u16) params.size();
1801 for(size_t i=0; i<params.size(); i++)
1807 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1810 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1813 pkt << do_override << (u16) (ratio * 65535);
1818 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1820 DSTACK(__FUNCTION_NAME);
1822 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1823 pkt << time << time_speed;
1825 if (peer_id == PEER_ID_INEXISTENT) {
1826 m_clients.sendToAll(0, &pkt, true);
1833 void Server::SendPlayerHP(u16 peer_id)
1835 DSTACK(__FUNCTION_NAME);
1836 PlayerSAO *playersao = getPlayerSAO(peer_id);
1837 // In some rare case, if the player is disconnected
1838 // while Lua call l_punch, for example, this can be NULL
1842 SendHP(peer_id, playersao->getHP());
1843 m_script->player_event(playersao,"health_changed");
1845 // Send to other clients
1846 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1847 ActiveObjectMessage aom(playersao->getId(), true, str);
1848 playersao->m_messages_out.push(aom);
1851 void Server::SendPlayerBreath(u16 peer_id)
1853 DSTACK(__FUNCTION_NAME);
1854 PlayerSAO *playersao = getPlayerSAO(peer_id);
1857 m_script->player_event(playersao, "breath_changed");
1858 SendBreath(peer_id, playersao->getBreath());
1861 void Server::SendMovePlayer(u16 peer_id)
1863 DSTACK(__FUNCTION_NAME);
1864 Player *player = m_env->getPlayer(peer_id);
1867 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1868 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1871 v3f pos = player->getPosition();
1872 f32 pitch = player->getPitch();
1873 f32 yaw = player->getYaw();
1874 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1875 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1876 << " pitch=" << pitch
1884 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1886 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1889 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1890 << animation_frames[3] << animation_speed;
1895 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1897 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1898 pkt << first << third;
1901 void Server::SendPlayerPrivileges(u16 peer_id)
1903 Player *player = m_env->getPlayer(peer_id);
1905 if(player->peer_id == PEER_ID_INEXISTENT)
1908 std::set<std::string> privs;
1909 m_script->getAuth(player->getName(), NULL, &privs);
1911 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1912 pkt << (u16) privs.size();
1914 for(std::set<std::string>::const_iterator i = privs.begin();
1915 i != privs.end(); i++) {
1922 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1924 Player *player = m_env->getPlayer(peer_id);
1926 if(player->peer_id == PEER_ID_INEXISTENT)
1929 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1930 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1934 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1936 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1937 pkt.putRawString(datas.c_str(), datas.size());
1939 return pkt.getSize();
1942 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1944 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1945 datas.size(), peer_id);
1947 pkt.putRawString(datas.c_str(), datas.size());
1949 m_clients.send(pkt.getPeerId(),
1950 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1955 s32 Server::playSound(const SimpleSoundSpec &spec,
1956 const ServerSoundParams ¶ms)
1958 // Find out initial position of sound
1959 bool pos_exists = false;
1960 v3f pos = params.getPos(m_env, &pos_exists);
1961 // If position is not found while it should be, cancel sound
1962 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1965 // Filter destination clients
1966 std::vector<u16> dst_clients;
1967 if(params.to_player != "")
1969 Player *player = m_env->getPlayer(params.to_player.c_str());
1971 infostream<<"Server::playSound: Player \""<<params.to_player
1972 <<"\" not found"<<std::endl;
1975 if(player->peer_id == PEER_ID_INEXISTENT){
1976 infostream<<"Server::playSound: Player \""<<params.to_player
1977 <<"\" not connected"<<std::endl;
1980 dst_clients.push_back(player->peer_id);
1983 std::vector<u16> clients = m_clients.getClientIDs();
1985 for(std::vector<u16>::iterator
1986 i = clients.begin(); i != clients.end(); ++i) {
1987 Player *player = m_env->getPlayer(*i);
1992 if(player->getPosition().getDistanceFrom(pos) >
1993 params.max_hear_distance)
1996 dst_clients.push_back(*i);
2000 if(dst_clients.empty())
2004 s32 id = m_next_sound_id++;
2005 // The sound will exist as a reference in m_playing_sounds
2006 m_playing_sounds[id] = ServerPlayingSound();
2007 ServerPlayingSound &psound = m_playing_sounds[id];
2008 psound.params = params;
2010 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2011 pkt << id << spec.name << (float) (spec.gain * params.gain)
2012 << (u8) params.type << pos << params.object << params.loop;
2014 for(std::vector<u16>::iterator i = dst_clients.begin();
2015 i != dst_clients.end(); i++) {
2016 psound.clients.insert(*i);
2017 m_clients.send(*i, 0, &pkt, true);
2021 void Server::stopSound(s32 handle)
2023 // Get sound reference
2024 std::map<s32, ServerPlayingSound>::iterator i =
2025 m_playing_sounds.find(handle);
2026 if(i == m_playing_sounds.end())
2028 ServerPlayingSound &psound = i->second;
2030 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2033 for(std::set<u16>::iterator i = psound.clients.begin();
2034 i != psound.clients.end(); i++) {
2036 m_clients.send(*i, 0, &pkt, true);
2038 // Remove sound reference
2039 m_playing_sounds.erase(i);
2042 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2043 std::vector<u16> *far_players, float far_d_nodes)
2045 float maxd = far_d_nodes*BS;
2046 v3f p_f = intToFloat(p, BS);
2048 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2051 std::vector<u16> clients = m_clients.getClientIDs();
2052 for(std::vector<u16>::iterator i = clients.begin();
2053 i != clients.end(); ++i) {
2056 if(Player *player = m_env->getPlayer(*i)) {
2057 // If player is far away, only set modified blocks not sent
2058 v3f player_pos = player->getPosition();
2059 if(player_pos.getDistanceFrom(p_f) > maxd) {
2060 far_players->push_back(*i);
2067 m_clients.send(*i, 0, &pkt, true);
2071 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2072 std::vector<u16> *far_players, float far_d_nodes,
2073 bool remove_metadata)
2075 float maxd = far_d_nodes*BS;
2076 v3f p_f = intToFloat(p, BS);
2078 std::vector<u16> clients = m_clients.getClientIDs();
2079 for(std::vector<u16>::iterator i = clients.begin();
2080 i != clients.end(); ++i) {
2084 if(Player *player = m_env->getPlayer(*i)) {
2085 // If player is far away, only set modified blocks not sent
2086 v3f player_pos = player->getPosition();
2087 if(player_pos.getDistanceFrom(p_f) > maxd) {
2088 far_players->push_back(*i);
2094 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2096 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2098 pkt << p << n.param0 << n.param1 << n.param2
2099 << (u8) (remove_metadata ? 0 : 1);
2101 if (!remove_metadata) {
2102 if (client->net_proto_version <= 21) {
2103 // Old clients always clear metadata; fix it
2104 // by sending the full block again.
2105 client->SetBlockNotSent(p);
2112 if (pkt.getSize() > 0)
2113 m_clients.send(*i, 0, &pkt, true);
2117 void Server::setBlockNotSent(v3s16 p)
2119 std::vector<u16> clients = m_clients.getClientIDs();
2121 for(std::vector<u16>::iterator i = clients.begin();
2122 i != clients.end(); ++i) {
2123 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2124 client->SetBlockNotSent(p);
2129 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2131 DSTACK(__FUNCTION_NAME);
2133 v3s16 p = block->getPos();
2136 Create a packet with the block in the right format
2139 std::ostringstream os(std::ios_base::binary);
2140 block->serialize(os, ver, false);
2141 block->serializeNetworkSpecific(os, net_proto_version);
2142 std::string s = os.str();
2144 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2147 pkt.putRawString(s.c_str(), s.size());
2151 void Server::SendBlocks(float dtime)
2153 DSTACK(__FUNCTION_NAME);
2155 MutexAutoLock envlock(m_env_mutex);
2156 //TODO check if one big lock could be faster then multiple small ones
2158 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2160 std::vector<PrioritySortedBlockTransfer> queue;
2162 s32 total_sending = 0;
2165 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2167 std::vector<u16> clients = m_clients.getClientIDs();
2170 for(std::vector<u16>::iterator i = clients.begin();
2171 i != clients.end(); ++i) {
2172 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2177 total_sending += client->SendingCount();
2178 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2184 // Lowest priority number comes first.
2185 // Lowest is most important.
2186 std::sort(queue.begin(), queue.end());
2189 for(u32 i=0; i<queue.size(); i++)
2191 //TODO: Calculate limit dynamically
2192 if(total_sending >= g_settings->getS32
2193 ("max_simultaneous_block_sends_server_total"))
2196 PrioritySortedBlockTransfer q = queue[i];
2198 MapBlock *block = NULL;
2201 block = m_env->getMap().getBlockNoCreate(q.pos);
2203 catch(InvalidPositionException &e)
2208 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2213 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2215 client->SentBlock(q.pos);
2221 void Server::fillMediaCache()
2223 DSTACK(__FUNCTION_NAME);
2225 infostream<<"Server: Calculating media file checksums"<<std::endl;
2227 // Collect all media file paths
2228 std::vector<std::string> paths;
2229 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2230 i != m_mods.end(); i++) {
2231 const ModSpec &mod = *i;
2232 paths.push_back(mod.path + DIR_DELIM + "textures");
2233 paths.push_back(mod.path + DIR_DELIM + "sounds");
2234 paths.push_back(mod.path + DIR_DELIM + "media");
2235 paths.push_back(mod.path + DIR_DELIM + "models");
2237 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2239 // Collect media file information from paths into cache
2240 for(std::vector<std::string>::iterator i = paths.begin();
2241 i != paths.end(); i++) {
2242 std::string mediapath = *i;
2243 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2244 for (u32 j = 0; j < dirlist.size(); j++) {
2245 if (dirlist[j].dir) // Ignode dirs
2247 std::string filename = dirlist[j].name;
2248 // If name contains illegal characters, ignore the file
2249 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2250 infostream<<"Server: ignoring illegal file name: \""
2251 << filename << "\"" << std::endl;
2254 // If name is not in a supported format, ignore it
2255 const char *supported_ext[] = {
2256 ".png", ".jpg", ".bmp", ".tga",
2257 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2259 ".x", ".b3d", ".md2", ".obj",
2262 if (removeStringEnd(filename, supported_ext) == ""){
2263 infostream << "Server: ignoring unsupported file extension: \""
2264 << filename << "\"" << std::endl;
2267 // Ok, attempt to load the file and add to cache
2268 std::string filepath = mediapath + DIR_DELIM + filename;
2270 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2272 errorstream << "Server::fillMediaCache(): Could not open \""
2273 << filename << "\" for reading" << std::endl;
2276 std::ostringstream tmp_os(std::ios_base::binary);
2280 fis.read(buf, 1024);
2281 std::streamsize len = fis.gcount();
2282 tmp_os.write(buf, len);
2291 errorstream<<"Server::fillMediaCache(): Failed to read \""
2292 << filename << "\"" << std::endl;
2295 if(tmp_os.str().length() == 0) {
2296 errorstream << "Server::fillMediaCache(): Empty file \""
2297 << filepath << "\"" << std::endl;
2302 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2304 unsigned char *digest = sha1.getDigest();
2305 std::string sha1_base64 = base64_encode(digest, 20);
2306 std::string sha1_hex = hex_encode((char*)digest, 20);
2310 m_media[filename] = MediaInfo(filepath, sha1_base64);
2311 verbosestream << "Server: " << sha1_hex << " is " << filename
2317 void Server::sendMediaAnnouncement(u16 peer_id)
2319 DSTACK(__FUNCTION_NAME);
2321 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2325 std::ostringstream os(std::ios_base::binary);
2327 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2328 pkt << (u16) m_media.size();
2330 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2331 i != m_media.end(); ++i) {
2332 pkt << i->first << i->second.sha1_digest;
2335 pkt << g_settings->get("remote_media");
2339 struct SendableMedia
2345 SendableMedia(const std::string &name_="", const std::string &path_="",
2346 const std::string &data_=""):
2353 void Server::sendRequestedMedia(u16 peer_id,
2354 const std::vector<std::string> &tosend)
2356 DSTACK(__FUNCTION_NAME);
2358 verbosestream<<"Server::sendRequestedMedia(): "
2359 <<"Sending files to client"<<std::endl;
2363 // Put 5kB in one bunch (this is not accurate)
2364 u32 bytes_per_bunch = 5000;
2366 std::vector< std::vector<SendableMedia> > file_bunches;
2367 file_bunches.push_back(std::vector<SendableMedia>());
2369 u32 file_size_bunch_total = 0;
2371 for(std::vector<std::string>::const_iterator i = tosend.begin();
2372 i != tosend.end(); ++i) {
2373 const std::string &name = *i;
2375 if(m_media.find(name) == m_media.end()) {
2376 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2377 <<"unknown file \""<<(name)<<"\""<<std::endl;
2381 //TODO get path + name
2382 std::string tpath = m_media[name].path;
2385 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2386 if(fis.good() == false){
2387 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2388 <<tpath<<"\" for reading"<<std::endl;
2391 std::ostringstream tmp_os(std::ios_base::binary);
2395 fis.read(buf, 1024);
2396 std::streamsize len = fis.gcount();
2397 tmp_os.write(buf, len);
2398 file_size_bunch_total += len;
2407 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2408 <<name<<"\""<<std::endl;
2411 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2412 <<tname<<"\""<<std::endl;*/
2414 file_bunches[file_bunches.size()-1].push_back(
2415 SendableMedia(name, tpath, tmp_os.str()));
2417 // Start next bunch if got enough data
2418 if(file_size_bunch_total >= bytes_per_bunch) {
2419 file_bunches.push_back(std::vector<SendableMedia>());
2420 file_size_bunch_total = 0;
2425 /* Create and send packets */
2427 u16 num_bunches = file_bunches.size();
2428 for(u16 i = 0; i < num_bunches; i++) {
2431 u16 total number of texture bunches
2432 u16 index of this bunch
2433 u32 number of files in this bunch
2442 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2443 pkt << num_bunches << i << (u32) file_bunches[i].size();
2445 for(std::vector<SendableMedia>::iterator
2446 j = file_bunches[i].begin();
2447 j != file_bunches[i].end(); ++j) {
2449 pkt.putLongString(j->data);
2452 verbosestream << "Server::sendRequestedMedia(): bunch "
2453 << i << "/" << num_bunches
2454 << " files=" << file_bunches[i].size()
2455 << " size=" << pkt.getSize() << std::endl;
2460 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2462 if(m_detached_inventories.count(name) == 0) {
2463 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2466 Inventory *inv = m_detached_inventories[name];
2467 std::ostringstream os(std::ios_base::binary);
2469 os << serializeString(name);
2473 std::string s = os.str();
2475 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2476 pkt.putRawString(s.c_str(), s.size());
2478 if (peer_id != PEER_ID_INEXISTENT) {
2482 m_clients.sendToAll(0, &pkt, true);
2486 void Server::sendDetachedInventories(u16 peer_id)
2488 DSTACK(__FUNCTION_NAME);
2490 for(std::map<std::string, Inventory*>::iterator
2491 i = m_detached_inventories.begin();
2492 i != m_detached_inventories.end(); i++) {
2493 const std::string &name = i->first;
2494 //Inventory *inv = i->second;
2495 sendDetachedInventory(name, peer_id);
2503 void Server::DiePlayer(u16 peer_id)
2505 DSTACK(__FUNCTION_NAME);
2507 PlayerSAO *playersao = getPlayerSAO(peer_id);
2510 infostream << "Server::DiePlayer(): Player "
2511 << playersao->getPlayer()->getName()
2512 << " dies" << std::endl;
2514 playersao->setHP(0);
2516 // Trigger scripted stuff
2517 m_script->on_dieplayer(playersao);
2519 SendPlayerHP(peer_id);
2520 SendDeathscreen(peer_id, false, v3f(0,0,0));
2523 void Server::RespawnPlayer(u16 peer_id)
2525 DSTACK(__FUNCTION_NAME);
2527 PlayerSAO *playersao = getPlayerSAO(peer_id);
2530 infostream << "Server::RespawnPlayer(): Player "
2531 << playersao->getPlayer()->getName()
2532 << " respawns" << std::endl;
2534 playersao->setHP(PLAYER_MAX_HP);
2535 playersao->setBreath(PLAYER_MAX_BREATH);
2537 SendPlayerHP(peer_id);
2538 SendPlayerBreath(peer_id);
2540 bool repositioned = m_script->on_respawnplayer(playersao);
2542 v3f pos = findSpawnPos();
2543 // setPos will send the new position to client
2544 playersao->setPos(pos);
2549 void Server::DenySudoAccess(u16 peer_id)
2551 DSTACK(__FUNCTION_NAME);
2553 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2558 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2559 const std::string &str_reason, bool reconnect)
2561 if (proto_ver >= 25) {
2562 SendAccessDenied(peer_id, reason, str_reason);
2564 std::wstring wreason = utf8_to_wide(
2565 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2566 accessDeniedStrings[(u8)reason]);
2567 SendAccessDenied_Legacy(peer_id, wreason);
2570 m_clients.event(peer_id, CSE_SetDenied);
2571 m_con.DisconnectPeer(peer_id);
2575 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2577 DSTACK(__FUNCTION_NAME);
2579 SendAccessDenied(peer_id, reason, custom_reason);
2580 m_clients.event(peer_id, CSE_SetDenied);
2581 m_con.DisconnectPeer(peer_id);
2584 // 13/03/15: remove this function when protocol version 25 will become
2585 // the minimum version for MT users, maybe in 1 year
2586 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2588 DSTACK(__FUNCTION_NAME);
2590 SendAccessDenied_Legacy(peer_id, reason);
2591 m_clients.event(peer_id, CSE_SetDenied);
2592 m_con.DisconnectPeer(peer_id);
2595 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2597 DSTACK(__FUNCTION_NAME);
2600 RemoteClient* client = getClient(peer_id, CS_Invalid);
2602 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2604 // Right now, the auth mechs don't change between login and sudo mode.
2605 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2606 client->allowed_sudo_mechs = sudo_auth_mechs;
2608 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2609 << g_settings->getFloat("dedicated_server_step")
2613 m_clients.event(peer_id, CSE_AuthAccept);
2615 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2617 // We only support SRP right now
2618 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2620 resp_pkt << sudo_auth_mechs;
2622 m_clients.event(peer_id, CSE_SudoSuccess);
2626 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2628 DSTACK(__FUNCTION_NAME);
2629 std::wstring message;
2632 Clear references to playing sounds
2634 for(std::map<s32, ServerPlayingSound>::iterator
2635 i = m_playing_sounds.begin();
2636 i != m_playing_sounds.end();)
2638 ServerPlayingSound &psound = i->second;
2639 psound.clients.erase(peer_id);
2640 if(psound.clients.empty())
2641 m_playing_sounds.erase(i++);
2646 Player *player = m_env->getPlayer(peer_id);
2648 // Collect information about leaving in chat
2650 if(player != NULL && reason != CDR_DENY)
2652 std::wstring name = narrow_to_wide(player->getName());
2655 message += L" left the game.";
2656 if(reason == CDR_TIMEOUT)
2657 message += L" (timed out)";
2661 /* Run scripts and remove from environment */
2665 PlayerSAO *playersao = player->getPlayerSAO();
2668 m_script->on_leaveplayer(playersao);
2670 playersao->disconnected();
2678 if(player != NULL && reason != CDR_DENY) {
2679 std::ostringstream os(std::ios_base::binary);
2680 std::vector<u16> clients = m_clients.getClientIDs();
2682 for(std::vector<u16>::iterator i = clients.begin();
2683 i != clients.end(); ++i) {
2685 Player *player = m_env->getPlayer(*i);
2689 // Get name of player
2690 os << player->getName() << " ";
2693 actionstream << player->getName() << " "
2694 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2695 << " List of players: " << os.str() << std::endl;
2699 MutexAutoLock env_lock(m_env_mutex);
2700 m_clients.DeleteClient(peer_id);
2704 // Send leave chat message to all remaining clients
2705 if(message.length() != 0)
2706 SendChatMessage(PEER_ID_INEXISTENT,message);
2709 void Server::UpdateCrafting(Player* player)
2711 DSTACK(__FUNCTION_NAME);
2713 // Get a preview for crafting
2715 InventoryLocation loc;
2716 loc.setPlayer(player->getName());
2717 std::vector<ItemStack> output_replacements;
2718 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2719 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2721 // Put the new preview in
2722 InventoryList *plist = player->inventory.getList("craftpreview");
2723 sanity_check(plist);
2724 sanity_check(plist->getSize() >= 1);
2725 plist->changeItem(0, preview);
2728 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2730 RemoteClient *client = getClientNoEx(peer_id,state_min);
2732 throw ClientNotFoundException("Client not found");
2736 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2738 return m_clients.getClientNoEx(peer_id, state_min);
2741 std::string Server::getPlayerName(u16 peer_id)
2743 Player *player = m_env->getPlayer(peer_id);
2745 return "[id="+itos(peer_id)+"]";
2746 return player->getName();
2749 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2751 Player *player = m_env->getPlayer(peer_id);
2754 return player->getPlayerSAO();
2757 std::wstring Server::getStatusString()
2759 std::wostringstream os(std::ios_base::binary);
2762 os<<L"version="<<narrow_to_wide(g_version_string);
2764 os<<L", uptime="<<m_uptime.get();
2766 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2767 // Information about clients
2770 std::vector<u16> clients = m_clients.getClientIDs();
2771 for(std::vector<u16>::iterator i = clients.begin();
2772 i != clients.end(); ++i) {
2774 Player *player = m_env->getPlayer(*i);
2775 // Get name of player
2776 std::wstring name = L"unknown";
2778 name = narrow_to_wide(player->getName());
2779 // Add name to information string
2787 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2788 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2789 if(g_settings->get("motd") != "")
2790 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2794 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2796 std::set<std::string> privs;
2797 m_script->getAuth(name, NULL, &privs);
2801 bool Server::checkPriv(const std::string &name, const std::string &priv)
2803 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2804 return (privs.count(priv) != 0);
2807 void Server::reportPrivsModified(const std::string &name)
2810 std::vector<u16> clients = m_clients.getClientIDs();
2811 for(std::vector<u16>::iterator i = clients.begin();
2812 i != clients.end(); ++i) {
2813 Player *player = m_env->getPlayer(*i);
2814 reportPrivsModified(player->getName());
2817 Player *player = m_env->getPlayer(name.c_str());
2820 SendPlayerPrivileges(player->peer_id);
2821 PlayerSAO *sao = player->getPlayerSAO();
2824 sao->updatePrivileges(
2825 getPlayerEffectivePrivs(name),
2830 void Server::reportInventoryFormspecModified(const std::string &name)
2832 Player *player = m_env->getPlayer(name.c_str());
2835 SendPlayerInventoryFormspec(player->peer_id);
2838 void Server::setIpBanned(const std::string &ip, const std::string &name)
2840 m_banmanager->add(ip, name);
2843 void Server::unsetIpBanned(const std::string &ip_or_name)
2845 m_banmanager->remove(ip_or_name);
2848 std::string Server::getBanDescription(const std::string &ip_or_name)
2850 return m_banmanager->getBanDescription(ip_or_name);
2853 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2855 // m_env will be NULL if the server is initializing
2859 Player *player = m_env->getPlayer(name);
2863 if (player->peer_id == PEER_ID_INEXISTENT)
2866 SendChatMessage(player->peer_id, msg);
2869 bool Server::showFormspec(const char *playername, const std::string &formspec,
2870 const std::string &formname)
2872 // m_env will be NULL if the server is initializing
2876 Player *player = m_env->getPlayer(playername);
2880 SendShowFormspecMessage(player->peer_id, formspec, formname);
2884 u32 Server::hudAdd(Player *player, HudElement *form)
2889 u32 id = player->addHud(form);
2891 SendHUDAdd(player->peer_id, id, form);
2896 bool Server::hudRemove(Player *player, u32 id) {
2900 HudElement* todel = player->removeHud(id);
2907 SendHUDRemove(player->peer_id, id);
2911 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2916 SendHUDChange(player->peer_id, id, stat, data);
2920 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2925 SendHUDSetFlags(player->peer_id, flags, mask);
2926 player->hud_flags = flags;
2928 PlayerSAO* playersao = player->getPlayerSAO();
2930 if (playersao == NULL)
2933 m_script->player_event(playersao, "hud_changed");
2937 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2941 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2944 player->setHotbarItemcount(hotbar_itemcount);
2945 std::ostringstream os(std::ios::binary);
2946 writeS32(os, hotbar_itemcount);
2947 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2951 s32 Server::hudGetHotbarItemcount(Player *player)
2955 return player->getHotbarItemcount();
2958 void Server::hudSetHotbarImage(Player *player, std::string name)
2963 player->setHotbarImage(name);
2964 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2967 std::string Server::hudGetHotbarImage(Player *player)
2971 return player->getHotbarImage();
2974 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2979 player->setHotbarSelectedImage(name);
2980 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2983 std::string Server::hudGetHotbarSelectedImage(Player *player)
2988 return player->getHotbarSelectedImage();
2991 bool Server::setLocalPlayerAnimations(Player *player,
2992 v2s32 animation_frames[4], f32 frame_speed)
2997 player->setLocalAnimations(animation_frames, frame_speed);
2998 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3002 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3007 player->eye_offset_first = first;
3008 player->eye_offset_third = third;
3009 SendEyeOffset(player->peer_id, first, third);
3013 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3014 const std::string &type, const std::vector<std::string> ¶ms)
3019 player->setSky(bgcolor, type, params);
3020 SendSetSky(player->peer_id, bgcolor, type, params);
3024 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3030 player->overrideDayNightRatio(do_override, ratio);
3031 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3035 void Server::notifyPlayers(const std::wstring &msg)
3037 SendChatMessage(PEER_ID_INEXISTENT,msg);
3040 void Server::spawnParticle(const std::string &playername, v3f pos,
3041 v3f velocity, v3f acceleration,
3042 float expirationtime, float size, bool
3043 collisiondetection, bool vertical, const std::string &texture)
3045 // m_env will be NULL if the server is initializing
3049 u16 peer_id = PEER_ID_INEXISTENT;
3050 if (playername != "") {
3051 Player* player = m_env->getPlayer(playername.c_str());
3054 peer_id = player->peer_id;
3057 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3058 expirationtime, size, collisiondetection, vertical, texture);
3061 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3062 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3063 float minexptime, float maxexptime, float minsize, float maxsize,
3064 bool collisiondetection, bool vertical, const std::string &texture,
3065 const std::string &playername)
3067 // m_env will be NULL if the server is initializing
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 // m_env will be NULL if the server is initializing
3104 throw ServerError("Can't delete particle spawners during initialisation!");
3106 u16 peer_id = PEER_ID_INEXISTENT;
3107 if (playername != "") {
3108 Player* player = m_env->getPlayer(playername.c_str());
3111 peer_id = player->peer_id;
3114 m_particlespawner_ids.erase(
3115 std::remove(m_particlespawner_ids.begin(),
3116 m_particlespawner_ids.end(), id),
3117 m_particlespawner_ids.end());
3118 SendDeleteParticleSpawner(peer_id, id);
3121 Inventory* Server::createDetachedInventory(const std::string &name)
3123 if(m_detached_inventories.count(name) > 0){
3124 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3125 delete m_detached_inventories[name];
3127 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3129 Inventory *inv = new Inventory(m_itemdef);
3131 m_detached_inventories[name] = inv;
3132 //TODO find a better way to do this
3133 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3137 // actions: time-reversed list
3138 // Return value: success/failure
3139 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3140 std::list<std::string> *log)
3142 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3143 ServerMap *map = (ServerMap*)(&m_env->getMap());
3145 // Fail if no actions to handle
3146 if(actions.empty()){
3147 log->push_back("Nothing to do.");
3154 for(std::list<RollbackAction>::const_iterator
3155 i = actions.begin();
3156 i != actions.end(); i++)
3158 const RollbackAction &action = *i;
3160 bool success = action.applyRevert(map, this, this);
3163 std::ostringstream os;
3164 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3165 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3167 log->push_back(os.str());
3169 std::ostringstream os;
3170 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3171 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3173 log->push_back(os.str());
3177 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3178 <<" failed"<<std::endl;
3180 // Call it done if less than half failed
3181 return num_failed <= num_tried/2;
3184 // IGameDef interface
3186 IItemDefManager *Server::getItemDefManager()
3191 INodeDefManager *Server::getNodeDefManager()
3196 ICraftDefManager *Server::getCraftDefManager()
3200 ITextureSource *Server::getTextureSource()
3204 IShaderSource *Server::getShaderSource()
3208 scene::ISceneManager *Server::getSceneManager()
3213 u16 Server::allocateUnknownNodeId(const std::string &name)
3215 return m_nodedef->allocateDummy(name);
3218 ISoundManager *Server::getSoundManager()
3220 return &dummySoundManager;
3223 MtEventManager *Server::getEventManager()
3228 IWritableItemDefManager *Server::getWritableItemDefManager()
3233 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3238 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3243 const ModSpec *Server::getModSpec(const std::string &modname) const
3245 std::vector<ModSpec>::const_iterator it;
3246 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3247 const ModSpec &mod = *it;
3248 if (mod.name == modname)
3254 void Server::getModNames(std::vector<std::string> &modlist)
3256 std::vector<ModSpec>::iterator it;
3257 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3258 modlist.push_back(it->name);
3261 std::string Server::getBuiltinLuaPath()
3263 return porting::path_share + DIR_DELIM + "builtin";
3266 v3f Server::findSpawnPos()
3268 ServerMap &map = m_env->getServerMap();
3270 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3271 return nodeposf * BS;
3274 // Default position is static_spawnpoint
3275 // We will return it if we don't found a good place
3276 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3278 s16 water_level = map.getWaterLevel();
3280 bool is_good = false;
3282 // Try to find a good place a few times
3283 for(s32 i = 0; i < 1000 && !is_good; i++) {
3285 // We're going to try to throw the player to this position
3286 v2s16 nodepos2d = v2s16(
3287 -range + (myrand() % (range * 2)),
3288 -range + (myrand() % (range * 2)));
3290 // Get ground height at point
3291 s16 groundheight = map.findGroundLevel(nodepos2d);
3292 if (groundheight <= water_level) // Don't go underwater
3294 if (groundheight > water_level + 6) // Don't go to high places
3297 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3300 for (s32 i = 0; i < 10; i++) {
3301 v3s16 blockpos = getNodeBlockPos(nodepos);
3302 map.emergeBlock(blockpos, true);
3303 content_t c = map.getNodeNoEx(nodepos).getContent();
3304 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3306 if (air_count >= 2){
3315 return intToFloat(nodepos, BS);
3318 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3320 bool newplayer = false;
3323 Try to get an existing player
3325 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3327 // If player is already connected, cancel
3328 if(player != NULL && player->peer_id != 0)
3330 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3335 If player with the wanted peer_id already exists, cancel.
3337 if(m_env->getPlayer(peer_id) != NULL)
3339 infostream<<"emergePlayer(): Player with wrong name but same"
3340 " peer_id already exists"<<std::endl;
3344 // Load player if it isn't already loaded
3346 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3349 // Create player if it doesn't exist
3352 player = new RemotePlayer(this, name);
3353 // Set player position
3354 infostream<<"Server: Finding spawn place for player \""
3355 <<name<<"\""<<std::endl;
3356 v3f pos = findSpawnPos();
3357 player->setPosition(pos);
3359 // Make sure the player is saved
3360 player->setModified(true);
3362 // Add player to environment
3363 m_env->addPlayer(player);
3366 // Create a new player active object
3367 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3368 getPlayerEffectivePrivs(player->getName()),
3371 player->protocol_version = proto_version;
3373 /* Clean up old HUD elements from previous sessions */
3376 /* Add object to environment */
3377 m_env->addActiveObject(playersao);
3381 m_script->on_newplayer(playersao);
3387 void dedicated_server_loop(Server &server, bool &kill)
3389 DSTACK(__FUNCTION_NAME);
3391 verbosestream<<"dedicated_server_loop()"<<std::endl;
3393 IntervalLimiter m_profiler_interval;
3397 float steplen = g_settings->getFloat("dedicated_server_step");
3398 // This is kind of a hack but can be done like this
3399 // because server.step() is very light
3401 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3402 sleep_ms((int)(steplen*1000.0));
3404 server.step(steplen);
3406 if(server.getShutdownRequested() || kill)
3408 infostream<<"Dedicated server quitting"<<std::endl;
3410 if(g_settings->getBool("server_announce"))
3411 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3419 float profiler_print_interval =
3420 g_settings->getFloat("profiler_print_interval");
3421 if(profiler_print_interval != 0)
3423 if(m_profiler_interval.step(steplen, profiler_print_interval))
3425 infostream<<"Profiler:"<<std::endl;
3426 g_profiler->print(infostream);
3427 g_profiler->clear();