3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public Thread
78 ServerThread(Server *server):
89 void *ServerThread::run()
91 DSTACK(FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
94 m_server->AsyncRunStep(true);
96 while (!stopRequested()) {
98 //TimeTaker timer("AsyncRunStep() + Receive()");
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
115 END_DEBUG_EXCEPTION_HANDLER
120 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
122 if(pos_exists) *pos_exists = false;
127 if(pos_exists) *pos_exists = true;
132 ServerActiveObject *sao = env->getActiveObject(object);
135 if(pos_exists) *pos_exists = true;
136 return sao->getBasePosition(); }
148 const std::string &path_world,
149 const SubgameSpec &gamespec,
150 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_async_fatal_error(""),
166 m_enable_rollback_recording(false),
169 m_itemdef(createItemDefManager()),
170 m_nodedef(createNodeDefManager()),
171 m_craftdef(createCraftDefManager()),
172 m_event(new EventManager()),
174 m_time_of_day_send_timer(0),
177 m_shutdown_requested(false),
178 m_shutdown_ask_reconnect(false),
180 m_ignore_map_edit_events(false),
181 m_ignore_map_edit_events_peer_id(0),
185 m_liquid_transform_timer = 0.0;
186 m_liquid_transform_every = 1.0;
187 m_print_info_timer = 0.0;
188 m_masterserver_timer = 0.0;
189 m_objectdata_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if(!modconf.isConsistent()) {
229 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
230 it != unsatisfied_mods.end(); ++it) {
232 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
233 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
234 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
235 errorstream << " \"" << *dep_it << "\"";
236 errorstream << std::endl;
240 Settings worldmt_settings;
241 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
242 worldmt_settings.readConfigFile(worldmt.c_str());
243 std::vector<std::string> names = worldmt_settings.getNames();
244 std::set<std::string> load_mod_names;
245 for(std::vector<std::string>::iterator it = names.begin();
246 it != names.end(); ++it) {
247 std::string name = *it;
248 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
249 load_mod_names.insert(name.substr(9));
251 // complain about mods declared to be loaded, but not found
252 for(std::vector<ModSpec>::iterator it = m_mods.begin();
253 it != m_mods.end(); ++it)
254 load_mod_names.erase((*it).name);
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
257 load_mod_names.erase((*it).name);
258 if(!load_mod_names.empty()) {
259 errorstream << "The following mods could not be found:";
260 for(std::set<std::string>::iterator it = load_mod_names.begin();
261 it != load_mod_names.end(); ++it)
262 errorstream << " \"" << (*it) << "\"";
263 errorstream << std::endl;
267 MutexAutoLock envlock(m_env_mutex);
269 // Load mapgen params from Settings
270 m_emerge->loadMapgenParams();
272 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
273 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
275 // Initialize scripting
276 infostream<<"Server: Initializing Lua"<<std::endl;
278 m_script = new GameScripting(this);
280 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
282 m_script->loadMod(script_path, BUILTIN_MOD_NAME);
285 infostream << "Server: Loading mods: ";
286 for(std::vector<ModSpec>::iterator i = m_mods.begin();
287 i != m_mods.end(); ++i) {
288 const ModSpec &mod = *i;
289 infostream << mod.name << " ";
291 infostream << std::endl;
292 // Load and run "mod" scripts
293 for (std::vector<ModSpec>::iterator it = m_mods.begin();
294 it != m_mods.end(); ++it) {
295 const ModSpec &mod = *it;
296 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
297 throw ModError("Error loading mod \"" + mod.name +
298 "\": Mod name does not follow naming conventions: "
299 "Only chararacters [a-z0-9_] are allowed.");
301 std::string script_path = mod.path + DIR_DELIM + "init.lua";
302 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
303 << script_path << "\"]" << std::endl;
304 m_script->loadMod(script_path, mod.name);
307 // Read Textures and calculate sha1 sums
310 // Apply item aliases in the node definition manager
311 m_nodedef->updateAliases(m_itemdef);
313 // Apply texture overrides from texturepack/override.txt
314 std::string texture_path = g_settings->get("texture_path");
315 if (texture_path != "" && fs::IsDir(texture_path))
316 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
318 m_nodedef->setNodeRegistrationStatus(true);
320 // Perform pending node name resolutions
321 m_nodedef->runNodeResolveCallbacks();
323 // init the recipe hashes to speed up crafting
324 m_craftdef->initHashes(this);
326 // Initialize Environment
327 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
329 m_clients.setEnv(m_env);
331 // Initialize mapgens
332 m_emerge->initMapgens();
334 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
335 if (m_enable_rollback_recording) {
336 // Create rollback manager
337 m_rollback = new RollbackManager(m_path_world, this);
340 // Give environment reference to scripting api
341 m_script->initializeEnvironment(m_env);
343 // Register us to receive map edit events
344 servermap->addEventReceiver(this);
346 // If file exists, load environment metadata
347 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
349 infostream<<"Server: Loading environment metadata"<<std::endl;
353 // Add some test ActiveBlockModifiers to environment
354 add_legacy_abms(m_env, m_nodedef);
356 m_liquid_transform_every = g_settings->getFloat("liquid_update");
361 infostream<<"Server destructing"<<std::endl;
363 // Send shutdown message
364 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
367 MutexAutoLock envlock(m_env_mutex);
369 // Execute script shutdown hooks
370 m_script->on_shutdown();
372 infostream << "Server: Saving players" << std::endl;
373 m_env->saveLoadedPlayers();
375 infostream << "Server: Kicking players" << std::endl;
376 std::string kick_msg;
377 bool reconnect = false;
378 if (getShutdownRequested()) {
379 reconnect = m_shutdown_ask_reconnect;
380 kick_msg = m_shutdown_msg;
382 if (kick_msg == "") {
383 kick_msg = g_settings->get("kick_msg_shutdown");
385 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
386 kick_msg, reconnect);
388 infostream << "Server: Saving environment metadata" << std::endl;
396 // stop all emerge threads before deleting players that may have
397 // requested blocks to be emerged
398 m_emerge->stopThreads();
400 // Delete things in the reverse order of creation
403 // N.B. the EmergeManager should be deleted after the Environment since Map
404 // depends on EmergeManager to write its current params to the map meta
413 // Deinitialize scripting
414 infostream<<"Server: Deinitializing scripting"<<std::endl;
417 // Delete detached inventories
418 for (std::map<std::string, Inventory*>::iterator
419 i = m_detached_inventories.begin();
420 i != m_detached_inventories.end(); ++i) {
425 void Server::start(Address bind_addr)
427 DSTACK(FUNCTION_NAME);
429 m_bind_addr = bind_addr;
431 infostream<<"Starting server on "
432 << bind_addr.serializeString() <<"..."<<std::endl;
434 // Stop thread if already running
437 // Initialize connection
438 m_con.SetTimeoutMs(30);
439 m_con.Serve(bind_addr);
444 // ASCII art for the win!
446 <<" .__ __ __ "<<std::endl
447 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
448 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
449 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
450 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
451 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
452 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
453 actionstream<<"Server for gameid=\""<<m_gamespec.id
454 <<"\" listening on "<<bind_addr.serializeString()<<":"
455 <<bind_addr.getPort() << "."<<std::endl;
460 DSTACK(FUNCTION_NAME);
462 infostream<<"Server: Stopping and waiting threads"<<std::endl;
464 // Stop threads (set run=false first so both start stopping)
466 //m_emergethread.setRun(false);
468 //m_emergethread.stop();
470 infostream<<"Server: Threads stopped"<<std::endl;
473 void Server::step(float dtime)
475 DSTACK(FUNCTION_NAME);
480 MutexAutoLock lock(m_step_dtime_mutex);
481 m_step_dtime += dtime;
483 // Throw if fatal error occurred in thread
484 std::string async_err = m_async_fatal_error.get();
485 if (!async_err.empty()) {
486 if (!m_simple_singleplayer_mode) {
487 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
488 g_settings->get("kick_msg_crash"),
489 g_settings->getBool("ask_reconnect_on_crash"));
491 throw ServerError(async_err);
495 void Server::AsyncRunStep(bool initial_step)
497 DSTACK(FUNCTION_NAME);
499 g_profiler->add("Server::AsyncRunStep (num)", 1);
503 MutexAutoLock lock1(m_step_dtime_mutex);
504 dtime = m_step_dtime;
508 // Send blocks to clients
512 if((dtime < 0.001) && (initial_step == false))
515 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
517 //infostream<<"Server steps "<<dtime<<std::endl;
518 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
521 MutexAutoLock lock1(m_step_dtime_mutex);
522 m_step_dtime -= dtime;
529 m_uptime.set(m_uptime.get() + dtime);
535 Update time of day and overall game time
537 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
540 Send to clients at constant intervals
543 m_time_of_day_send_timer -= dtime;
544 if(m_time_of_day_send_timer < 0.0) {
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
552 MutexAutoLock lock(m_env_mutex);
553 // Figure out and report maximum lag to environment
554 float max_lag = m_env->getMaxLagEstimate();
555 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
557 if(dtime > 0.1 && dtime > max_lag * 2.0)
558 infostream<<"Server: Maximum lag peaked to "<<dtime
562 m_env->reportMaxLagEstimate(max_lag);
564 ScopeProfiler sp(g_profiler, "SEnv step");
565 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
569 static const float map_timer_and_unload_dtime = 2.92;
570 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
572 MutexAutoLock lock(m_env_mutex);
573 // Run Map's timers and unload unused data
574 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
575 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
576 g_settings->getFloat("server_unload_unused_data_timeout"),
581 Listen to the admin chat, if available
584 if (!m_admin_chat->command_queue.empty()) {
585 MutexAutoLock lock(m_env_mutex);
586 while (!m_admin_chat->command_queue.empty()) {
587 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
588 handleChatInterfaceEvent(evt);
592 m_admin_chat->outgoing_queue.push_back(
593 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
600 /* Transform liquids */
601 m_liquid_transform_timer += dtime;
602 if(m_liquid_transform_timer >= m_liquid_transform_every)
604 m_liquid_transform_timer -= m_liquid_transform_every;
606 MutexAutoLock lock(m_env_mutex);
608 ScopeProfiler sp(g_profiler, "Server: liquid transform");
610 std::map<v3s16, MapBlock*> modified_blocks;
611 m_env->getMap().transformLiquids(modified_blocks);
616 core::map<v3s16, MapBlock*> lighting_modified_blocks;
617 ServerMap &map = ((ServerMap&)m_env->getMap());
618 map.updateLighting(modified_blocks, lighting_modified_blocks);
620 // Add blocks modified by lighting to modified_blocks
621 for(core::map<v3s16, MapBlock*>::Iterator
622 i = lighting_modified_blocks.getIterator();
623 i.atEnd() == false; i++)
625 MapBlock *block = i.getNode()->getValue();
626 modified_blocks.insert(block->getPos(), block);
630 Set the modified blocks unsent for all the clients
632 if(!modified_blocks.empty())
634 SetBlocksNotSent(modified_blocks);
637 m_clients.step(dtime);
639 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
641 // send masterserver announce
643 float &counter = m_masterserver_timer;
644 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
645 g_settings->getBool("server_announce"))
647 ServerList::sendAnnounce(counter ? "update" : "start",
648 m_bind_addr.getPort(),
649 m_clients.getPlayerNames(),
651 m_env->getGameTime(),
654 m_emerge->params.mg_name,
663 Check added and deleted active objects
666 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
667 MutexAutoLock envlock(m_env_mutex);
670 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
671 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
673 // Radius inside which objects are active
674 s16 radius = g_settings->getS16("active_object_send_range_blocks");
675 s16 player_radius = g_settings->getS16("player_transfer_distance");
677 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
678 !g_settings->getBool("unlimited_player_transfer_distance"))
679 player_radius = radius;
681 radius *= MAP_BLOCKSIZE;
682 player_radius *= MAP_BLOCKSIZE;
684 for (std::map<u16, RemoteClient*>::iterator
686 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);
696 // This can happen if the client timeouts somehow
697 /*warningstream<<FUNCTION_NAME<<": Client "
699 <<" has no associated player"<<std::endl;*/
703 std::queue<u16> removed_objects;
704 std::queue<u16> added_objects;
705 m_env->getRemovedActiveObjects(player, radius, player_radius,
706 client->m_known_objects, removed_objects);
707 m_env->getAddedActiveObjects(player, radius, player_radius,
708 client->m_known_objects, added_objects);
710 // Ignore if nothing happened
711 if (removed_objects.empty() && added_objects.empty()) {
715 std::string data_buffer;
719 // Handle removed objects
720 writeU16((u8*)buf, removed_objects.size());
721 data_buffer.append(buf, 2);
722 while (!removed_objects.empty()) {
724 u16 id = removed_objects.front();
725 ServerActiveObject* obj = m_env->getActiveObject(id);
727 // Add to data buffer for sending
728 writeU16((u8*)buf, id);
729 data_buffer.append(buf, 2);
731 // Remove from known objects
732 client->m_known_objects.erase(id);
734 if(obj && obj->m_known_by_count > 0)
735 obj->m_known_by_count--;
736 removed_objects.pop();
739 // Handle added objects
740 writeU16((u8*)buf, added_objects.size());
741 data_buffer.append(buf, 2);
742 while (!added_objects.empty()) {
744 u16 id = added_objects.front();
745 ServerActiveObject* obj = m_env->getActiveObject(id);
748 u8 type = ACTIVEOBJECT_TYPE_INVALID;
750 warningstream<<FUNCTION_NAME
751 <<": NULL object"<<std::endl;
753 type = obj->getSendType();
755 // Add to data buffer for sending
756 writeU16((u8*)buf, id);
757 data_buffer.append(buf, 2);
758 writeU8((u8*)buf, type);
759 data_buffer.append(buf, 1);
762 data_buffer.append(serializeLongString(
763 obj->getClientInitializationData(client->net_proto_version)));
765 data_buffer.append(serializeLongString(""));
767 // Add to known objects
768 client->m_known_objects.insert(id);
771 obj->m_known_by_count++;
776 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
777 verbosestream << "Server: Sent object remove/add: "
778 << removed_objects.size() << " removed, "
779 << added_objects.size() << " added, "
780 << "packet size is " << pktSize << std::endl;
789 MutexAutoLock envlock(m_env_mutex);
790 ScopeProfiler sp(g_profiler, "Server: sending object messages");
793 // Value = data sent by object
794 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
796 // Get active object messages from environment
798 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
802 std::vector<ActiveObjectMessage>* message_list = NULL;
803 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
804 n = buffered_messages.find(aom.id);
805 if (n == buffered_messages.end()) {
806 message_list = new std::vector<ActiveObjectMessage>;
807 buffered_messages[aom.id] = message_list;
810 message_list = n->second;
812 message_list->push_back(aom);
816 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
817 // Route data to every client
818 for (std::map<u16, RemoteClient*>::iterator
820 i != clients.end(); ++i) {
821 RemoteClient *client = i->second;
822 std::string reliable_data;
823 std::string unreliable_data;
824 // Go through all objects in message buffer
825 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
826 j = buffered_messages.begin();
827 j != buffered_messages.end(); ++j) {
828 // If object is not known by client, skip it
830 if (client->m_known_objects.find(id) == client->m_known_objects.end())
833 // Get message list of object
834 std::vector<ActiveObjectMessage>* list = j->second;
835 // Go through every message
836 for (std::vector<ActiveObjectMessage>::iterator
837 k = list->begin(); k != list->end(); ++k) {
838 // Compose the full new data with header
839 ActiveObjectMessage aom = *k;
840 std::string new_data;
843 writeU16((u8*)&buf[0], aom.id);
844 new_data.append(buf, 2);
846 new_data += serializeString(aom.datastring);
847 // Add data to buffer
849 reliable_data += new_data;
851 unreliable_data += new_data;
855 reliable_data and unreliable_data are now ready.
858 if(reliable_data.size() > 0) {
859 SendActiveObjectMessages(client->peer_id, reliable_data);
862 if(unreliable_data.size() > 0) {
863 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
868 // Clear buffered_messages
869 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
870 i = buffered_messages.begin();
871 i != buffered_messages.end(); ++i) {
877 Send queued-for-sending map edit events.
880 // We will be accessing the environment
881 MutexAutoLock lock(m_env_mutex);
883 // Don't send too many at a time
886 // Single change sending is disabled if queue size is not small
887 bool disable_single_change_sending = false;
888 if(m_unsent_map_edit_queue.size() >= 4)
889 disable_single_change_sending = true;
891 int event_count = m_unsent_map_edit_queue.size();
893 // We'll log the amount of each
896 while(m_unsent_map_edit_queue.size() != 0)
898 MapEditEvent* event = m_unsent_map_edit_queue.front();
899 m_unsent_map_edit_queue.pop();
901 // Players far away from the change are stored here.
902 // Instead of sending the changes, MapBlocks are set not sent
904 std::vector<u16> far_players;
906 switch (event->type) {
909 prof.add("MEET_ADDNODE", 1);
910 sendAddNode(event->p, event->n, event->already_known_by_peer,
911 &far_players, disable_single_change_sending ? 5 : 30,
912 event->type == MEET_ADDNODE);
914 case MEET_REMOVENODE:
915 prof.add("MEET_REMOVENODE", 1);
916 sendRemoveNode(event->p, event->already_known_by_peer,
917 &far_players, disable_single_change_sending ? 5 : 30);
919 case MEET_BLOCK_NODE_METADATA_CHANGED:
920 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
921 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
922 setBlockNotSent(event->p);
925 infostream << "Server: MEET_OTHER" << std::endl;
926 prof.add("MEET_OTHER", 1);
927 for(std::set<v3s16>::iterator
928 i = event->modified_blocks.begin();
929 i != event->modified_blocks.end(); ++i) {
934 prof.add("unknown", 1);
935 warningstream << "Server: Unknown MapEditEvent "
936 << ((u32)event->type) << std::endl;
941 Set blocks not sent to far players
943 if(!far_players.empty()) {
944 // Convert list format to that wanted by SetBlocksNotSent
945 std::map<v3s16, MapBlock*> modified_blocks2;
946 for(std::set<v3s16>::iterator
947 i = event->modified_blocks.begin();
948 i != event->modified_blocks.end(); ++i) {
949 modified_blocks2[*i] =
950 m_env->getMap().getBlockNoCreateNoEx(*i);
953 // Set blocks not sent
954 for(std::vector<u16>::iterator
955 i = far_players.begin();
956 i != far_players.end(); ++i) {
957 if(RemoteClient *client = getClient(*i))
958 client->SetBlocksNotSent(modified_blocks2);
964 /*// Don't send too many at a time
966 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
970 if(event_count >= 5){
971 infostream<<"Server: MapEditEvents:"<<std::endl;
972 prof.print(infostream);
973 } else if(event_count != 0){
974 verbosestream<<"Server: MapEditEvents:"<<std::endl;
975 prof.print(verbosestream);
981 Trigger emergethread (it somehow gets to a non-triggered but
982 bysy state sometimes)
985 float &counter = m_emergethread_trigger_timer;
991 m_emerge->startThreads();
995 // Save map, players and auth stuff
997 float &counter = m_savemap_timer;
999 if(counter >= g_settings->getFloat("server_map_save_interval"))
1002 MutexAutoLock lock(m_env_mutex);
1004 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1007 if (m_banmanager->isModified()) {
1008 m_banmanager->save();
1011 // Save changed parts of map
1012 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1015 m_env->saveLoadedPlayers();
1017 // Save environment metadata
1023 void Server::Receive()
1025 DSTACK(FUNCTION_NAME);
1026 SharedBuffer<u8> data;
1030 m_con.Receive(&pkt);
1031 peer_id = pkt.getPeerId();
1034 catch(con::InvalidIncomingDataException &e) {
1035 infostream<<"Server::Receive(): "
1036 "InvalidIncomingDataException: what()="
1037 <<e.what()<<std::endl;
1039 catch(SerializationError &e) {
1040 infostream<<"Server::Receive(): "
1041 "SerializationError: what()="
1042 <<e.what()<<std::endl;
1044 catch(ClientStateError &e) {
1045 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1046 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1047 L"Try reconnecting or updating your client");
1049 catch(con::PeerNotFoundException &e) {
1054 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1056 std::string playername = "";
1057 PlayerSAO *playersao = NULL;
1060 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1061 if (client != NULL) {
1062 playername = client->getName();
1063 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1065 } catch (std::exception &e) {
1071 RemotePlayer *player =
1072 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1074 // If failed, cancel
1075 if ((playersao == NULL) || (player == NULL)) {
1076 if (player && player->peer_id != 0) {
1077 actionstream << "Server: Failed to emerge player \"" << playername
1078 << "\" (player allocated to an another client)" << std::endl;
1079 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1080 L"name. If your client closed unexpectedly, try again in "
1083 errorstream << "Server: " << playername << ": Failed to emerge player"
1085 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1091 Send complete position information
1093 SendMovePlayer(peer_id);
1096 SendPlayerPrivileges(peer_id);
1098 // Send inventory formspec
1099 SendPlayerInventoryFormspec(peer_id);
1102 SendInventory(playersao);
1105 SendPlayerHPOrDie(playersao);
1108 SendPlayerBreath(peer_id);
1110 // Show death screen if necessary
1111 if(player->isDead())
1112 SendDeathscreen(peer_id, false, v3f(0,0,0));
1114 // Note things in chat if not in simple singleplayer mode
1115 if(!m_simple_singleplayer_mode) {
1116 // Send information about server to player in chat
1117 SendChatMessage(peer_id, getStatusString());
1119 // Send information about joining in chat
1121 std::string name = "unknown";
1122 Player *player = m_env->getPlayer(peer_id);
1124 name = player->getName();
1126 std::wstring message;
1128 message += narrow_to_wide(name);
1129 message += L" joined the game.";
1130 SendChatMessage(PEER_ID_INEXISTENT,message);
1132 m_admin_chat->outgoing_queue.push_back(
1133 new ChatEventNick(CET_NICK_ADD, name));
1136 Address addr = getPeerAddress(player->peer_id);
1137 std::string ip_str = addr.serializeString();
1138 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1143 std::vector<std::string> names = m_clients.getPlayerNames();
1145 actionstream<<player->getName() <<" joins game. List of players: ";
1147 for (std::vector<std::string>::iterator i = names.begin();
1148 i != names.end(); ++i) {
1149 actionstream << *i << " ";
1152 actionstream << player->getName() <<std::endl;
1157 inline void Server::handleCommand(NetworkPacket* pkt)
1159 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1160 (this->*opHandle.handler)(pkt);
1163 void Server::ProcessData(NetworkPacket *pkt)
1165 DSTACK(FUNCTION_NAME);
1166 // Environment is locked first.
1167 MutexAutoLock envlock(m_env_mutex);
1169 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1170 u32 peer_id = pkt->getPeerId();
1173 Address address = getPeerAddress(peer_id);
1174 std::string addr_s = address.serializeString();
1176 if(m_banmanager->isIpBanned(addr_s)) {
1177 std::string ban_name = m_banmanager->getBanName(addr_s);
1178 infostream << "Server: A banned client tried to connect from "
1179 << addr_s << "; banned name was "
1180 << ban_name << std::endl;
1181 // This actually doesn't seem to transfer to the client
1182 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1183 + utf8_to_wide(ban_name));
1187 catch(con::PeerNotFoundException &e) {
1189 * no peer for this packet found
1190 * most common reason is peer timeout, e.g. peer didn't
1191 * respond for some time, your server was overloaded or
1194 infostream << "Server::ProcessData(): Canceling: peer "
1195 << peer_id << " not found" << std::endl;
1200 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1202 // Command must be handled into ToServerCommandHandler
1203 if (command >= TOSERVER_NUM_MSG_TYPES) {
1204 infostream << "Server: Ignoring unknown command "
1205 << command << std::endl;
1209 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1214 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1216 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1217 errorstream << "Server::ProcessData(): Cancelling: Peer"
1218 " serialization format invalid or not initialized."
1219 " Skipping incoming command=" << command << std::endl;
1223 /* Handle commands related to client startup */
1224 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1229 if (m_clients.getClientState(peer_id) < CS_Active) {
1230 if (command == TOSERVER_PLAYERPOS) return;
1232 errorstream << "Got packet command: " << command << " for peer id "
1233 << peer_id << " but client isn't active yet. Dropping packet "
1239 } catch (SendFailedException &e) {
1240 errorstream << "Server::ProcessData(): SendFailedException: "
1241 << "what=" << e.what()
1243 } catch (PacketError &e) {
1244 actionstream << "Server::ProcessData(): PacketError: "
1245 << "what=" << e.what()
1250 void Server::setTimeOfDay(u32 time)
1252 m_env->setTimeOfDay(time);
1253 m_time_of_day_send_timer = 0;
1256 void Server::onMapEditEvent(MapEditEvent *event)
1258 if(m_ignore_map_edit_events)
1260 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1262 MapEditEvent *e = event->clone();
1263 m_unsent_map_edit_queue.push(e);
1266 Inventory* Server::getInventory(const InventoryLocation &loc)
1269 case InventoryLocation::UNDEFINED:
1270 case InventoryLocation::CURRENT_PLAYER:
1272 case InventoryLocation::PLAYER:
1274 Player *player = m_env->getPlayer(loc.name.c_str());
1277 PlayerSAO *playersao = player->getPlayerSAO();
1280 return playersao->getInventory();
1283 case InventoryLocation::NODEMETA:
1285 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1288 return meta->getInventory();
1291 case InventoryLocation::DETACHED:
1293 if(m_detached_inventories.count(loc.name) == 0)
1295 return m_detached_inventories[loc.name];
1299 sanity_check(false); // abort
1304 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1307 case InventoryLocation::UNDEFINED:
1309 case InventoryLocation::PLAYER:
1314 Player *player = m_env->getPlayer(loc.name.c_str());
1317 PlayerSAO *playersao = player->getPlayerSAO();
1321 SendInventory(playersao);
1324 case InventoryLocation::NODEMETA:
1326 v3s16 blockpos = getNodeBlockPos(loc.p);
1328 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1330 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1332 setBlockNotSent(blockpos);
1335 case InventoryLocation::DETACHED:
1337 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1341 sanity_check(false); // abort
1346 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1348 std::vector<u16> clients = m_clients.getClientIDs();
1350 // Set the modified blocks unsent for all the clients
1351 for (std::vector<u16>::iterator i = clients.begin();
1352 i != clients.end(); ++i) {
1353 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1354 client->SetBlocksNotSent(block);
1359 void Server::peerAdded(con::Peer *peer)
1361 DSTACK(FUNCTION_NAME);
1362 verbosestream<<"Server::peerAdded(): peer->id="
1363 <<peer->id<<std::endl;
1366 c.type = con::PEER_ADDED;
1367 c.peer_id = peer->id;
1369 m_peer_change_queue.push(c);
1372 void Server::deletingPeer(con::Peer *peer, bool timeout)
1374 DSTACK(FUNCTION_NAME);
1375 verbosestream<<"Server::deletingPeer(): peer->id="
1376 <<peer->id<<", timeout="<<timeout<<std::endl;
1378 m_clients.event(peer->id, CSE_Disconnect);
1380 c.type = con::PEER_REMOVED;
1381 c.peer_id = peer->id;
1382 c.timeout = timeout;
1383 m_peer_change_queue.push(c);
1386 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1388 *retval = m_con.getPeerStat(peer_id,type);
1389 if (*retval == -1) return false;
1393 bool Server::getClientInfo(
1402 std::string* vers_string
1405 *state = m_clients.getClientState(peer_id);
1407 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1409 if (client == NULL) {
1414 *uptime = client->uptime();
1415 *ser_vers = client->serialization_version;
1416 *prot_vers = client->net_proto_version;
1418 *major = client->getMajor();
1419 *minor = client->getMinor();
1420 *patch = client->getPatch();
1421 *vers_string = client->getPatch();
1428 void Server::handlePeerChanges()
1430 while(m_peer_change_queue.size() > 0)
1432 con::PeerChange c = m_peer_change_queue.front();
1433 m_peer_change_queue.pop();
1435 verbosestream<<"Server: Handling peer change: "
1436 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1441 case con::PEER_ADDED:
1442 m_clients.CreateClient(c.peer_id);
1445 case con::PEER_REMOVED:
1446 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1450 FATAL_ERROR("Invalid peer change event received!");
1456 void Server::printToConsoleOnly(const std::string &text)
1459 m_admin_chat->outgoing_queue.push_back(
1460 new ChatEventChat("", utf8_to_wide(text)));
1462 std::cout << text << std::endl;
1466 void Server::Send(NetworkPacket* pkt)
1468 m_clients.send(pkt->getPeerId(),
1469 clientCommandFactoryTable[pkt->getCommand()].channel,
1471 clientCommandFactoryTable[pkt->getCommand()].reliable);
1474 void Server::SendMovement(u16 peer_id)
1476 DSTACK(FUNCTION_NAME);
1477 std::ostringstream os(std::ios_base::binary);
1479 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1481 pkt << g_settings->getFloat("movement_acceleration_default");
1482 pkt << g_settings->getFloat("movement_acceleration_air");
1483 pkt << g_settings->getFloat("movement_acceleration_fast");
1484 pkt << g_settings->getFloat("movement_speed_walk");
1485 pkt << g_settings->getFloat("movement_speed_crouch");
1486 pkt << g_settings->getFloat("movement_speed_fast");
1487 pkt << g_settings->getFloat("movement_speed_climb");
1488 pkt << g_settings->getFloat("movement_speed_jump");
1489 pkt << g_settings->getFloat("movement_liquid_fluidity");
1490 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1491 pkt << g_settings->getFloat("movement_liquid_sink");
1492 pkt << g_settings->getFloat("movement_gravity");
1497 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1499 if (!g_settings->getBool("enable_damage"))
1502 u16 peer_id = playersao->getPeerID();
1503 bool is_alive = playersao->getHP() > 0;
1506 SendPlayerHP(peer_id);
1511 void Server::SendHP(u16 peer_id, u8 hp)
1513 DSTACK(FUNCTION_NAME);
1515 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1520 void Server::SendBreath(u16 peer_id, u16 breath)
1522 DSTACK(FUNCTION_NAME);
1524 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1525 pkt << (u16) breath;
1529 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1530 const std::string &custom_reason, bool reconnect)
1532 assert(reason < SERVER_ACCESSDENIED_MAX);
1534 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1536 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1537 pkt << custom_reason;
1538 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1539 reason == SERVER_ACCESSDENIED_CRASH)
1540 pkt << custom_reason << (u8)reconnect;
1544 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1546 DSTACK(FUNCTION_NAME);
1548 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1553 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1554 v3f camera_point_target)
1556 DSTACK(FUNCTION_NAME);
1558 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1559 pkt << set_camera_point_target << camera_point_target;
1563 void Server::SendItemDef(u16 peer_id,
1564 IItemDefManager *itemdef, u16 protocol_version)
1566 DSTACK(FUNCTION_NAME);
1568 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1572 u32 length of the next item
1573 zlib-compressed serialized ItemDefManager
1575 std::ostringstream tmp_os(std::ios::binary);
1576 itemdef->serialize(tmp_os, protocol_version);
1577 std::ostringstream tmp_os2(std::ios::binary);
1578 compressZlib(tmp_os.str(), tmp_os2);
1579 pkt.putLongString(tmp_os2.str());
1582 verbosestream << "Server: Sending item definitions to id(" << peer_id
1583 << "): size=" << pkt.getSize() << std::endl;
1588 void Server::SendNodeDef(u16 peer_id,
1589 INodeDefManager *nodedef, u16 protocol_version)
1591 DSTACK(FUNCTION_NAME);
1593 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1597 u32 length of the next item
1598 zlib-compressed serialized NodeDefManager
1600 std::ostringstream tmp_os(std::ios::binary);
1601 nodedef->serialize(tmp_os, protocol_version);
1602 std::ostringstream tmp_os2(std::ios::binary);
1603 compressZlib(tmp_os.str(), tmp_os2);
1605 pkt.putLongString(tmp_os2.str());
1608 verbosestream << "Server: Sending node definitions to id(" << peer_id
1609 << "): size=" << pkt.getSize() << std::endl;
1615 Non-static send methods
1618 void Server::SendInventory(PlayerSAO* playerSAO)
1620 DSTACK(FUNCTION_NAME);
1622 UpdateCrafting(playerSAO->getPlayer());
1628 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1630 std::ostringstream os;
1631 playerSAO->getInventory()->serialize(os);
1633 std::string s = os.str();
1635 pkt.putRawString(s.c_str(), s.size());
1639 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1641 DSTACK(FUNCTION_NAME);
1643 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1646 if (peer_id != PEER_ID_INEXISTENT) {
1650 m_clients.sendToAll(0, &pkt, true);
1654 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1655 const std::string &formname)
1657 DSTACK(FUNCTION_NAME);
1659 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1661 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1667 // Spawns a particle on peer with peer_id
1668 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1669 float expirationtime, float size, bool collisiondetection,
1670 bool vertical, std::string texture)
1672 DSTACK(FUNCTION_NAME);
1674 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1676 pkt << pos << velocity << acceleration << expirationtime
1677 << size << collisiondetection;
1678 pkt.putLongString(texture);
1681 if (peer_id != PEER_ID_INEXISTENT) {
1685 m_clients.sendToAll(0, &pkt, true);
1689 // Adds a ParticleSpawner on peer with peer_id
1690 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1691 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1692 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1694 DSTACK(FUNCTION_NAME);
1696 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1698 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1699 << minacc << maxacc << minexptime << maxexptime << minsize
1700 << maxsize << collisiondetection;
1702 pkt.putLongString(texture);
1704 pkt << id << vertical;
1706 if (peer_id != PEER_ID_INEXISTENT) {
1710 m_clients.sendToAll(0, &pkt, true);
1714 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1716 DSTACK(FUNCTION_NAME);
1718 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1720 // Ugly error in this packet
1723 if (peer_id != PEER_ID_INEXISTENT) {
1727 m_clients.sendToAll(0, &pkt, true);
1732 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1734 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1736 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1737 << form->text << form->number << form->item << form->dir
1738 << form->align << form->offset << form->world_pos << form->size;
1743 void Server::SendHUDRemove(u16 peer_id, u32 id)
1745 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1750 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1752 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1753 pkt << id << (u8) stat;
1757 case HUD_STAT_SCALE:
1758 case HUD_STAT_ALIGN:
1759 case HUD_STAT_OFFSET:
1760 pkt << *(v2f *) value;
1764 pkt << *(std::string *) value;
1766 case HUD_STAT_WORLD_POS:
1767 pkt << *(v3f *) value;
1770 pkt << *(v2s32 *) value;
1772 case HUD_STAT_NUMBER:
1776 pkt << *(u32 *) value;
1783 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1785 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1787 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1789 pkt << flags << mask;
1794 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1796 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1797 pkt << param << value;
1801 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1802 const std::string &type, const std::vector<std::string> ¶ms)
1804 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1805 pkt << bgcolor << type << (u16) params.size();
1807 for(size_t i=0; i<params.size(); i++)
1813 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1816 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1819 pkt << do_override << (u16) (ratio * 65535);
1824 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1826 DSTACK(FUNCTION_NAME);
1828 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1829 pkt << time << time_speed;
1831 if (peer_id == PEER_ID_INEXISTENT) {
1832 m_clients.sendToAll(0, &pkt, true);
1839 void Server::SendPlayerHP(u16 peer_id)
1841 DSTACK(FUNCTION_NAME);
1842 PlayerSAO *playersao = getPlayerSAO(peer_id);
1843 // In some rare case, if the player is disconnected
1844 // while Lua call l_punch, for example, this can be NULL
1848 SendHP(peer_id, playersao->getHP());
1849 m_script->player_event(playersao,"health_changed");
1851 // Send to other clients
1852 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1853 ActiveObjectMessage aom(playersao->getId(), true, str);
1854 playersao->m_messages_out.push(aom);
1857 void Server::SendPlayerBreath(u16 peer_id)
1859 DSTACK(FUNCTION_NAME);
1860 PlayerSAO *playersao = getPlayerSAO(peer_id);
1863 m_script->player_event(playersao, "breath_changed");
1864 SendBreath(peer_id, playersao->getBreath());
1867 void Server::SendMovePlayer(u16 peer_id)
1869 DSTACK(FUNCTION_NAME);
1870 Player *player = m_env->getPlayer(peer_id);
1873 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1874 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1877 v3f pos = player->getPosition();
1878 f32 pitch = player->getPitch();
1879 f32 yaw = player->getYaw();
1880 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1881 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1882 << " pitch=" << pitch
1890 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1892 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1895 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1896 << animation_frames[3] << animation_speed;
1901 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1903 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1904 pkt << first << third;
1907 void Server::SendPlayerPrivileges(u16 peer_id)
1909 Player *player = m_env->getPlayer(peer_id);
1911 if(player->peer_id == PEER_ID_INEXISTENT)
1914 std::set<std::string> privs;
1915 m_script->getAuth(player->getName(), NULL, &privs);
1917 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1918 pkt << (u16) privs.size();
1920 for(std::set<std::string>::const_iterator i = privs.begin();
1921 i != privs.end(); ++i) {
1928 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1930 Player *player = m_env->getPlayer(peer_id);
1932 if(player->peer_id == PEER_ID_INEXISTENT)
1935 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1936 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1940 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1942 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 return pkt.getSize();
1948 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1950 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1951 datas.size(), peer_id);
1953 pkt.putRawString(datas.c_str(), datas.size());
1955 m_clients.send(pkt.getPeerId(),
1956 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1961 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<u16> dst_clients;
1973 if(params.to_player != "")
1975 Player *player = m_env->getPlayer(params.to_player.c_str());
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not found"<<std::endl;
1981 if(player->peer_id == PEER_ID_INEXISTENT){
1982 infostream<<"Server::playSound: Player \""<<params.to_player
1983 <<"\" not connected"<<std::endl;
1986 dst_clients.push_back(player->peer_id);
1989 std::vector<u16> clients = m_clients.getClientIDs();
1991 for(std::vector<u16>::iterator
1992 i = clients.begin(); i != clients.end(); ++i) {
1993 Player *player = m_env->getPlayer(*i);
1998 if(player->getPosition().getDistanceFrom(pos) >
1999 params.max_hear_distance)
2002 dst_clients.push_back(*i);
2006 if(dst_clients.empty())
2010 s32 id = m_next_sound_id++;
2011 // The sound will exist as a reference in m_playing_sounds
2012 m_playing_sounds[id] = ServerPlayingSound();
2013 ServerPlayingSound &psound = m_playing_sounds[id];
2014 psound.params = params;
2016 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2017 pkt << id << spec.name << (float) (spec.gain * params.gain)
2018 << (u8) params.type << pos << params.object << params.loop;
2020 for(std::vector<u16>::iterator i = dst_clients.begin();
2021 i != dst_clients.end(); ++i) {
2022 psound.clients.insert(*i);
2023 m_clients.send(*i, 0, &pkt, true);
2027 void Server::stopSound(s32 handle)
2029 // Get sound reference
2030 std::map<s32, ServerPlayingSound>::iterator i =
2031 m_playing_sounds.find(handle);
2032 if(i == m_playing_sounds.end())
2034 ServerPlayingSound &psound = i->second;
2036 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2039 for(std::set<u16>::iterator i = psound.clients.begin();
2040 i != psound.clients.end(); ++i) {
2042 m_clients.send(*i, 0, &pkt, true);
2044 // Remove sound reference
2045 m_playing_sounds.erase(i);
2048 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2049 std::vector<u16> *far_players, float far_d_nodes)
2051 float maxd = far_d_nodes*BS;
2052 v3f p_f = intToFloat(p, BS);
2054 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2057 std::vector<u16> clients = m_clients.getClientIDs();
2058 for(std::vector<u16>::iterator i = clients.begin();
2059 i != clients.end(); ++i) {
2062 if(Player *player = m_env->getPlayer(*i)) {
2063 // If player is far away, only set modified blocks not sent
2064 v3f player_pos = player->getPosition();
2065 if(player_pos.getDistanceFrom(p_f) > maxd) {
2066 far_players->push_back(*i);
2073 m_clients.send(*i, 0, &pkt, true);
2077 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2078 std::vector<u16> *far_players, float far_d_nodes,
2079 bool remove_metadata)
2081 float maxd = far_d_nodes*BS;
2082 v3f p_f = intToFloat(p, BS);
2084 std::vector<u16> clients = m_clients.getClientIDs();
2085 for(std::vector<u16>::iterator i = clients.begin();
2086 i != clients.end(); ++i) {
2090 if(Player *player = m_env->getPlayer(*i)) {
2091 // If player is far away, only set modified blocks not sent
2092 v3f player_pos = player->getPosition();
2093 if(player_pos.getDistanceFrom(p_f) > maxd) {
2094 far_players->push_back(*i);
2100 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2102 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2104 pkt << p << n.param0 << n.param1 << n.param2
2105 << (u8) (remove_metadata ? 0 : 1);
2107 if (!remove_metadata) {
2108 if (client->net_proto_version <= 21) {
2109 // Old clients always clear metadata; fix it
2110 // by sending the full block again.
2111 client->SetBlockNotSent(getNodeBlockPos(p));
2118 if (pkt.getSize() > 0)
2119 m_clients.send(*i, 0, &pkt, true);
2123 void Server::setBlockNotSent(v3s16 p)
2125 std::vector<u16> clients = m_clients.getClientIDs();
2127 for(std::vector<u16>::iterator i = clients.begin();
2128 i != clients.end(); ++i) {
2129 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2130 client->SetBlockNotSent(p);
2135 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2137 DSTACK(FUNCTION_NAME);
2139 v3s16 p = block->getPos();
2142 Create a packet with the block in the right format
2145 std::ostringstream os(std::ios_base::binary);
2146 block->serialize(os, ver, false);
2147 block->serializeNetworkSpecific(os, net_proto_version);
2148 std::string s = os.str();
2150 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2153 pkt.putRawString(s.c_str(), s.size());
2157 void Server::SendBlocks(float dtime)
2159 DSTACK(FUNCTION_NAME);
2161 MutexAutoLock envlock(m_env_mutex);
2162 //TODO check if one big lock could be faster then multiple small ones
2164 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2166 std::vector<PrioritySortedBlockTransfer> queue;
2168 s32 total_sending = 0;
2171 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2173 std::vector<u16> clients = m_clients.getClientIDs();
2176 for(std::vector<u16>::iterator i = clients.begin();
2177 i != clients.end(); ++i) {
2178 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2183 total_sending += client->SendingCount();
2184 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2190 // Lowest priority number comes first.
2191 // Lowest is most important.
2192 std::sort(queue.begin(), queue.end());
2195 for(u32 i=0; i<queue.size(); i++)
2197 //TODO: Calculate limit dynamically
2198 if(total_sending >= g_settings->getS32
2199 ("max_simultaneous_block_sends_server_total"))
2202 PrioritySortedBlockTransfer q = queue[i];
2204 MapBlock *block = NULL;
2207 block = m_env->getMap().getBlockNoCreate(q.pos);
2209 catch(InvalidPositionException &e)
2214 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2219 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2221 client->SentBlock(q.pos);
2227 void Server::fillMediaCache()
2229 DSTACK(FUNCTION_NAME);
2231 infostream<<"Server: Calculating media file checksums"<<std::endl;
2233 // Collect all media file paths
2234 std::vector<std::string> paths;
2235 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2236 i != m_mods.end(); ++i) {
2237 const ModSpec &mod = *i;
2238 paths.push_back(mod.path + DIR_DELIM + "textures");
2239 paths.push_back(mod.path + DIR_DELIM + "sounds");
2240 paths.push_back(mod.path + DIR_DELIM + "media");
2241 paths.push_back(mod.path + DIR_DELIM + "models");
2243 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2245 // Collect media file information from paths into cache
2246 for(std::vector<std::string>::iterator i = paths.begin();
2247 i != paths.end(); ++i) {
2248 std::string mediapath = *i;
2249 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2250 for (u32 j = 0; j < dirlist.size(); j++) {
2251 if (dirlist[j].dir) // Ignode dirs
2253 std::string filename = dirlist[j].name;
2254 // If name contains illegal characters, ignore the file
2255 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2256 infostream<<"Server: ignoring illegal file name: \""
2257 << filename << "\"" << std::endl;
2260 // If name is not in a supported format, ignore it
2261 const char *supported_ext[] = {
2262 ".png", ".jpg", ".bmp", ".tga",
2263 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2265 ".x", ".b3d", ".md2", ".obj",
2268 if (removeStringEnd(filename, supported_ext) == ""){
2269 infostream << "Server: ignoring unsupported file extension: \""
2270 << filename << "\"" << std::endl;
2273 // Ok, attempt to load the file and add to cache
2274 std::string filepath = mediapath + DIR_DELIM + filename;
2276 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2278 errorstream << "Server::fillMediaCache(): Could not open \""
2279 << filename << "\" for reading" << std::endl;
2282 std::ostringstream tmp_os(std::ios_base::binary);
2286 fis.read(buf, 1024);
2287 std::streamsize len = fis.gcount();
2288 tmp_os.write(buf, len);
2297 errorstream<<"Server::fillMediaCache(): Failed to read \""
2298 << filename << "\"" << std::endl;
2301 if(tmp_os.str().length() == 0) {
2302 errorstream << "Server::fillMediaCache(): Empty file \""
2303 << filepath << "\"" << std::endl;
2308 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2310 unsigned char *digest = sha1.getDigest();
2311 std::string sha1_base64 = base64_encode(digest, 20);
2312 std::string sha1_hex = hex_encode((char*)digest, 20);
2316 m_media[filename] = MediaInfo(filepath, sha1_base64);
2317 verbosestream << "Server: " << sha1_hex << " is " << filename
2323 void Server::sendMediaAnnouncement(u16 peer_id)
2325 DSTACK(FUNCTION_NAME);
2327 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2331 std::ostringstream os(std::ios_base::binary);
2333 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2334 pkt << (u16) m_media.size();
2336 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2337 i != m_media.end(); ++i) {
2338 pkt << i->first << i->second.sha1_digest;
2341 pkt << g_settings->get("remote_media");
2345 struct SendableMedia
2351 SendableMedia(const std::string &name_="", const std::string &path_="",
2352 const std::string &data_=""):
2359 void Server::sendRequestedMedia(u16 peer_id,
2360 const std::vector<std::string> &tosend)
2362 DSTACK(FUNCTION_NAME);
2364 verbosestream<<"Server::sendRequestedMedia(): "
2365 <<"Sending files to client"<<std::endl;
2369 // Put 5kB in one bunch (this is not accurate)
2370 u32 bytes_per_bunch = 5000;
2372 std::vector< std::vector<SendableMedia> > file_bunches;
2373 file_bunches.push_back(std::vector<SendableMedia>());
2375 u32 file_size_bunch_total = 0;
2377 for(std::vector<std::string>::const_iterator i = tosend.begin();
2378 i != tosend.end(); ++i) {
2379 const std::string &name = *i;
2381 if(m_media.find(name) == m_media.end()) {
2382 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2383 <<"unknown file \""<<(name)<<"\""<<std::endl;
2387 //TODO get path + name
2388 std::string tpath = m_media[name].path;
2391 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2392 if(fis.good() == false){
2393 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2394 <<tpath<<"\" for reading"<<std::endl;
2397 std::ostringstream tmp_os(std::ios_base::binary);
2401 fis.read(buf, 1024);
2402 std::streamsize len = fis.gcount();
2403 tmp_os.write(buf, len);
2404 file_size_bunch_total += len;
2413 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2414 <<name<<"\""<<std::endl;
2417 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2418 <<tname<<"\""<<std::endl;*/
2420 file_bunches[file_bunches.size()-1].push_back(
2421 SendableMedia(name, tpath, tmp_os.str()));
2423 // Start next bunch if got enough data
2424 if(file_size_bunch_total >= bytes_per_bunch) {
2425 file_bunches.push_back(std::vector<SendableMedia>());
2426 file_size_bunch_total = 0;
2431 /* Create and send packets */
2433 u16 num_bunches = file_bunches.size();
2434 for(u16 i = 0; i < num_bunches; i++) {
2437 u16 total number of texture bunches
2438 u16 index of this bunch
2439 u32 number of files in this bunch
2448 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2449 pkt << num_bunches << i << (u32) file_bunches[i].size();
2451 for(std::vector<SendableMedia>::iterator
2452 j = file_bunches[i].begin();
2453 j != file_bunches[i].end(); ++j) {
2455 pkt.putLongString(j->data);
2458 verbosestream << "Server::sendRequestedMedia(): bunch "
2459 << i << "/" << num_bunches
2460 << " files=" << file_bunches[i].size()
2461 << " size=" << pkt.getSize() << std::endl;
2466 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2468 if(m_detached_inventories.count(name) == 0) {
2469 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2472 Inventory *inv = m_detached_inventories[name];
2473 std::ostringstream os(std::ios_base::binary);
2475 os << serializeString(name);
2479 std::string s = os.str();
2481 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2482 pkt.putRawString(s.c_str(), s.size());
2484 if (peer_id != PEER_ID_INEXISTENT) {
2488 m_clients.sendToAll(0, &pkt, true);
2492 void Server::sendDetachedInventories(u16 peer_id)
2494 DSTACK(FUNCTION_NAME);
2496 for(std::map<std::string, Inventory*>::iterator
2497 i = m_detached_inventories.begin();
2498 i != m_detached_inventories.end(); ++i) {
2499 const std::string &name = i->first;
2500 //Inventory *inv = i->second;
2501 sendDetachedInventory(name, peer_id);
2509 void Server::DiePlayer(u16 peer_id)
2511 DSTACK(FUNCTION_NAME);
2513 PlayerSAO *playersao = getPlayerSAO(peer_id);
2516 infostream << "Server::DiePlayer(): Player "
2517 << playersao->getPlayer()->getName()
2518 << " dies" << std::endl;
2520 playersao->setHP(0);
2522 // Trigger scripted stuff
2523 m_script->on_dieplayer(playersao);
2525 SendPlayerHP(peer_id);
2526 SendDeathscreen(peer_id, false, v3f(0,0,0));
2529 void Server::RespawnPlayer(u16 peer_id)
2531 DSTACK(FUNCTION_NAME);
2533 PlayerSAO *playersao = getPlayerSAO(peer_id);
2536 infostream << "Server::RespawnPlayer(): Player "
2537 << playersao->getPlayer()->getName()
2538 << " respawns" << std::endl;
2540 playersao->setHP(PLAYER_MAX_HP);
2541 playersao->setBreath(PLAYER_MAX_BREATH);
2543 SendPlayerHP(peer_id);
2544 SendPlayerBreath(peer_id);
2546 bool repositioned = m_script->on_respawnplayer(playersao);
2548 v3f pos = findSpawnPos();
2549 // setPos will send the new position to client
2550 playersao->setPos(pos);
2555 void Server::DenySudoAccess(u16 peer_id)
2557 DSTACK(FUNCTION_NAME);
2559 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2564 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2565 const std::string &str_reason, bool reconnect)
2567 if (proto_ver >= 25) {
2568 SendAccessDenied(peer_id, reason, str_reason);
2570 std::wstring wreason = utf8_to_wide(
2571 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2572 accessDeniedStrings[(u8)reason]);
2573 SendAccessDenied_Legacy(peer_id, wreason);
2576 m_clients.event(peer_id, CSE_SetDenied);
2577 m_con.DisconnectPeer(peer_id);
2581 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2583 DSTACK(FUNCTION_NAME);
2585 SendAccessDenied(peer_id, reason, custom_reason);
2586 m_clients.event(peer_id, CSE_SetDenied);
2587 m_con.DisconnectPeer(peer_id);
2590 // 13/03/15: remove this function when protocol version 25 will become
2591 // the minimum version for MT users, maybe in 1 year
2592 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2594 DSTACK(FUNCTION_NAME);
2596 SendAccessDenied_Legacy(peer_id, reason);
2597 m_clients.event(peer_id, CSE_SetDenied);
2598 m_con.DisconnectPeer(peer_id);
2601 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2603 DSTACK(FUNCTION_NAME);
2606 RemoteClient* client = getClient(peer_id, CS_Invalid);
2608 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2610 // Right now, the auth mechs don't change between login and sudo mode.
2611 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2612 client->allowed_sudo_mechs = sudo_auth_mechs;
2614 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2615 << g_settings->getFloat("dedicated_server_step")
2619 m_clients.event(peer_id, CSE_AuthAccept);
2621 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2623 // We only support SRP right now
2624 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2626 resp_pkt << sudo_auth_mechs;
2628 m_clients.event(peer_id, CSE_SudoSuccess);
2632 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2634 DSTACK(FUNCTION_NAME);
2635 std::wstring message;
2638 Clear references to playing sounds
2640 for(std::map<s32, ServerPlayingSound>::iterator
2641 i = m_playing_sounds.begin();
2642 i != m_playing_sounds.end();)
2644 ServerPlayingSound &psound = i->second;
2645 psound.clients.erase(peer_id);
2646 if(psound.clients.empty())
2647 m_playing_sounds.erase(i++);
2652 Player *player = m_env->getPlayer(peer_id);
2654 // Collect information about leaving in chat
2656 if(player != NULL && reason != CDR_DENY)
2658 std::wstring name = narrow_to_wide(player->getName());
2661 message += L" left the game.";
2662 if(reason == CDR_TIMEOUT)
2663 message += L" (timed out)";
2667 /* Run scripts and remove from environment */
2671 PlayerSAO *playersao = player->getPlayerSAO();
2674 m_script->on_leaveplayer(playersao);
2676 playersao->disconnected();
2684 if(player != NULL && reason != CDR_DENY) {
2685 std::ostringstream os(std::ios_base::binary);
2686 std::vector<u16> clients = m_clients.getClientIDs();
2688 for(std::vector<u16>::iterator i = clients.begin();
2689 i != clients.end(); ++i) {
2691 Player *player = m_env->getPlayer(*i);
2695 // Get name of player
2696 os << player->getName() << " ";
2699 std::string name = player->getName();
2700 actionstream << name << " "
2701 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2702 << " List of players: " << os.str() << std::endl;
2704 m_admin_chat->outgoing_queue.push_back(
2705 new ChatEventNick(CET_NICK_REMOVE, name));
2709 MutexAutoLock env_lock(m_env_mutex);
2710 m_clients.DeleteClient(peer_id);
2714 // Send leave chat message to all remaining clients
2715 if(message.length() != 0)
2716 SendChatMessage(PEER_ID_INEXISTENT,message);
2719 void Server::UpdateCrafting(Player* player)
2721 DSTACK(FUNCTION_NAME);
2723 // Get a preview for crafting
2725 InventoryLocation loc;
2726 loc.setPlayer(player->getName());
2727 std::vector<ItemStack> output_replacements;
2728 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2729 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2731 // Put the new preview in
2732 InventoryList *plist = player->inventory.getList("craftpreview");
2733 sanity_check(plist);
2734 sanity_check(plist->getSize() >= 1);
2735 plist->changeItem(0, preview);
2738 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2740 if (evt->type == CET_NICK_ADD) {
2741 // The terminal informed us of its nick choice
2742 m_admin_nick = ((ChatEventNick *)evt)->nick;
2743 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2744 errorstream << "You haven't set up an account." << std::endl
2745 << "Please log in using the client as '"
2746 << m_admin_nick << "' with a secure password." << std::endl
2747 << "Until then, you can't execute admin tasks via the console," << std::endl
2748 << "and everybody can claim the user account instead of you," << std::endl
2749 << "giving them full control over this server." << std::endl;
2752 assert(evt->type == CET_CHAT);
2753 handleAdminChat((ChatEventChat *)evt);
2757 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2758 const std::wstring &wmessage, bool check_shout_priv,
2759 u16 peer_id_to_avoid_sending)
2761 // If something goes wrong, this player is to blame
2762 RollbackScopeActor rollback_scope(m_rollback,
2763 std::string("player:") + name);
2767 // Whether to send line to the player that sent the message, or to all players
2768 bool broadcast_line = true;
2771 bool ate = m_script->on_chat_message(name,
2772 wide_to_utf8(wmessage));
2773 // If script ate the message, don't proceed
2777 // Commands are implemented in Lua, so only catch invalid
2778 // commands that were not "eaten" and send an error back
2779 if (wmessage[0] == L'/') {
2780 std::wstring wcmd = wmessage.substr(1);
2781 broadcast_line = false;
2782 if (wcmd.length() == 0)
2783 line += L"-!- Empty command";
2785 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2787 if (check_shout_priv && !checkPriv(name, "shout")) {
2788 line += L"-!- You don't have permission to shout.";
2789 broadcast_line = false;
2799 Tell calling method to send the message to sender
2801 if (!broadcast_line) {
2805 Send the message to others
2807 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2809 std::vector<u16> clients = m_clients.getClientIDs();
2811 for (u16 i = 0; i < clients.size(); i++) {
2812 u16 cid = clients[i];
2813 if (cid != peer_id_to_avoid_sending)
2814 SendChatMessage(cid, line);
2820 void Server::handleAdminChat(const ChatEventChat *evt)
2822 std::string name = evt->nick;
2823 std::wstring wname = utf8_to_wide(name);
2824 std::wstring wmessage = evt->evt_msg;
2826 std::wstring answer = handleChat(name, wname, wmessage);
2828 // If asked to send answer to sender
2829 if (!answer.empty()) {
2830 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2834 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2836 RemoteClient *client = getClientNoEx(peer_id,state_min);
2838 throw ClientNotFoundException("Client not found");
2842 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2844 return m_clients.getClientNoEx(peer_id, state_min);
2847 std::string Server::getPlayerName(u16 peer_id)
2849 Player *player = m_env->getPlayer(peer_id);
2851 return "[id="+itos(peer_id)+"]";
2852 return player->getName();
2855 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2857 Player *player = m_env->getPlayer(peer_id);
2860 return player->getPlayerSAO();
2863 std::wstring Server::getStatusString()
2865 std::wostringstream os(std::ios_base::binary);
2868 os<<L"version="<<narrow_to_wide(g_version_string);
2870 os<<L", uptime="<<m_uptime.get();
2872 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2873 // Information about clients
2876 std::vector<u16> clients = m_clients.getClientIDs();
2877 for(std::vector<u16>::iterator i = clients.begin();
2878 i != clients.end(); ++i) {
2880 Player *player = m_env->getPlayer(*i);
2881 // Get name of player
2882 std::wstring name = L"unknown";
2884 name = narrow_to_wide(player->getName());
2885 // Add name to information string
2893 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2894 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2895 if(g_settings->get("motd") != "")
2896 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2900 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2902 std::set<std::string> privs;
2903 m_script->getAuth(name, NULL, &privs);
2907 bool Server::checkPriv(const std::string &name, const std::string &priv)
2909 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2910 return (privs.count(priv) != 0);
2913 void Server::reportPrivsModified(const std::string &name)
2916 std::vector<u16> clients = m_clients.getClientIDs();
2917 for(std::vector<u16>::iterator i = clients.begin();
2918 i != clients.end(); ++i) {
2919 Player *player = m_env->getPlayer(*i);
2920 reportPrivsModified(player->getName());
2923 Player *player = m_env->getPlayer(name.c_str());
2926 SendPlayerPrivileges(player->peer_id);
2927 PlayerSAO *sao = player->getPlayerSAO();
2930 sao->updatePrivileges(
2931 getPlayerEffectivePrivs(name),
2936 void Server::reportInventoryFormspecModified(const std::string &name)
2938 Player *player = m_env->getPlayer(name.c_str());
2941 SendPlayerInventoryFormspec(player->peer_id);
2944 void Server::setIpBanned(const std::string &ip, const std::string &name)
2946 m_banmanager->add(ip, name);
2949 void Server::unsetIpBanned(const std::string &ip_or_name)
2951 m_banmanager->remove(ip_or_name);
2954 std::string Server::getBanDescription(const std::string &ip_or_name)
2956 return m_banmanager->getBanDescription(ip_or_name);
2959 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2961 // m_env will be NULL if the server is initializing
2965 if (m_admin_nick == name && !m_admin_nick.empty()) {
2966 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2969 Player *player = m_env->getPlayer(name);
2974 if (player->peer_id == PEER_ID_INEXISTENT)
2977 SendChatMessage(player->peer_id, msg);
2980 bool Server::showFormspec(const char *playername, const std::string &formspec,
2981 const std::string &formname)
2983 // m_env will be NULL if the server is initializing
2987 Player *player = m_env->getPlayer(playername);
2991 SendShowFormspecMessage(player->peer_id, formspec, formname);
2995 u32 Server::hudAdd(Player *player, HudElement *form)
3000 u32 id = player->addHud(form);
3002 SendHUDAdd(player->peer_id, id, form);
3007 bool Server::hudRemove(Player *player, u32 id) {
3011 HudElement* todel = player->removeHud(id);
3018 SendHUDRemove(player->peer_id, id);
3022 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3027 SendHUDChange(player->peer_id, id, stat, data);
3031 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3036 SendHUDSetFlags(player->peer_id, flags, mask);
3037 player->hud_flags = flags;
3039 PlayerSAO* playersao = player->getPlayerSAO();
3041 if (playersao == NULL)
3044 m_script->player_event(playersao, "hud_changed");
3048 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3052 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3055 player->setHotbarItemcount(hotbar_itemcount);
3056 std::ostringstream os(std::ios::binary);
3057 writeS32(os, hotbar_itemcount);
3058 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3062 s32 Server::hudGetHotbarItemcount(Player *player)
3066 return player->getHotbarItemcount();
3069 void Server::hudSetHotbarImage(Player *player, std::string name)
3074 player->setHotbarImage(name);
3075 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3078 std::string Server::hudGetHotbarImage(Player *player)
3082 return player->getHotbarImage();
3085 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3090 player->setHotbarSelectedImage(name);
3091 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3094 std::string Server::hudGetHotbarSelectedImage(Player *player)
3099 return player->getHotbarSelectedImage();
3102 bool Server::setLocalPlayerAnimations(Player *player,
3103 v2s32 animation_frames[4], f32 frame_speed)
3108 player->setLocalAnimations(animation_frames, frame_speed);
3109 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3113 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3118 player->eye_offset_first = first;
3119 player->eye_offset_third = third;
3120 SendEyeOffset(player->peer_id, first, third);
3124 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3125 const std::string &type, const std::vector<std::string> ¶ms)
3130 player->setSky(bgcolor, type, params);
3131 SendSetSky(player->peer_id, bgcolor, type, params);
3135 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3141 player->overrideDayNightRatio(do_override, ratio);
3142 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3146 void Server::notifyPlayers(const std::wstring &msg)
3148 SendChatMessage(PEER_ID_INEXISTENT,msg);
3151 void Server::spawnParticle(const std::string &playername, v3f pos,
3152 v3f velocity, v3f acceleration,
3153 float expirationtime, float size, bool
3154 collisiondetection, bool vertical, const std::string &texture)
3156 // m_env will be NULL if the server is initializing
3160 u16 peer_id = PEER_ID_INEXISTENT;
3161 if (playername != "") {
3162 Player* player = m_env->getPlayer(playername.c_str());
3165 peer_id = player->peer_id;
3168 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3169 expirationtime, size, collisiondetection, vertical, texture);
3172 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3173 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3174 float minexptime, float maxexptime, float minsize, float maxsize,
3175 bool collisiondetection, bool vertical, const std::string &texture,
3176 const std::string &playername)
3178 // m_env will be NULL if the server is initializing
3182 u16 peer_id = PEER_ID_INEXISTENT;
3183 if (playername != "") {
3184 Player* player = m_env->getPlayer(playername.c_str());
3187 peer_id = player->peer_id;
3191 for(;;) // look for unused particlespawner id
3194 if (std::find(m_particlespawner_ids.begin(),
3195 m_particlespawner_ids.end(), id)
3196 == m_particlespawner_ids.end())
3198 m_particlespawner_ids.push_back(id);
3203 SendAddParticleSpawner(peer_id, amount, spawntime,
3204 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3205 minexptime, maxexptime, minsize, maxsize,
3206 collisiondetection, vertical, texture, id);
3211 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3213 // m_env will be NULL if the server is initializing
3215 throw ServerError("Can't delete particle spawners during initialisation!");
3217 u16 peer_id = PEER_ID_INEXISTENT;
3218 if (playername != "") {
3219 Player* player = m_env->getPlayer(playername.c_str());
3222 peer_id = player->peer_id;
3225 m_particlespawner_ids.erase(
3226 std::remove(m_particlespawner_ids.begin(),
3227 m_particlespawner_ids.end(), id),
3228 m_particlespawner_ids.end());
3229 SendDeleteParticleSpawner(peer_id, id);
3232 Inventory* Server::createDetachedInventory(const std::string &name)
3234 if(m_detached_inventories.count(name) > 0){
3235 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3236 delete m_detached_inventories[name];
3238 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3240 Inventory *inv = new Inventory(m_itemdef);
3242 m_detached_inventories[name] = inv;
3243 //TODO find a better way to do this
3244 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3248 // actions: time-reversed list
3249 // Return value: success/failure
3250 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3251 std::list<std::string> *log)
3253 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3254 ServerMap *map = (ServerMap*)(&m_env->getMap());
3256 // Fail if no actions to handle
3257 if(actions.empty()){
3258 log->push_back("Nothing to do.");
3265 for(std::list<RollbackAction>::const_iterator
3266 i = actions.begin();
3267 i != actions.end(); ++i)
3269 const RollbackAction &action = *i;
3271 bool success = action.applyRevert(map, this, this);
3274 std::ostringstream os;
3275 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3276 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3278 log->push_back(os.str());
3280 std::ostringstream os;
3281 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3282 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3284 log->push_back(os.str());
3288 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3289 <<" failed"<<std::endl;
3291 // Call it done if less than half failed
3292 return num_failed <= num_tried/2;
3295 // IGameDef interface
3297 IItemDefManager *Server::getItemDefManager()
3302 INodeDefManager *Server::getNodeDefManager()
3307 ICraftDefManager *Server::getCraftDefManager()
3311 ITextureSource *Server::getTextureSource()
3315 IShaderSource *Server::getShaderSource()
3319 scene::ISceneManager *Server::getSceneManager()
3324 u16 Server::allocateUnknownNodeId(const std::string &name)
3326 return m_nodedef->allocateDummy(name);
3329 ISoundManager *Server::getSoundManager()
3331 return &dummySoundManager;
3334 MtEventManager *Server::getEventManager()
3339 IWritableItemDefManager *Server::getWritableItemDefManager()
3344 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3349 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3354 const ModSpec *Server::getModSpec(const std::string &modname) const
3356 std::vector<ModSpec>::const_iterator it;
3357 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3358 const ModSpec &mod = *it;
3359 if (mod.name == modname)
3365 void Server::getModNames(std::vector<std::string> &modlist)
3367 std::vector<ModSpec>::iterator it;
3368 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3369 modlist.push_back(it->name);
3372 std::string Server::getBuiltinLuaPath()
3374 return porting::path_share + DIR_DELIM + "builtin";
3377 v3f Server::findSpawnPos()
3379 ServerMap &map = m_env->getServerMap();
3381 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3382 return nodeposf * BS;
3385 s16 water_level = map.getWaterLevel();
3386 s16 vertical_spawn_range = g_settings->getS16("vertical_spawn_range");
3387 bool is_good = false;
3389 // Try to find a good place a few times
3390 for(s32 i = 0; i < 1000 && !is_good; i++) {
3392 // We're going to try to throw the player to this position
3393 v2s16 nodepos2d = v2s16(
3394 -range + (myrand() % (range * 2)),
3395 -range + (myrand() % (range * 2)));
3397 // Get ground height at point
3398 s16 groundheight = map.findGroundLevel(nodepos2d);
3399 // Don't go underwater or to high places
3400 if (groundheight <= water_level ||
3401 groundheight > water_level + vertical_spawn_range)
3404 v3s16 nodepos(nodepos2d.X, groundheight, nodepos2d.Y);
3407 for (s32 i = 0; i < 10; i++) {
3408 v3s16 blockpos = getNodeBlockPos(nodepos);
3409 map.emergeBlock(blockpos, true);
3410 content_t c = map.getNodeNoEx(nodepos).getContent();
3411 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3413 if (air_count >= 2) {
3414 nodeposf = intToFloat(nodepos, BS);
3415 // Don't spawn the player outside map boundaries
3416 if (objectpos_over_limit(nodeposf))
3429 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3431 bool newplayer = false;
3434 Try to get an existing player
3436 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3438 // If player is already connected, cancel
3439 if(player != NULL && player->peer_id != 0)
3441 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3446 If player with the wanted peer_id already exists, cancel.
3448 if(m_env->getPlayer(peer_id) != NULL)
3450 infostream<<"emergePlayer(): Player with wrong name but same"
3451 " peer_id already exists"<<std::endl;
3455 // Load player if it isn't already loaded
3457 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3460 // Create player if it doesn't exist
3463 player = new RemotePlayer(this, name);
3464 // Set player position
3465 infostream<<"Server: Finding spawn place for player \""
3466 <<name<<"\""<<std::endl;
3467 v3f pos = findSpawnPos();
3468 player->setPosition(pos);
3470 // Make sure the player is saved
3471 player->setModified(true);
3473 // Add player to environment
3474 m_env->addPlayer(player);
3476 // If the player exists, ensure that they respawn inside legal bounds
3477 // This fixes an assert crash when the player can't be added
3478 // to the environment
3479 if (objectpos_over_limit(player->getPosition())) {
3480 actionstream << "Respawn position for player \""
3481 << name << "\" outside limits, resetting" << std::endl;
3482 v3f pos = findSpawnPos();
3483 player->setPosition(pos);
3487 // Create a new player active object
3488 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3489 getPlayerEffectivePrivs(player->getName()),
3492 player->protocol_version = proto_version;
3494 /* Clean up old HUD elements from previous sessions */
3497 /* Add object to environment */
3498 m_env->addActiveObject(playersao);
3502 m_script->on_newplayer(playersao);
3508 void dedicated_server_loop(Server &server, bool &kill)
3510 DSTACK(FUNCTION_NAME);
3512 verbosestream<<"dedicated_server_loop()"<<std::endl;
3514 IntervalLimiter m_profiler_interval;
3518 float steplen = g_settings->getFloat("dedicated_server_step");
3519 // This is kind of a hack but can be done like this
3520 // because server.step() is very light
3522 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3523 sleep_ms((int)(steplen*1000.0));
3525 server.step(steplen);
3527 if(server.getShutdownRequested() || kill)
3529 infostream<<"Dedicated server quitting"<<std::endl;
3531 if(g_settings->getBool("server_announce"))
3532 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3540 float profiler_print_interval =
3541 g_settings->getFloat("profiler_print_interval");
3542 if(profiler_print_interval != 0)
3544 if(m_profiler_interval.step(steplen, profiler_print_interval))
3546 infostream<<"Profiler:"<<std::endl;
3547 g_profiler->print(infostream);
3548 g_profiler->clear();