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 // unmap node names for connected nodeboxes
324 m_nodedef->mapNodeboxConnections();
326 // init the recipe hashes to speed up crafting
327 m_craftdef->initHashes(this);
329 // Initialize Environment
330 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
332 m_clients.setEnv(m_env);
334 // Initialize mapgens
335 m_emerge->initMapgens();
337 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
338 if (m_enable_rollback_recording) {
339 // Create rollback manager
340 m_rollback = new RollbackManager(m_path_world, this);
343 // Give environment reference to scripting api
344 m_script->initializeEnvironment(m_env);
346 // Register us to receive map edit events
347 servermap->addEventReceiver(this);
349 // If file exists, load environment metadata
350 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
351 infostream << "Server: Loading environment metadata" << std::endl;
354 m_env->loadDefaultMeta();
357 // Add some test ActiveBlockModifiers to environment
358 add_legacy_abms(m_env, m_nodedef);
360 m_liquid_transform_every = g_settings->getFloat("liquid_update");
365 infostream<<"Server destructing"<<std::endl;
367 // Send shutdown message
368 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
371 MutexAutoLock envlock(m_env_mutex);
373 // Execute script shutdown hooks
374 m_script->on_shutdown();
376 infostream << "Server: Saving players" << std::endl;
377 m_env->saveLoadedPlayers();
379 infostream << "Server: Kicking players" << std::endl;
380 std::string kick_msg;
381 bool reconnect = false;
382 if (getShutdownRequested()) {
383 reconnect = m_shutdown_ask_reconnect;
384 kick_msg = m_shutdown_msg;
386 if (kick_msg == "") {
387 kick_msg = g_settings->get("kick_msg_shutdown");
389 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
390 kick_msg, reconnect);
392 infostream << "Server: Saving environment metadata" << std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
407 // N.B. the EmergeManager should be deleted after the Environment since Map
408 // depends on EmergeManager to write its current params to the map meta
417 // Deinitialize scripting
418 infostream<<"Server: Deinitializing scripting"<<std::endl;
421 // Delete detached inventories
422 for (std::map<std::string, Inventory*>::iterator
423 i = m_detached_inventories.begin();
424 i != m_detached_inventories.end(); ++i) {
429 void Server::start(Address bind_addr)
431 DSTACK(FUNCTION_NAME);
433 m_bind_addr = bind_addr;
435 infostream<<"Starting server on "
436 << bind_addr.serializeString() <<"..."<<std::endl;
438 // Stop thread if already running
441 // Initialize connection
442 m_con.SetTimeoutMs(30);
443 m_con.Serve(bind_addr);
448 // ASCII art for the win!
450 <<" .__ __ __ "<<std::endl
451 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
452 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
453 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
454 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
455 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
456 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
457 actionstream<<"Server for gameid=\""<<m_gamespec.id
458 <<"\" listening on "<<bind_addr.serializeString()<<":"
459 <<bind_addr.getPort() << "."<<std::endl;
464 DSTACK(FUNCTION_NAME);
466 infostream<<"Server: Stopping and waiting threads"<<std::endl;
468 // Stop threads (set run=false first so both start stopping)
470 //m_emergethread.setRun(false);
472 //m_emergethread.stop();
474 infostream<<"Server: Threads stopped"<<std::endl;
477 void Server::step(float dtime)
479 DSTACK(FUNCTION_NAME);
484 MutexAutoLock lock(m_step_dtime_mutex);
485 m_step_dtime += dtime;
487 // Throw if fatal error occurred in thread
488 std::string async_err = m_async_fatal_error.get();
489 if (!async_err.empty()) {
490 if (!m_simple_singleplayer_mode) {
491 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
492 g_settings->get("kick_msg_crash"),
493 g_settings->getBool("ask_reconnect_on_crash"));
495 throw ServerError(async_err);
499 void Server::AsyncRunStep(bool initial_step)
501 DSTACK(FUNCTION_NAME);
503 g_profiler->add("Server::AsyncRunStep (num)", 1);
507 MutexAutoLock lock1(m_step_dtime_mutex);
508 dtime = m_step_dtime;
512 // Send blocks to clients
516 if((dtime < 0.001) && (initial_step == false))
519 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
521 //infostream<<"Server steps "<<dtime<<std::endl;
522 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
525 MutexAutoLock lock1(m_step_dtime_mutex);
526 m_step_dtime -= dtime;
533 m_uptime.set(m_uptime.get() + dtime);
539 Update time of day and overall game time
541 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
544 Send to clients at constant intervals
547 m_time_of_day_send_timer -= dtime;
548 if(m_time_of_day_send_timer < 0.0) {
549 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
550 u16 time = m_env->getTimeOfDay();
551 float time_speed = g_settings->getFloat("time_speed");
552 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
556 MutexAutoLock lock(m_env_mutex);
557 // Figure out and report maximum lag to environment
558 float max_lag = m_env->getMaxLagEstimate();
559 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
561 if(dtime > 0.1 && dtime > max_lag * 2.0)
562 infostream<<"Server: Maximum lag peaked to "<<dtime
566 m_env->reportMaxLagEstimate(max_lag);
568 ScopeProfiler sp(g_profiler, "SEnv step");
569 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
573 static const float map_timer_and_unload_dtime = 2.92;
574 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
576 MutexAutoLock lock(m_env_mutex);
577 // Run Map's timers and unload unused data
578 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
579 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
580 g_settings->getFloat("server_unload_unused_data_timeout"),
585 Listen to the admin chat, if available
588 if (!m_admin_chat->command_queue.empty()) {
589 MutexAutoLock lock(m_env_mutex);
590 while (!m_admin_chat->command_queue.empty()) {
591 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
592 handleChatInterfaceEvent(evt);
596 m_admin_chat->outgoing_queue.push_back(
597 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
604 /* Transform liquids */
605 m_liquid_transform_timer += dtime;
606 if(m_liquid_transform_timer >= m_liquid_transform_every)
608 m_liquid_transform_timer -= m_liquid_transform_every;
610 MutexAutoLock lock(m_env_mutex);
612 ScopeProfiler sp(g_profiler, "Server: liquid transform");
614 std::map<v3s16, MapBlock*> modified_blocks;
615 m_env->getMap().transformLiquids(modified_blocks);
620 core::map<v3s16, MapBlock*> lighting_modified_blocks;
621 ServerMap &map = ((ServerMap&)m_env->getMap());
622 map.updateLighting(modified_blocks, lighting_modified_blocks);
624 // Add blocks modified by lighting to modified_blocks
625 for(core::map<v3s16, MapBlock*>::Iterator
626 i = lighting_modified_blocks.getIterator();
627 i.atEnd() == false; i++)
629 MapBlock *block = i.getNode()->getValue();
630 modified_blocks.insert(block->getPos(), block);
634 Set the modified blocks unsent for all the clients
636 if(!modified_blocks.empty())
638 SetBlocksNotSent(modified_blocks);
641 m_clients.step(dtime);
643 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
645 // send masterserver announce
647 float &counter = m_masterserver_timer;
648 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
649 g_settings->getBool("server_announce"))
651 ServerList::sendAnnounce(counter ? "update" : "start",
652 m_bind_addr.getPort(),
653 m_clients.getPlayerNames(),
655 m_env->getGameTime(),
658 m_emerge->params.mg_name,
667 Check added and deleted active objects
670 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
671 MutexAutoLock envlock(m_env_mutex);
674 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
675 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
677 // Radius inside which objects are active
678 static const s16 radius =
679 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
681 // Radius inside which players are active
682 static const bool is_transfer_limited =
683 g_settings->exists("unlimited_player_transfer_distance") &&
684 !g_settings->getBool("unlimited_player_transfer_distance");
685 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
686 s16 player_radius = player_transfer_dist;
687 if (player_radius == 0 && is_transfer_limited)
688 player_radius = radius;
690 for (std::map<u16, RemoteClient*>::iterator
692 i != clients.end(); ++i) {
693 RemoteClient *client = i->second;
695 // If definitions and textures have not been sent, don't
696 // send objects either
697 if (client->getState() < CS_DefinitionsSent)
700 Player *player = m_env->getPlayer(client->peer_id);
702 // This can happen if the client timeouts somehow
703 /*warningstream<<FUNCTION_NAME<<": Client "
705 <<" has no associated player"<<std::endl;*/
709 std::queue<u16> removed_objects;
710 std::queue<u16> added_objects;
711 m_env->getRemovedActiveObjects(player, radius, player_radius,
712 client->m_known_objects, removed_objects);
713 m_env->getAddedActiveObjects(player, radius, player_radius,
714 client->m_known_objects, added_objects);
716 // Ignore if nothing happened
717 if (removed_objects.empty() && added_objects.empty()) {
721 std::string data_buffer;
725 // Handle removed objects
726 writeU16((u8*)buf, removed_objects.size());
727 data_buffer.append(buf, 2);
728 while (!removed_objects.empty()) {
730 u16 id = removed_objects.front();
731 ServerActiveObject* obj = m_env->getActiveObject(id);
733 // Add to data buffer for sending
734 writeU16((u8*)buf, id);
735 data_buffer.append(buf, 2);
737 // Remove from known objects
738 client->m_known_objects.erase(id);
740 if(obj && obj->m_known_by_count > 0)
741 obj->m_known_by_count--;
742 removed_objects.pop();
745 // Handle added objects
746 writeU16((u8*)buf, added_objects.size());
747 data_buffer.append(buf, 2);
748 while (!added_objects.empty()) {
750 u16 id = added_objects.front();
751 ServerActiveObject* obj = m_env->getActiveObject(id);
754 u8 type = ACTIVEOBJECT_TYPE_INVALID;
756 warningstream<<FUNCTION_NAME
757 <<": NULL object"<<std::endl;
759 type = obj->getSendType();
761 // Add to data buffer for sending
762 writeU16((u8*)buf, id);
763 data_buffer.append(buf, 2);
764 writeU8((u8*)buf, type);
765 data_buffer.append(buf, 1);
768 data_buffer.append(serializeLongString(
769 obj->getClientInitializationData(client->net_proto_version)));
771 data_buffer.append(serializeLongString(""));
773 // Add to known objects
774 client->m_known_objects.insert(id);
777 obj->m_known_by_count++;
782 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
783 verbosestream << "Server: Sent object remove/add: "
784 << removed_objects.size() << " removed, "
785 << added_objects.size() << " added, "
786 << "packet size is " << pktSize << std::endl;
795 MutexAutoLock envlock(m_env_mutex);
796 ScopeProfiler sp(g_profiler, "Server: sending object messages");
799 // Value = data sent by object
800 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
802 // Get active object messages from environment
804 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
808 std::vector<ActiveObjectMessage>* message_list = NULL;
809 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
810 n = buffered_messages.find(aom.id);
811 if (n == buffered_messages.end()) {
812 message_list = new std::vector<ActiveObjectMessage>;
813 buffered_messages[aom.id] = message_list;
816 message_list = n->second;
818 message_list->push_back(aom);
822 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
823 // Route data to every client
824 for (std::map<u16, RemoteClient*>::iterator
826 i != clients.end(); ++i) {
827 RemoteClient *client = i->second;
828 std::string reliable_data;
829 std::string unreliable_data;
830 // Go through all objects in message buffer
831 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
832 j = buffered_messages.begin();
833 j != buffered_messages.end(); ++j) {
834 // If object is not known by client, skip it
836 if (client->m_known_objects.find(id) == client->m_known_objects.end())
839 // Get message list of object
840 std::vector<ActiveObjectMessage>* list = j->second;
841 // Go through every message
842 for (std::vector<ActiveObjectMessage>::iterator
843 k = list->begin(); k != list->end(); ++k) {
844 // Compose the full new data with header
845 ActiveObjectMessage aom = *k;
846 std::string new_data;
849 writeU16((u8*)&buf[0], aom.id);
850 new_data.append(buf, 2);
852 new_data += serializeString(aom.datastring);
853 // Add data to buffer
855 reliable_data += new_data;
857 unreliable_data += new_data;
861 reliable_data and unreliable_data are now ready.
864 if(reliable_data.size() > 0) {
865 SendActiveObjectMessages(client->peer_id, reliable_data);
868 if(unreliable_data.size() > 0) {
869 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
874 // Clear buffered_messages
875 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
876 i = buffered_messages.begin();
877 i != buffered_messages.end(); ++i) {
883 Send queued-for-sending map edit events.
886 // We will be accessing the environment
887 MutexAutoLock lock(m_env_mutex);
889 // Don't send too many at a time
892 // Single change sending is disabled if queue size is not small
893 bool disable_single_change_sending = false;
894 if(m_unsent_map_edit_queue.size() >= 4)
895 disable_single_change_sending = true;
897 int event_count = m_unsent_map_edit_queue.size();
899 // We'll log the amount of each
902 while(m_unsent_map_edit_queue.size() != 0)
904 MapEditEvent* event = m_unsent_map_edit_queue.front();
905 m_unsent_map_edit_queue.pop();
907 // Players far away from the change are stored here.
908 // Instead of sending the changes, MapBlocks are set not sent
910 std::vector<u16> far_players;
912 switch (event->type) {
915 prof.add("MEET_ADDNODE", 1);
916 sendAddNode(event->p, event->n, event->already_known_by_peer,
917 &far_players, disable_single_change_sending ? 5 : 30,
918 event->type == MEET_ADDNODE);
920 case MEET_REMOVENODE:
921 prof.add("MEET_REMOVENODE", 1);
922 sendRemoveNode(event->p, event->already_known_by_peer,
923 &far_players, disable_single_change_sending ? 5 : 30);
925 case MEET_BLOCK_NODE_METADATA_CHANGED:
926 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
927 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
928 setBlockNotSent(event->p);
931 infostream << "Server: MEET_OTHER" << std::endl;
932 prof.add("MEET_OTHER", 1);
933 for(std::set<v3s16>::iterator
934 i = event->modified_blocks.begin();
935 i != event->modified_blocks.end(); ++i) {
940 prof.add("unknown", 1);
941 warningstream << "Server: Unknown MapEditEvent "
942 << ((u32)event->type) << std::endl;
947 Set blocks not sent to far players
949 if(!far_players.empty()) {
950 // Convert list format to that wanted by SetBlocksNotSent
951 std::map<v3s16, MapBlock*> modified_blocks2;
952 for(std::set<v3s16>::iterator
953 i = event->modified_blocks.begin();
954 i != event->modified_blocks.end(); ++i) {
955 modified_blocks2[*i] =
956 m_env->getMap().getBlockNoCreateNoEx(*i);
959 // Set blocks not sent
960 for(std::vector<u16>::iterator
961 i = far_players.begin();
962 i != far_players.end(); ++i) {
963 if(RemoteClient *client = getClient(*i))
964 client->SetBlocksNotSent(modified_blocks2);
970 /*// Don't send too many at a time
972 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
976 if(event_count >= 5){
977 infostream<<"Server: MapEditEvents:"<<std::endl;
978 prof.print(infostream);
979 } else if(event_count != 0){
980 verbosestream<<"Server: MapEditEvents:"<<std::endl;
981 prof.print(verbosestream);
987 Trigger emergethread (it somehow gets to a non-triggered but
988 bysy state sometimes)
991 float &counter = m_emergethread_trigger_timer;
993 if (counter >= 2.0) {
996 m_emerge->startThreads();
1000 // Save map, players and auth stuff
1002 float &counter = m_savemap_timer;
1004 static const float save_interval =
1005 g_settings->getFloat("server_map_save_interval");
1006 if (counter >= save_interval) {
1008 MutexAutoLock lock(m_env_mutex);
1010 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1013 if (m_banmanager->isModified()) {
1014 m_banmanager->save();
1017 // Save changed parts of map
1018 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1021 m_env->saveLoadedPlayers();
1023 // Save environment metadata
1029 void Server::Receive()
1031 DSTACK(FUNCTION_NAME);
1032 SharedBuffer<u8> data;
1036 m_con.Receive(&pkt);
1037 peer_id = pkt.getPeerId();
1040 catch(con::InvalidIncomingDataException &e) {
1041 infostream<<"Server::Receive(): "
1042 "InvalidIncomingDataException: what()="
1043 <<e.what()<<std::endl;
1045 catch(SerializationError &e) {
1046 infostream<<"Server::Receive(): "
1047 "SerializationError: what()="
1048 <<e.what()<<std::endl;
1050 catch(ClientStateError &e) {
1051 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1052 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1053 L"Try reconnecting or updating your client");
1055 catch(con::PeerNotFoundException &e) {
1060 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1062 std::string playername = "";
1063 PlayerSAO *playersao = NULL;
1066 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1067 if (client != NULL) {
1068 playername = client->getName();
1069 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1071 } catch (std::exception &e) {
1077 RemotePlayer *player =
1078 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1080 // If failed, cancel
1081 if ((playersao == NULL) || (player == NULL)) {
1082 if (player && player->peer_id != 0) {
1083 actionstream << "Server: Failed to emerge player \"" << playername
1084 << "\" (player allocated to an another client)" << std::endl;
1085 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1086 L"name. If your client closed unexpectedly, try again in "
1089 errorstream << "Server: " << playername << ": Failed to emerge player"
1091 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1097 Send complete position information
1099 SendMovePlayer(peer_id);
1102 SendPlayerPrivileges(peer_id);
1104 // Send inventory formspec
1105 SendPlayerInventoryFormspec(peer_id);
1108 SendInventory(playersao);
1111 SendPlayerHPOrDie(playersao);
1114 SendPlayerBreath(peer_id);
1116 // Show death screen if necessary
1117 if(player->isDead())
1118 SendDeathscreen(peer_id, false, v3f(0,0,0));
1120 // Note things in chat if not in simple singleplayer mode
1121 if(!m_simple_singleplayer_mode) {
1122 // Send information about server to player in chat
1123 SendChatMessage(peer_id, getStatusString());
1125 // Send information about joining in chat
1127 std::string name = "unknown";
1128 Player *player = m_env->getPlayer(peer_id);
1130 name = player->getName();
1132 std::wstring message;
1134 message += narrow_to_wide(name);
1135 message += L" joined the game.";
1136 SendChatMessage(PEER_ID_INEXISTENT,message);
1138 m_admin_chat->outgoing_queue.push_back(
1139 new ChatEventNick(CET_NICK_ADD, name));
1142 Address addr = getPeerAddress(player->peer_id);
1143 std::string ip_str = addr.serializeString();
1144 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1149 std::vector<std::string> names = m_clients.getPlayerNames();
1151 actionstream<<player->getName() <<" joins game. List of players: ";
1153 for (std::vector<std::string>::iterator i = names.begin();
1154 i != names.end(); ++i) {
1155 actionstream << *i << " ";
1158 actionstream << player->getName() <<std::endl;
1163 inline void Server::handleCommand(NetworkPacket* pkt)
1165 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1166 (this->*opHandle.handler)(pkt);
1169 void Server::ProcessData(NetworkPacket *pkt)
1171 DSTACK(FUNCTION_NAME);
1172 // Environment is locked first.
1173 MutexAutoLock envlock(m_env_mutex);
1175 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1176 u32 peer_id = pkt->getPeerId();
1179 Address address = getPeerAddress(peer_id);
1180 std::string addr_s = address.serializeString();
1182 if(m_banmanager->isIpBanned(addr_s)) {
1183 std::string ban_name = m_banmanager->getBanName(addr_s);
1184 infostream << "Server: A banned client tried to connect from "
1185 << addr_s << "; banned name was "
1186 << ban_name << std::endl;
1187 // This actually doesn't seem to transfer to the client
1188 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1189 + utf8_to_wide(ban_name));
1193 catch(con::PeerNotFoundException &e) {
1195 * no peer for this packet found
1196 * most common reason is peer timeout, e.g. peer didn't
1197 * respond for some time, your server was overloaded or
1200 infostream << "Server::ProcessData(): Canceling: peer "
1201 << peer_id << " not found" << std::endl;
1206 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1208 // Command must be handled into ToServerCommandHandler
1209 if (command >= TOSERVER_NUM_MSG_TYPES) {
1210 infostream << "Server: Ignoring unknown command "
1211 << command << std::endl;
1215 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1220 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1222 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1223 errorstream << "Server::ProcessData(): Cancelling: Peer"
1224 " serialization format invalid or not initialized."
1225 " Skipping incoming command=" << command << std::endl;
1229 /* Handle commands related to client startup */
1230 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1235 if (m_clients.getClientState(peer_id) < CS_Active) {
1236 if (command == TOSERVER_PLAYERPOS) return;
1238 errorstream << "Got packet command: " << command << " for peer id "
1239 << peer_id << " but client isn't active yet. Dropping packet "
1245 } catch (SendFailedException &e) {
1246 errorstream << "Server::ProcessData(): SendFailedException: "
1247 << "what=" << e.what()
1249 } catch (PacketError &e) {
1250 actionstream << "Server::ProcessData(): PacketError: "
1251 << "what=" << e.what()
1256 void Server::setTimeOfDay(u32 time)
1258 m_env->setTimeOfDay(time);
1259 m_time_of_day_send_timer = 0;
1262 void Server::onMapEditEvent(MapEditEvent *event)
1264 if(m_ignore_map_edit_events)
1266 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1268 MapEditEvent *e = event->clone();
1269 m_unsent_map_edit_queue.push(e);
1272 Inventory* Server::getInventory(const InventoryLocation &loc)
1275 case InventoryLocation::UNDEFINED:
1276 case InventoryLocation::CURRENT_PLAYER:
1278 case InventoryLocation::PLAYER:
1280 Player *player = m_env->getPlayer(loc.name.c_str());
1283 PlayerSAO *playersao = player->getPlayerSAO();
1286 return playersao->getInventory();
1289 case InventoryLocation::NODEMETA:
1291 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1294 return meta->getInventory();
1297 case InventoryLocation::DETACHED:
1299 if(m_detached_inventories.count(loc.name) == 0)
1301 return m_detached_inventories[loc.name];
1305 sanity_check(false); // abort
1310 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1313 case InventoryLocation::UNDEFINED:
1315 case InventoryLocation::PLAYER:
1320 Player *player = m_env->getPlayer(loc.name.c_str());
1323 PlayerSAO *playersao = player->getPlayerSAO();
1327 SendInventory(playersao);
1330 case InventoryLocation::NODEMETA:
1332 v3s16 blockpos = getNodeBlockPos(loc.p);
1334 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1336 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1338 setBlockNotSent(blockpos);
1341 case InventoryLocation::DETACHED:
1343 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1347 sanity_check(false); // abort
1352 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1354 std::vector<u16> clients = m_clients.getClientIDs();
1356 // Set the modified blocks unsent for all the clients
1357 for (std::vector<u16>::iterator i = clients.begin();
1358 i != clients.end(); ++i) {
1359 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1360 client->SetBlocksNotSent(block);
1365 void Server::peerAdded(con::Peer *peer)
1367 DSTACK(FUNCTION_NAME);
1368 verbosestream<<"Server::peerAdded(): peer->id="
1369 <<peer->id<<std::endl;
1372 c.type = con::PEER_ADDED;
1373 c.peer_id = peer->id;
1375 m_peer_change_queue.push(c);
1378 void Server::deletingPeer(con::Peer *peer, bool timeout)
1380 DSTACK(FUNCTION_NAME);
1381 verbosestream<<"Server::deletingPeer(): peer->id="
1382 <<peer->id<<", timeout="<<timeout<<std::endl;
1384 m_clients.event(peer->id, CSE_Disconnect);
1386 c.type = con::PEER_REMOVED;
1387 c.peer_id = peer->id;
1388 c.timeout = timeout;
1389 m_peer_change_queue.push(c);
1392 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1394 *retval = m_con.getPeerStat(peer_id,type);
1395 if (*retval == -1) return false;
1399 bool Server::getClientInfo(
1408 std::string* vers_string
1411 *state = m_clients.getClientState(peer_id);
1413 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1415 if (client == NULL) {
1420 *uptime = client->uptime();
1421 *ser_vers = client->serialization_version;
1422 *prot_vers = client->net_proto_version;
1424 *major = client->getMajor();
1425 *minor = client->getMinor();
1426 *patch = client->getPatch();
1427 *vers_string = client->getPatch();
1434 void Server::handlePeerChanges()
1436 while(m_peer_change_queue.size() > 0)
1438 con::PeerChange c = m_peer_change_queue.front();
1439 m_peer_change_queue.pop();
1441 verbosestream<<"Server: Handling peer change: "
1442 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1447 case con::PEER_ADDED:
1448 m_clients.CreateClient(c.peer_id);
1451 case con::PEER_REMOVED:
1452 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1456 FATAL_ERROR("Invalid peer change event received!");
1462 void Server::printToConsoleOnly(const std::string &text)
1465 m_admin_chat->outgoing_queue.push_back(
1466 new ChatEventChat("", utf8_to_wide(text)));
1468 std::cout << text << std::endl;
1472 void Server::Send(NetworkPacket* pkt)
1474 m_clients.send(pkt->getPeerId(),
1475 clientCommandFactoryTable[pkt->getCommand()].channel,
1477 clientCommandFactoryTable[pkt->getCommand()].reliable);
1480 void Server::SendMovement(u16 peer_id)
1482 DSTACK(FUNCTION_NAME);
1483 std::ostringstream os(std::ios_base::binary);
1485 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1487 pkt << g_settings->getFloat("movement_acceleration_default");
1488 pkt << g_settings->getFloat("movement_acceleration_air");
1489 pkt << g_settings->getFloat("movement_acceleration_fast");
1490 pkt << g_settings->getFloat("movement_speed_walk");
1491 pkt << g_settings->getFloat("movement_speed_crouch");
1492 pkt << g_settings->getFloat("movement_speed_fast");
1493 pkt << g_settings->getFloat("movement_speed_climb");
1494 pkt << g_settings->getFloat("movement_speed_jump");
1495 pkt << g_settings->getFloat("movement_liquid_fluidity");
1496 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1497 pkt << g_settings->getFloat("movement_liquid_sink");
1498 pkt << g_settings->getFloat("movement_gravity");
1503 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1505 if (!g_settings->getBool("enable_damage"))
1508 u16 peer_id = playersao->getPeerID();
1509 bool is_alive = playersao->getHP() > 0;
1512 SendPlayerHP(peer_id);
1517 void Server::SendHP(u16 peer_id, u8 hp)
1519 DSTACK(FUNCTION_NAME);
1521 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1526 void Server::SendBreath(u16 peer_id, u16 breath)
1528 DSTACK(FUNCTION_NAME);
1530 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1531 pkt << (u16) breath;
1535 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1536 const std::string &custom_reason, bool reconnect)
1538 assert(reason < SERVER_ACCESSDENIED_MAX);
1540 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1542 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1543 pkt << custom_reason;
1544 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1545 reason == SERVER_ACCESSDENIED_CRASH)
1546 pkt << custom_reason << (u8)reconnect;
1550 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1559 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1560 v3f camera_point_target)
1562 DSTACK(FUNCTION_NAME);
1564 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1565 pkt << set_camera_point_target << camera_point_target;
1569 void Server::SendItemDef(u16 peer_id,
1570 IItemDefManager *itemdef, u16 protocol_version)
1572 DSTACK(FUNCTION_NAME);
1574 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1578 u32 length of the next item
1579 zlib-compressed serialized ItemDefManager
1581 std::ostringstream tmp_os(std::ios::binary);
1582 itemdef->serialize(tmp_os, protocol_version);
1583 std::ostringstream tmp_os2(std::ios::binary);
1584 compressZlib(tmp_os.str(), tmp_os2);
1585 pkt.putLongString(tmp_os2.str());
1588 verbosestream << "Server: Sending item definitions to id(" << peer_id
1589 << "): size=" << pkt.getSize() << std::endl;
1594 void Server::SendNodeDef(u16 peer_id,
1595 INodeDefManager *nodedef, u16 protocol_version)
1597 DSTACK(FUNCTION_NAME);
1599 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1603 u32 length of the next item
1604 zlib-compressed serialized NodeDefManager
1606 std::ostringstream tmp_os(std::ios::binary);
1607 nodedef->serialize(tmp_os, protocol_version);
1608 std::ostringstream tmp_os2(std::ios::binary);
1609 compressZlib(tmp_os.str(), tmp_os2);
1611 pkt.putLongString(tmp_os2.str());
1614 verbosestream << "Server: Sending node definitions to id(" << peer_id
1615 << "): size=" << pkt.getSize() << std::endl;
1621 Non-static send methods
1624 void Server::SendInventory(PlayerSAO* playerSAO)
1626 DSTACK(FUNCTION_NAME);
1628 UpdateCrafting(playerSAO->getPlayer());
1634 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1636 std::ostringstream os;
1637 playerSAO->getInventory()->serialize(os);
1639 std::string s = os.str();
1641 pkt.putRawString(s.c_str(), s.size());
1645 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1647 DSTACK(FUNCTION_NAME);
1649 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1652 if (peer_id != PEER_ID_INEXISTENT) {
1656 m_clients.sendToAll(0, &pkt, true);
1660 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1661 const std::string &formname)
1663 DSTACK(FUNCTION_NAME);
1665 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1667 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1673 // Spawns a particle on peer with peer_id
1674 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1675 float expirationtime, float size, bool collisiondetection,
1676 bool collision_removal,
1677 bool vertical, const std::string &texture)
1679 DSTACK(FUNCTION_NAME);
1681 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1683 pkt << pos << velocity << acceleration << expirationtime
1684 << size << collisiondetection;
1685 pkt.putLongString(texture);
1687 pkt << collision_removal;
1689 if (peer_id != PEER_ID_INEXISTENT) {
1693 m_clients.sendToAll(0, &pkt, true);
1697 // Adds a ParticleSpawner on peer with peer_id
1698 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1699 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1700 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1701 bool vertical, const std::string &texture, u32 id)
1703 DSTACK(FUNCTION_NAME);
1705 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1707 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1708 << minacc << maxacc << minexptime << maxexptime << minsize
1709 << maxsize << collisiondetection;
1711 pkt.putLongString(texture);
1713 pkt << id << vertical;
1714 pkt << collision_removal;
1716 if (peer_id != PEER_ID_INEXISTENT) {
1720 m_clients.sendToAll(0, &pkt, true);
1724 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1726 DSTACK(FUNCTION_NAME);
1728 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1730 // Ugly error in this packet
1733 if (peer_id != PEER_ID_INEXISTENT) {
1737 m_clients.sendToAll(0, &pkt, true);
1742 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1744 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1746 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1747 << form->text << form->number << form->item << form->dir
1748 << form->align << form->offset << form->world_pos << form->size;
1753 void Server::SendHUDRemove(u16 peer_id, u32 id)
1755 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1760 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1762 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1763 pkt << id << (u8) stat;
1767 case HUD_STAT_SCALE:
1768 case HUD_STAT_ALIGN:
1769 case HUD_STAT_OFFSET:
1770 pkt << *(v2f *) value;
1774 pkt << *(std::string *) value;
1776 case HUD_STAT_WORLD_POS:
1777 pkt << *(v3f *) value;
1780 pkt << *(v2s32 *) value;
1782 case HUD_STAT_NUMBER:
1786 pkt << *(u32 *) value;
1793 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1795 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1797 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1799 pkt << flags << mask;
1804 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1806 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1807 pkt << param << value;
1811 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1812 const std::string &type, const std::vector<std::string> ¶ms)
1814 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1815 pkt << bgcolor << type << (u16) params.size();
1817 for(size_t i=0; i<params.size(); i++)
1823 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1826 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1829 pkt << do_override << (u16) (ratio * 65535);
1834 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1836 DSTACK(FUNCTION_NAME);
1838 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1839 pkt << time << time_speed;
1841 if (peer_id == PEER_ID_INEXISTENT) {
1842 m_clients.sendToAll(0, &pkt, true);
1849 void Server::SendPlayerHP(u16 peer_id)
1851 DSTACK(FUNCTION_NAME);
1852 PlayerSAO *playersao = getPlayerSAO(peer_id);
1853 // In some rare case if the player is disconnected
1854 // while Lua call l_punch, for example, this can be NULL
1858 SendHP(peer_id, playersao->getHP());
1859 m_script->player_event(playersao,"health_changed");
1861 // Send to other clients
1862 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1863 ActiveObjectMessage aom(playersao->getId(), true, str);
1864 playersao->m_messages_out.push(aom);
1867 void Server::SendPlayerBreath(u16 peer_id)
1869 DSTACK(FUNCTION_NAME);
1870 PlayerSAO *playersao = getPlayerSAO(peer_id);
1873 m_script->player_event(playersao, "breath_changed");
1874 SendBreath(peer_id, playersao->getBreath());
1877 void Server::SendMovePlayer(u16 peer_id)
1879 DSTACK(FUNCTION_NAME);
1880 Player *player = m_env->getPlayer(peer_id);
1883 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1884 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1887 v3f pos = player->getPosition();
1888 f32 pitch = player->getPitch();
1889 f32 yaw = player->getYaw();
1890 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1891 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1892 << " pitch=" << pitch
1900 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1902 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1905 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1906 << animation_frames[3] << animation_speed;
1911 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1913 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1914 pkt << first << third;
1917 void Server::SendPlayerPrivileges(u16 peer_id)
1919 Player *player = m_env->getPlayer(peer_id);
1921 if(player->peer_id == PEER_ID_INEXISTENT)
1924 std::set<std::string> privs;
1925 m_script->getAuth(player->getName(), NULL, &privs);
1927 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1928 pkt << (u16) privs.size();
1930 for(std::set<std::string>::const_iterator i = privs.begin();
1931 i != privs.end(); ++i) {
1938 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1940 Player *player = m_env->getPlayer(peer_id);
1942 if(player->peer_id == PEER_ID_INEXISTENT)
1945 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1946 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1950 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1952 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1953 pkt.putRawString(datas.c_str(), datas.size());
1955 return pkt.getSize();
1958 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1960 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1961 datas.size(), peer_id);
1963 pkt.putRawString(datas.c_str(), datas.size());
1965 m_clients.send(pkt.getPeerId(),
1966 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1971 s32 Server::playSound(const SimpleSoundSpec &spec,
1972 const ServerSoundParams ¶ms)
1974 // Find out initial position of sound
1975 bool pos_exists = false;
1976 v3f pos = params.getPos(m_env, &pos_exists);
1977 // If position is not found while it should be, cancel sound
1978 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1981 // Filter destination clients
1982 std::vector<u16> dst_clients;
1983 if(params.to_player != "")
1985 Player *player = m_env->getPlayer(params.to_player.c_str());
1987 infostream<<"Server::playSound: Player \""<<params.to_player
1988 <<"\" not found"<<std::endl;
1991 if(player->peer_id == PEER_ID_INEXISTENT){
1992 infostream<<"Server::playSound: Player \""<<params.to_player
1993 <<"\" not connected"<<std::endl;
1996 dst_clients.push_back(player->peer_id);
1999 std::vector<u16> clients = m_clients.getClientIDs();
2001 for(std::vector<u16>::iterator
2002 i = clients.begin(); i != clients.end(); ++i) {
2003 Player *player = m_env->getPlayer(*i);
2008 if(player->getPosition().getDistanceFrom(pos) >
2009 params.max_hear_distance)
2012 dst_clients.push_back(*i);
2016 if(dst_clients.empty())
2020 s32 id = m_next_sound_id++;
2021 // The sound will exist as a reference in m_playing_sounds
2022 m_playing_sounds[id] = ServerPlayingSound();
2023 ServerPlayingSound &psound = m_playing_sounds[id];
2024 psound.params = params;
2026 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2027 pkt << id << spec.name << (float) (spec.gain * params.gain)
2028 << (u8) params.type << pos << params.object << params.loop;
2030 for(std::vector<u16>::iterator i = dst_clients.begin();
2031 i != dst_clients.end(); ++i) {
2032 psound.clients.insert(*i);
2033 m_clients.send(*i, 0, &pkt, true);
2037 void Server::stopSound(s32 handle)
2039 // Get sound reference
2040 std::map<s32, ServerPlayingSound>::iterator i =
2041 m_playing_sounds.find(handle);
2042 if(i == m_playing_sounds.end())
2044 ServerPlayingSound &psound = i->second;
2046 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2049 for(std::set<u16>::iterator i = psound.clients.begin();
2050 i != psound.clients.end(); ++i) {
2052 m_clients.send(*i, 0, &pkt, true);
2054 // Remove sound reference
2055 m_playing_sounds.erase(i);
2058 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2059 std::vector<u16> *far_players, float far_d_nodes)
2061 float maxd = far_d_nodes*BS;
2062 v3f p_f = intToFloat(p, BS);
2064 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2067 std::vector<u16> clients = m_clients.getClientIDs();
2068 for(std::vector<u16>::iterator i = clients.begin();
2069 i != clients.end(); ++i) {
2072 if(Player *player = m_env->getPlayer(*i)) {
2073 // If player is far away, only set modified blocks not sent
2074 v3f player_pos = player->getPosition();
2075 if(player_pos.getDistanceFrom(p_f) > maxd) {
2076 far_players->push_back(*i);
2083 m_clients.send(*i, 0, &pkt, true);
2087 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2088 std::vector<u16> *far_players, float far_d_nodes,
2089 bool remove_metadata)
2091 float maxd = far_d_nodes*BS;
2092 v3f p_f = intToFloat(p, BS);
2094 std::vector<u16> clients = m_clients.getClientIDs();
2095 for(std::vector<u16>::iterator i = clients.begin();
2096 i != clients.end(); ++i) {
2100 if(Player *player = m_env->getPlayer(*i)) {
2101 // If player is far away, only set modified blocks not sent
2102 v3f player_pos = player->getPosition();
2103 if(player_pos.getDistanceFrom(p_f) > maxd) {
2104 far_players->push_back(*i);
2110 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2112 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2114 pkt << p << n.param0 << n.param1 << n.param2
2115 << (u8) (remove_metadata ? 0 : 1);
2117 if (!remove_metadata) {
2118 if (client->net_proto_version <= 21) {
2119 // Old clients always clear metadata; fix it
2120 // by sending the full block again.
2121 client->SetBlockNotSent(getNodeBlockPos(p));
2128 if (pkt.getSize() > 0)
2129 m_clients.send(*i, 0, &pkt, true);
2133 void Server::setBlockNotSent(v3s16 p)
2135 std::vector<u16> clients = m_clients.getClientIDs();
2137 for(std::vector<u16>::iterator i = clients.begin();
2138 i != clients.end(); ++i) {
2139 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2140 client->SetBlockNotSent(p);
2145 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2147 DSTACK(FUNCTION_NAME);
2149 v3s16 p = block->getPos();
2152 Create a packet with the block in the right format
2155 std::ostringstream os(std::ios_base::binary);
2156 block->serialize(os, ver, false);
2157 block->serializeNetworkSpecific(os, net_proto_version);
2158 std::string s = os.str();
2160 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2163 pkt.putRawString(s.c_str(), s.size());
2167 void Server::SendBlocks(float dtime)
2169 DSTACK(FUNCTION_NAME);
2171 MutexAutoLock envlock(m_env_mutex);
2172 //TODO check if one big lock could be faster then multiple small ones
2174 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2176 std::vector<PrioritySortedBlockTransfer> queue;
2178 s32 total_sending = 0;
2181 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2183 std::vector<u16> clients = m_clients.getClientIDs();
2186 for(std::vector<u16>::iterator i = clients.begin();
2187 i != clients.end(); ++i) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2193 total_sending += client->SendingCount();
2194 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2200 // Lowest priority number comes first.
2201 // Lowest is most important.
2202 std::sort(queue.begin(), queue.end());
2205 for(u32 i=0; i<queue.size(); i++)
2207 //TODO: Calculate limit dynamically
2208 if(total_sending >= g_settings->getS32
2209 ("max_simultaneous_block_sends_server_total"))
2212 PrioritySortedBlockTransfer q = queue[i];
2214 MapBlock *block = NULL;
2217 block = m_env->getMap().getBlockNoCreate(q.pos);
2219 catch(InvalidPositionException &e)
2224 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2229 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2231 client->SentBlock(q.pos);
2237 void Server::fillMediaCache()
2239 DSTACK(FUNCTION_NAME);
2241 infostream<<"Server: Calculating media file checksums"<<std::endl;
2243 // Collect all media file paths
2244 std::vector<std::string> paths;
2245 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2246 i != m_mods.end(); ++i) {
2247 const ModSpec &mod = *i;
2248 paths.push_back(mod.path + DIR_DELIM + "textures");
2249 paths.push_back(mod.path + DIR_DELIM + "sounds");
2250 paths.push_back(mod.path + DIR_DELIM + "media");
2251 paths.push_back(mod.path + DIR_DELIM + "models");
2253 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2255 // Collect media file information from paths into cache
2256 for(std::vector<std::string>::iterator i = paths.begin();
2257 i != paths.end(); ++i) {
2258 std::string mediapath = *i;
2259 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2260 for (u32 j = 0; j < dirlist.size(); j++) {
2261 if (dirlist[j].dir) // Ignode dirs
2263 std::string filename = dirlist[j].name;
2264 // If name contains illegal characters, ignore the file
2265 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2266 infostream<<"Server: ignoring illegal file name: \""
2267 << filename << "\"" << std::endl;
2270 // If name is not in a supported format, ignore it
2271 const char *supported_ext[] = {
2272 ".png", ".jpg", ".bmp", ".tga",
2273 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2275 ".x", ".b3d", ".md2", ".obj",
2278 if (removeStringEnd(filename, supported_ext) == ""){
2279 infostream << "Server: ignoring unsupported file extension: \""
2280 << filename << "\"" << std::endl;
2283 // Ok, attempt to load the file and add to cache
2284 std::string filepath = mediapath + DIR_DELIM + filename;
2286 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2288 errorstream << "Server::fillMediaCache(): Could not open \""
2289 << filename << "\" for reading" << std::endl;
2292 std::ostringstream tmp_os(std::ios_base::binary);
2296 fis.read(buf, 1024);
2297 std::streamsize len = fis.gcount();
2298 tmp_os.write(buf, len);
2307 errorstream<<"Server::fillMediaCache(): Failed to read \""
2308 << filename << "\"" << std::endl;
2311 if(tmp_os.str().length() == 0) {
2312 errorstream << "Server::fillMediaCache(): Empty file \""
2313 << filepath << "\"" << std::endl;
2318 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2320 unsigned char *digest = sha1.getDigest();
2321 std::string sha1_base64 = base64_encode(digest, 20);
2322 std::string sha1_hex = hex_encode((char*)digest, 20);
2326 m_media[filename] = MediaInfo(filepath, sha1_base64);
2327 verbosestream << "Server: " << sha1_hex << " is " << filename
2333 void Server::sendMediaAnnouncement(u16 peer_id)
2335 DSTACK(FUNCTION_NAME);
2337 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2341 std::ostringstream os(std::ios_base::binary);
2343 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2344 pkt << (u16) m_media.size();
2346 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2347 i != m_media.end(); ++i) {
2348 pkt << i->first << i->second.sha1_digest;
2351 pkt << g_settings->get("remote_media");
2355 struct SendableMedia
2361 SendableMedia(const std::string &name_="", const std::string &path_="",
2362 const std::string &data_=""):
2369 void Server::sendRequestedMedia(u16 peer_id,
2370 const std::vector<std::string> &tosend)
2372 DSTACK(FUNCTION_NAME);
2374 verbosestream<<"Server::sendRequestedMedia(): "
2375 <<"Sending files to client"<<std::endl;
2379 // Put 5kB in one bunch (this is not accurate)
2380 u32 bytes_per_bunch = 5000;
2382 std::vector< std::vector<SendableMedia> > file_bunches;
2383 file_bunches.push_back(std::vector<SendableMedia>());
2385 u32 file_size_bunch_total = 0;
2387 for(std::vector<std::string>::const_iterator i = tosend.begin();
2388 i != tosend.end(); ++i) {
2389 const std::string &name = *i;
2391 if(m_media.find(name) == m_media.end()) {
2392 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2393 <<"unknown file \""<<(name)<<"\""<<std::endl;
2397 //TODO get path + name
2398 std::string tpath = m_media[name].path;
2401 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2402 if(fis.good() == false){
2403 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2404 <<tpath<<"\" for reading"<<std::endl;
2407 std::ostringstream tmp_os(std::ios_base::binary);
2411 fis.read(buf, 1024);
2412 std::streamsize len = fis.gcount();
2413 tmp_os.write(buf, len);
2414 file_size_bunch_total += len;
2423 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2424 <<name<<"\""<<std::endl;
2427 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2428 <<tname<<"\""<<std::endl;*/
2430 file_bunches[file_bunches.size()-1].push_back(
2431 SendableMedia(name, tpath, tmp_os.str()));
2433 // Start next bunch if got enough data
2434 if(file_size_bunch_total >= bytes_per_bunch) {
2435 file_bunches.push_back(std::vector<SendableMedia>());
2436 file_size_bunch_total = 0;
2441 /* Create and send packets */
2443 u16 num_bunches = file_bunches.size();
2444 for(u16 i = 0; i < num_bunches; i++) {
2447 u16 total number of texture bunches
2448 u16 index of this bunch
2449 u32 number of files in this bunch
2458 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2459 pkt << num_bunches << i << (u32) file_bunches[i].size();
2461 for(std::vector<SendableMedia>::iterator
2462 j = file_bunches[i].begin();
2463 j != file_bunches[i].end(); ++j) {
2465 pkt.putLongString(j->data);
2468 verbosestream << "Server::sendRequestedMedia(): bunch "
2469 << i << "/" << num_bunches
2470 << " files=" << file_bunches[i].size()
2471 << " size=" << pkt.getSize() << std::endl;
2476 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2478 if(m_detached_inventories.count(name) == 0) {
2479 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2482 Inventory *inv = m_detached_inventories[name];
2483 std::ostringstream os(std::ios_base::binary);
2485 os << serializeString(name);
2489 std::string s = os.str();
2491 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2492 pkt.putRawString(s.c_str(), s.size());
2494 if (peer_id != PEER_ID_INEXISTENT) {
2498 m_clients.sendToAll(0, &pkt, true);
2502 void Server::sendDetachedInventories(u16 peer_id)
2504 DSTACK(FUNCTION_NAME);
2506 for(std::map<std::string, Inventory*>::iterator
2507 i = m_detached_inventories.begin();
2508 i != m_detached_inventories.end(); ++i) {
2509 const std::string &name = i->first;
2510 //Inventory *inv = i->second;
2511 sendDetachedInventory(name, peer_id);
2519 void Server::DiePlayer(u16 peer_id)
2521 DSTACK(FUNCTION_NAME);
2522 PlayerSAO *playersao = getPlayerSAO(peer_id);
2523 // In some rare cases this can be NULL -- if the player is disconnected
2524 // when a Lua function modifies l_punch, for example
2528 infostream << "Server::DiePlayer(): Player "
2529 << playersao->getPlayer()->getName()
2530 << " dies" << std::endl;
2532 playersao->setHP(0);
2534 // Trigger scripted stuff
2535 m_script->on_dieplayer(playersao);
2537 SendPlayerHP(peer_id);
2538 SendDeathscreen(peer_id, false, v3f(0,0,0));
2541 void Server::RespawnPlayer(u16 peer_id)
2543 DSTACK(FUNCTION_NAME);
2545 PlayerSAO *playersao = getPlayerSAO(peer_id);
2548 infostream << "Server::RespawnPlayer(): Player "
2549 << playersao->getPlayer()->getName()
2550 << " respawns" << std::endl;
2552 playersao->setHP(PLAYER_MAX_HP);
2553 playersao->setBreath(PLAYER_MAX_BREATH);
2555 SendPlayerHP(peer_id);
2556 SendPlayerBreath(peer_id);
2558 bool repositioned = m_script->on_respawnplayer(playersao);
2560 v3f pos = findSpawnPos();
2561 // setPos will send the new position to client
2562 playersao->setPos(pos);
2567 void Server::DenySudoAccess(u16 peer_id)
2569 DSTACK(FUNCTION_NAME);
2571 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2576 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2577 const std::string &str_reason, bool reconnect)
2579 if (proto_ver >= 25) {
2580 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2582 std::wstring wreason = utf8_to_wide(
2583 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2584 accessDeniedStrings[(u8)reason]);
2585 SendAccessDenied_Legacy(peer_id, wreason);
2588 m_clients.event(peer_id, CSE_SetDenied);
2589 m_con.DisconnectPeer(peer_id);
2593 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2595 DSTACK(FUNCTION_NAME);
2597 SendAccessDenied(peer_id, reason, custom_reason);
2598 m_clients.event(peer_id, CSE_SetDenied);
2599 m_con.DisconnectPeer(peer_id);
2602 // 13/03/15: remove this function when protocol version 25 will become
2603 // the minimum version for MT users, maybe in 1 year
2604 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2606 DSTACK(FUNCTION_NAME);
2608 SendAccessDenied_Legacy(peer_id, reason);
2609 m_clients.event(peer_id, CSE_SetDenied);
2610 m_con.DisconnectPeer(peer_id);
2613 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2615 DSTACK(FUNCTION_NAME);
2618 RemoteClient* client = getClient(peer_id, CS_Invalid);
2620 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2622 // Right now, the auth mechs don't change between login and sudo mode.
2623 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2624 client->allowed_sudo_mechs = sudo_auth_mechs;
2626 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2627 << g_settings->getFloat("dedicated_server_step")
2631 m_clients.event(peer_id, CSE_AuthAccept);
2633 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2635 // We only support SRP right now
2636 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2638 resp_pkt << sudo_auth_mechs;
2640 m_clients.event(peer_id, CSE_SudoSuccess);
2644 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2646 DSTACK(FUNCTION_NAME);
2647 std::wstring message;
2650 Clear references to playing sounds
2652 for(std::map<s32, ServerPlayingSound>::iterator
2653 i = m_playing_sounds.begin();
2654 i != m_playing_sounds.end();)
2656 ServerPlayingSound &psound = i->second;
2657 psound.clients.erase(peer_id);
2658 if(psound.clients.empty())
2659 m_playing_sounds.erase(i++);
2664 Player *player = m_env->getPlayer(peer_id);
2666 // Collect information about leaving in chat
2668 if(player != NULL && reason != CDR_DENY)
2670 std::wstring name = narrow_to_wide(player->getName());
2673 message += L" left the game.";
2674 if(reason == CDR_TIMEOUT)
2675 message += L" (timed out)";
2679 /* Run scripts and remove from environment */
2683 PlayerSAO *playersao = player->getPlayerSAO();
2686 m_script->on_leaveplayer(playersao);
2688 playersao->disconnected();
2696 if(player != NULL && reason != CDR_DENY) {
2697 std::ostringstream os(std::ios_base::binary);
2698 std::vector<u16> clients = m_clients.getClientIDs();
2700 for(std::vector<u16>::iterator i = clients.begin();
2701 i != clients.end(); ++i) {
2703 Player *player = m_env->getPlayer(*i);
2707 // Get name of player
2708 os << player->getName() << " ";
2711 std::string name = player->getName();
2712 actionstream << name << " "
2713 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2714 << " List of players: " << os.str() << std::endl;
2716 m_admin_chat->outgoing_queue.push_back(
2717 new ChatEventNick(CET_NICK_REMOVE, name));
2721 MutexAutoLock env_lock(m_env_mutex);
2722 m_clients.DeleteClient(peer_id);
2726 // Send leave chat message to all remaining clients
2727 if(message.length() != 0)
2728 SendChatMessage(PEER_ID_INEXISTENT,message);
2731 void Server::UpdateCrafting(Player* player)
2733 DSTACK(FUNCTION_NAME);
2735 // Get a preview for crafting
2737 InventoryLocation loc;
2738 loc.setPlayer(player->getName());
2739 std::vector<ItemStack> output_replacements;
2740 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2741 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2743 // Put the new preview in
2744 InventoryList *plist = player->inventory.getList("craftpreview");
2745 sanity_check(plist);
2746 sanity_check(plist->getSize() >= 1);
2747 plist->changeItem(0, preview);
2750 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2752 if (evt->type == CET_NICK_ADD) {
2753 // The terminal informed us of its nick choice
2754 m_admin_nick = ((ChatEventNick *)evt)->nick;
2755 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2756 errorstream << "You haven't set up an account." << std::endl
2757 << "Please log in using the client as '"
2758 << m_admin_nick << "' with a secure password." << std::endl
2759 << "Until then, you can't execute admin tasks via the console," << std::endl
2760 << "and everybody can claim the user account instead of you," << std::endl
2761 << "giving them full control over this server." << std::endl;
2764 assert(evt->type == CET_CHAT);
2765 handleAdminChat((ChatEventChat *)evt);
2769 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2770 const std::wstring &wmessage, bool check_shout_priv,
2771 u16 peer_id_to_avoid_sending)
2773 // If something goes wrong, this player is to blame
2774 RollbackScopeActor rollback_scope(m_rollback,
2775 std::string("player:") + name);
2779 // Whether to send line to the player that sent the message, or to all players
2780 bool broadcast_line = true;
2783 bool ate = m_script->on_chat_message(name,
2784 wide_to_utf8(wmessage));
2785 // If script ate the message, don't proceed
2789 // Commands are implemented in Lua, so only catch invalid
2790 // commands that were not "eaten" and send an error back
2791 if (wmessage[0] == L'/') {
2792 std::wstring wcmd = wmessage.substr(1);
2793 broadcast_line = false;
2794 if (wcmd.length() == 0)
2795 line += L"-!- Empty command";
2797 line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
2799 if (check_shout_priv && !checkPriv(name, "shout")) {
2800 line += L"-!- You don't have permission to shout.";
2801 broadcast_line = false;
2811 Tell calling method to send the message to sender
2813 if (!broadcast_line) {
2817 Send the message to others
2819 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2821 std::vector<u16> clients = m_clients.getClientIDs();
2823 for (u16 i = 0; i < clients.size(); i++) {
2824 u16 cid = clients[i];
2825 if (cid != peer_id_to_avoid_sending)
2826 SendChatMessage(cid, line);
2832 void Server::handleAdminChat(const ChatEventChat *evt)
2834 std::string name = evt->nick;
2835 std::wstring wname = utf8_to_wide(name);
2836 std::wstring wmessage = evt->evt_msg;
2838 std::wstring answer = handleChat(name, wname, wmessage);
2840 // If asked to send answer to sender
2841 if (!answer.empty()) {
2842 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2846 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2848 RemoteClient *client = getClientNoEx(peer_id,state_min);
2850 throw ClientNotFoundException("Client not found");
2854 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2856 return m_clients.getClientNoEx(peer_id, state_min);
2859 std::string Server::getPlayerName(u16 peer_id)
2861 Player *player = m_env->getPlayer(peer_id);
2863 return "[id="+itos(peer_id)+"]";
2864 return player->getName();
2867 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2869 Player *player = m_env->getPlayer(peer_id);
2872 return player->getPlayerSAO();
2875 std::wstring Server::getStatusString()
2877 std::wostringstream os(std::ios_base::binary);
2880 os<<L"version="<<narrow_to_wide(g_version_string);
2882 os<<L", uptime="<<m_uptime.get();
2884 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2885 // Information about clients
2888 std::vector<u16> clients = m_clients.getClientIDs();
2889 for(std::vector<u16>::iterator i = clients.begin();
2890 i != clients.end(); ++i) {
2892 Player *player = m_env->getPlayer(*i);
2893 // Get name of player
2894 std::wstring name = L"unknown";
2896 name = narrow_to_wide(player->getName());
2897 // Add name to information string
2905 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2906 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2907 if(g_settings->get("motd") != "")
2908 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2912 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2914 std::set<std::string> privs;
2915 m_script->getAuth(name, NULL, &privs);
2919 bool Server::checkPriv(const std::string &name, const std::string &priv)
2921 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2922 return (privs.count(priv) != 0);
2925 void Server::reportPrivsModified(const std::string &name)
2928 std::vector<u16> clients = m_clients.getClientIDs();
2929 for(std::vector<u16>::iterator i = clients.begin();
2930 i != clients.end(); ++i) {
2931 Player *player = m_env->getPlayer(*i);
2932 reportPrivsModified(player->getName());
2935 Player *player = m_env->getPlayer(name.c_str());
2938 SendPlayerPrivileges(player->peer_id);
2939 PlayerSAO *sao = player->getPlayerSAO();
2942 sao->updatePrivileges(
2943 getPlayerEffectivePrivs(name),
2948 void Server::reportInventoryFormspecModified(const std::string &name)
2950 Player *player = m_env->getPlayer(name.c_str());
2953 SendPlayerInventoryFormspec(player->peer_id);
2956 void Server::setIpBanned(const std::string &ip, const std::string &name)
2958 m_banmanager->add(ip, name);
2961 void Server::unsetIpBanned(const std::string &ip_or_name)
2963 m_banmanager->remove(ip_or_name);
2966 std::string Server::getBanDescription(const std::string &ip_or_name)
2968 return m_banmanager->getBanDescription(ip_or_name);
2971 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2973 // m_env will be NULL if the server is initializing
2977 if (m_admin_nick == name && !m_admin_nick.empty()) {
2978 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2981 Player *player = m_env->getPlayer(name);
2986 if (player->peer_id == PEER_ID_INEXISTENT)
2989 SendChatMessage(player->peer_id, msg);
2992 bool Server::showFormspec(const char *playername, const std::string &formspec,
2993 const std::string &formname)
2995 // m_env will be NULL if the server is initializing
2999 Player *player = m_env->getPlayer(playername);
3003 SendShowFormspecMessage(player->peer_id, formspec, formname);
3007 u32 Server::hudAdd(Player *player, HudElement *form)
3012 u32 id = player->addHud(form);
3014 SendHUDAdd(player->peer_id, id, form);
3019 bool Server::hudRemove(Player *player, u32 id) {
3023 HudElement* todel = player->removeHud(id);
3030 SendHUDRemove(player->peer_id, id);
3034 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
3039 SendHUDChange(player->peer_id, id, stat, data);
3043 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
3048 SendHUDSetFlags(player->peer_id, flags, mask);
3049 player->hud_flags &= ~mask;
3050 player->hud_flags |= flags;
3052 PlayerSAO* playersao = player->getPlayerSAO();
3054 if (playersao == NULL)
3057 m_script->player_event(playersao, "hud_changed");
3061 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
3065 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3068 player->setHotbarItemcount(hotbar_itemcount);
3069 std::ostringstream os(std::ios::binary);
3070 writeS32(os, hotbar_itemcount);
3071 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3075 s32 Server::hudGetHotbarItemcount(Player *player)
3079 return player->getHotbarItemcount();
3082 void Server::hudSetHotbarImage(Player *player, std::string name)
3087 player->setHotbarImage(name);
3088 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3091 std::string Server::hudGetHotbarImage(Player *player)
3095 return player->getHotbarImage();
3098 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
3103 player->setHotbarSelectedImage(name);
3104 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3107 std::string Server::hudGetHotbarSelectedImage(Player *player)
3112 return player->getHotbarSelectedImage();
3115 bool Server::setLocalPlayerAnimations(Player *player,
3116 v2s32 animation_frames[4], f32 frame_speed)
3121 player->setLocalAnimations(animation_frames, frame_speed);
3122 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3126 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3131 player->eye_offset_first = first;
3132 player->eye_offset_third = third;
3133 SendEyeOffset(player->peer_id, first, third);
3137 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3138 const std::string &type, const std::vector<std::string> ¶ms)
3143 player->setSky(bgcolor, type, params);
3144 SendSetSky(player->peer_id, bgcolor, type, params);
3148 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3154 player->overrideDayNightRatio(do_override, ratio);
3155 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3159 void Server::notifyPlayers(const std::wstring &msg)
3161 SendChatMessage(PEER_ID_INEXISTENT,msg);
3164 void Server::spawnParticle(const std::string &playername, v3f pos,
3165 v3f velocity, v3f acceleration,
3166 float expirationtime, float size, bool
3167 collisiondetection, bool collision_removal,
3168 bool vertical, const std::string &texture)
3170 // m_env will be NULL if the server is initializing
3174 u16 peer_id = PEER_ID_INEXISTENT;
3175 if (playername != "") {
3176 Player* player = m_env->getPlayer(playername.c_str());
3179 peer_id = player->peer_id;
3182 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3183 expirationtime, size, collisiondetection,
3184 collision_removal, vertical, texture);
3187 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3188 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3189 float minexptime, float maxexptime, float minsize, float maxsize,
3190 bool collisiondetection, bool collision_removal,
3191 bool vertical, const std::string &texture,
3192 const std::string &playername)
3194 // m_env will be NULL if the server is initializing
3198 u16 peer_id = PEER_ID_INEXISTENT;
3199 if (playername != "") {
3200 Player* player = m_env->getPlayer(playername.c_str());
3203 peer_id = player->peer_id;
3206 u32 id = m_env->addParticleSpawner(spawntime);
3207 SendAddParticleSpawner(peer_id, amount, spawntime,
3208 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3209 minexptime, maxexptime, minsize, maxsize,
3210 collisiondetection, collision_removal, vertical, texture, id);
3215 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3217 // m_env will be NULL if the server is initializing
3219 throw ServerError("Can't delete particle spawners during initialisation!");
3221 u16 peer_id = PEER_ID_INEXISTENT;
3222 if (playername != "") {
3223 Player* player = m_env->getPlayer(playername.c_str());
3226 peer_id = player->peer_id;
3229 m_env->deleteParticleSpawner(id);
3230 SendDeleteParticleSpawner(peer_id, id);
3233 void Server::deleteParticleSpawnerAll(u32 id)
3235 m_env->deleteParticleSpawner(id);
3236 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3239 Inventory* Server::createDetachedInventory(const std::string &name)
3241 if(m_detached_inventories.count(name) > 0){
3242 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3243 delete m_detached_inventories[name];
3245 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3247 Inventory *inv = new Inventory(m_itemdef);
3249 m_detached_inventories[name] = inv;
3250 //TODO find a better way to do this
3251 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3255 // actions: time-reversed list
3256 // Return value: success/failure
3257 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3258 std::list<std::string> *log)
3260 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3261 ServerMap *map = (ServerMap*)(&m_env->getMap());
3263 // Fail if no actions to handle
3264 if(actions.empty()){
3265 log->push_back("Nothing to do.");
3272 for(std::list<RollbackAction>::const_iterator
3273 i = actions.begin();
3274 i != actions.end(); ++i)
3276 const RollbackAction &action = *i;
3278 bool success = action.applyRevert(map, this, this);
3281 std::ostringstream os;
3282 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3283 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3285 log->push_back(os.str());
3287 std::ostringstream os;
3288 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3289 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3291 log->push_back(os.str());
3295 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3296 <<" failed"<<std::endl;
3298 // Call it done if less than half failed
3299 return num_failed <= num_tried/2;
3302 // IGameDef interface
3304 IItemDefManager *Server::getItemDefManager()
3309 INodeDefManager *Server::getNodeDefManager()
3314 ICraftDefManager *Server::getCraftDefManager()
3318 ITextureSource *Server::getTextureSource()
3322 IShaderSource *Server::getShaderSource()
3326 scene::ISceneManager *Server::getSceneManager()
3331 u16 Server::allocateUnknownNodeId(const std::string &name)
3333 return m_nodedef->allocateDummy(name);
3336 ISoundManager *Server::getSoundManager()
3338 return &dummySoundManager;
3341 MtEventManager *Server::getEventManager()
3346 IWritableItemDefManager *Server::getWritableItemDefManager()
3351 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3356 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3361 const ModSpec *Server::getModSpec(const std::string &modname) const
3363 std::vector<ModSpec>::const_iterator it;
3364 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3365 const ModSpec &mod = *it;
3366 if (mod.name == modname)
3372 void Server::getModNames(std::vector<std::string> &modlist)
3374 std::vector<ModSpec>::iterator it;
3375 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3376 modlist.push_back(it->name);
3379 std::string Server::getBuiltinLuaPath()
3381 return porting::path_share + DIR_DELIM + "builtin";
3384 v3f Server::findSpawnPos()
3386 ServerMap &map = m_env->getServerMap();
3388 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3389 return nodeposf * BS;
3392 bool is_good = false;
3394 // Try to find a good place a few times
3395 for(s32 i = 0; i < 4000 && !is_good; i++) {
3397 // We're going to try to throw the player to this position
3398 v2s16 nodepos2d = v2s16(
3399 -range + (myrand() % (range * 2)),
3400 -range + (myrand() % (range * 2)));
3402 // Get spawn level at point
3403 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3404 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3405 // the mapgen to signify an unsuitable spawn position
3406 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3409 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3412 for (s32 i = 0; i < 10; i++) {
3413 v3s16 blockpos = getNodeBlockPos(nodepos);
3414 map.emergeBlock(blockpos, true);
3415 content_t c = map.getNodeNoEx(nodepos).getContent();
3416 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3418 if (air_count >= 2) {
3419 nodeposf = intToFloat(nodepos, BS);
3420 // Don't spawn the player outside map boundaries
3421 if (objectpos_over_limit(nodeposf))
3434 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3436 bool newplayer = false;
3439 Try to get an existing player
3441 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3443 // If player is already connected, cancel
3444 if(player != NULL && player->peer_id != 0)
3446 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3451 If player with the wanted peer_id already exists, cancel.
3453 if(m_env->getPlayer(peer_id) != NULL)
3455 infostream<<"emergePlayer(): Player with wrong name but same"
3456 " peer_id already exists"<<std::endl;
3460 // Load player if it isn't already loaded
3462 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3465 // Create player if it doesn't exist
3468 player = new RemotePlayer(this, name);
3469 // Set player position
3470 infostream<<"Server: Finding spawn place for player \""
3471 <<name<<"\""<<std::endl;
3472 v3f pos = findSpawnPos();
3473 player->setPosition(pos);
3475 // Make sure the player is saved
3476 player->setModified(true);
3478 // Add player to environment
3479 m_env->addPlayer(player);
3481 // If the player exists, ensure that they respawn inside legal bounds
3482 // This fixes an assert crash when the player can't be added
3483 // to the environment
3484 if (objectpos_over_limit(player->getPosition())) {
3485 actionstream << "Respawn position for player \""
3486 << name << "\" outside limits, resetting" << std::endl;
3487 v3f pos = findSpawnPos();
3488 player->setPosition(pos);
3492 // Create a new player active object
3493 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3494 getPlayerEffectivePrivs(player->getName()),
3497 player->protocol_version = proto_version;
3499 /* Clean up old HUD elements from previous sessions */
3502 /* Add object to environment */
3503 m_env->addActiveObject(playersao);
3507 m_script->on_newplayer(playersao);
3513 void dedicated_server_loop(Server &server, bool &kill)
3515 DSTACK(FUNCTION_NAME);
3517 verbosestream<<"dedicated_server_loop()"<<std::endl;
3519 IntervalLimiter m_profiler_interval;
3521 static const float steplen = g_settings->getFloat("dedicated_server_step");
3522 static const float profiler_print_interval =
3523 g_settings->getFloat("profiler_print_interval");
3526 // This is kind of a hack but can be done like this
3527 // because server.step() is very light
3529 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3530 sleep_ms((int)(steplen*1000.0));
3532 server.step(steplen);
3534 if(server.getShutdownRequested() || kill)
3536 infostream<<"Dedicated server quitting"<<std::endl;
3538 if(g_settings->getBool("server_announce"))
3539 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3547 if (profiler_print_interval != 0) {
3548 if(m_profiler_interval.step(steplen, profiler_print_interval))
3550 infostream<<"Profiler:"<<std::endl;
3551 g_profiler->print(infostream);
3552 g_profiler->clear();