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_server.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_sao.h"
52 #include "event_manager.h"
53 #include "serverlist.h"
54 #include "util/string.h"
56 #include "util/serialize.h"
57 #include "util/thread.h"
58 #include "defaultsettings.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
64 class ClientNotFoundException : public BaseException
67 ClientNotFoundException(const char *s):
72 class ServerThread : public Thread
76 ServerThread(Server *server):
87 void *ServerThread::run()
89 DSTACK(FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
92 m_server->AsyncRunStep(true);
94 while (!stopRequested()) {
96 //TimeTaker timer("AsyncRunStep() + Receive()");
98 m_server->AsyncRunStep();
102 } catch (con::NoIncomingDataException &e) {
103 } catch (con::PeerNotFoundException &e) {
104 infostream<<"Server: PeerNotFoundException"<<std::endl;
105 } catch (ClientNotFoundException &e) {
106 } catch (con::ConnectionBindFailed &e) {
107 m_server->setAsyncFatalError(e.what());
108 } catch (LuaError &e) {
109 m_server->setAsyncFatalError(
110 "ServerThread::run Lua: " + std::string(e.what()));
114 END_DEBUG_EXCEPTION_HANDLER
119 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
121 if(pos_exists) *pos_exists = false;
126 if(pos_exists) *pos_exists = true;
131 ServerActiveObject *sao = env->getActiveObject(object);
134 if(pos_exists) *pos_exists = true;
135 return sao->getBasePosition(); }
147 const std::string &path_world,
148 const SubgameSpec &gamespec,
149 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_dedicated(dedicated),
158 m_async_fatal_error(""),
164 m_itemdef(createItemDefManager()),
165 m_nodedef(createNodeDefManager()),
166 m_craftdef(createCraftDefManager()),
167 m_event(new EventManager()),
172 m_lag = g_settings->getFloat("dedicated_server_step");
175 throw ServerError("Supplied empty world path");
177 if(!gamespec.isValid())
178 throw ServerError("Supplied invalid gamespec");
180 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
181 if(m_simple_singleplayer_mode)
182 infostream<<" in simple singleplayer mode"<<std::endl;
184 infostream<<std::endl;
185 infostream<<"- world: "<<m_path_world<<std::endl;
186 infostream<<"- game: "<<m_gamespec.path<<std::endl;
188 // Create world if it doesn't exist
189 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
190 throw ServerError("Failed to initialize world");
192 // Create server thread
193 m_thread = new ServerThread(this);
195 // Create emerge manager
196 m_emerge = new EmergeManager(this);
198 // Create ban manager
199 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
200 m_banmanager = new BanManager(ban_path);
202 ServerModConfiguration modconf(m_path_world);
203 m_mods = modconf.getMods();
204 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
205 // complain about mods with unsatisfied dependencies
206 if (!modconf.isConsistent()) {
207 modconf.printUnsatisfiedModsError();
211 MutexAutoLock envlock(m_env_mutex);
213 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
214 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
216 // Initialize scripting
217 infostream<<"Server: Initializing Lua"<<std::endl;
219 m_script = new ServerScripting(this);
221 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
224 infostream << "Server: Loading mods: ";
225 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
226 i != m_mods.end(); ++i) {
227 infostream << (*i).name << " ";
229 infostream << std::endl;
230 // Load and run "mod" scripts
231 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
232 it != m_mods.end(); ++it) {
233 const ModSpec &mod = *it;
234 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
235 throw ModError("Error loading mod \"" + mod.name +
236 "\": Mod name does not follow naming conventions: "
237 "Only characters [a-z0-9_] are allowed.");
239 std::string script_path = mod.path + DIR_DELIM + "init.lua";
240 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
241 << script_path << "\"]" << std::endl;
242 m_script->loadMod(script_path, mod.name);
245 // Read Textures and calculate sha1 sums
248 // Apply item aliases in the node definition manager
249 m_nodedef->updateAliases(m_itemdef);
251 // Apply texture overrides from texturepack/override.txt
252 std::string texture_path = g_settings->get("texture_path");
253 if (texture_path != "" && fs::IsDir(texture_path))
254 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
256 m_nodedef->setNodeRegistrationStatus(true);
258 // Perform pending node name resolutions
259 m_nodedef->runNodeResolveCallbacks();
261 // unmap node names for connected nodeboxes
262 m_nodedef->mapNodeboxConnections();
264 // init the recipe hashes to speed up crafting
265 m_craftdef->initHashes(this);
267 // Initialize Environment
268 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
270 m_clients.setEnv(m_env);
272 if (!servermap->settings_mgr.makeMapgenParams())
273 FATAL_ERROR("Couldn't create any mapgen type");
275 // Initialize mapgens
276 m_emerge->initMapgens(servermap->getMapgenParams());
278 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
279 if (m_enable_rollback_recording) {
280 // Create rollback manager
281 m_rollback = new RollbackManager(m_path_world, this);
284 // Give environment reference to scripting api
285 m_script->initializeEnvironment(m_env);
287 // Register us to receive map edit events
288 servermap->addEventReceiver(this);
290 // If file exists, load environment metadata
291 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
292 infostream << "Server: Loading environment metadata" << std::endl;
295 m_env->loadDefaultMeta();
298 m_liquid_transform_every = g_settings->getFloat("liquid_update");
299 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
304 infostream<<"Server destructing"<<std::endl;
306 // Send shutdown message
307 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
310 MutexAutoLock envlock(m_env_mutex);
312 // Execute script shutdown hooks
313 m_script->on_shutdown();
315 infostream << "Server: Saving players" << std::endl;
316 m_env->saveLoadedPlayers();
318 infostream << "Server: Kicking players" << std::endl;
319 std::string kick_msg;
320 bool reconnect = false;
321 if (getShutdownRequested()) {
322 reconnect = m_shutdown_ask_reconnect;
323 kick_msg = m_shutdown_msg;
325 if (kick_msg == "") {
326 kick_msg = g_settings->get("kick_msg_shutdown");
328 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
329 kick_msg, reconnect);
331 infostream << "Server: Saving environment metadata" << std::endl;
339 // stop all emerge threads before deleting players that may have
340 // requested blocks to be emerged
341 m_emerge->stopThreads();
343 // Delete things in the reverse order of creation
353 // Deinitialize scripting
354 infostream<<"Server: Deinitializing scripting"<<std::endl;
357 // Delete detached inventories
358 for (std::map<std::string, Inventory*>::iterator
359 i = m_detached_inventories.begin();
360 i != m_detached_inventories.end(); ++i) {
365 void Server::start(Address bind_addr)
367 DSTACK(FUNCTION_NAME);
369 m_bind_addr = bind_addr;
371 infostream<<"Starting server on "
372 << bind_addr.serializeString() <<"..."<<std::endl;
374 // Stop thread if already running
377 // Initialize connection
378 m_con.SetTimeoutMs(30);
379 m_con.Serve(bind_addr);
384 // ASCII art for the win!
386 <<" .__ __ __ "<<std::endl
387 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
388 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
389 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
390 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
391 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
392 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
393 actionstream<<"Server for gameid=\""<<m_gamespec.id
394 <<"\" listening on "<<bind_addr.serializeString()<<":"
395 <<bind_addr.getPort() << "."<<std::endl;
400 DSTACK(FUNCTION_NAME);
402 infostream<<"Server: Stopping and waiting threads"<<std::endl;
404 // Stop threads (set run=false first so both start stopping)
406 //m_emergethread.setRun(false);
408 //m_emergethread.stop();
410 infostream<<"Server: Threads stopped"<<std::endl;
413 void Server::step(float dtime)
415 DSTACK(FUNCTION_NAME);
420 MutexAutoLock lock(m_step_dtime_mutex);
421 m_step_dtime += dtime;
423 // Throw if fatal error occurred in thread
424 std::string async_err = m_async_fatal_error.get();
425 if (!async_err.empty()) {
426 if (!m_simple_singleplayer_mode) {
427 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
428 g_settings->get("kick_msg_crash"),
429 g_settings->getBool("ask_reconnect_on_crash"));
431 throw ServerError("AsyncErr: " + async_err);
435 void Server::AsyncRunStep(bool initial_step)
437 DSTACK(FUNCTION_NAME);
439 g_profiler->add("Server::AsyncRunStep (num)", 1);
443 MutexAutoLock lock1(m_step_dtime_mutex);
444 dtime = m_step_dtime;
448 // Send blocks to clients
452 if((dtime < 0.001) && (initial_step == false))
455 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
457 //infostream<<"Server steps "<<dtime<<std::endl;
458 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
461 MutexAutoLock lock1(m_step_dtime_mutex);
462 m_step_dtime -= dtime;
469 m_uptime.set(m_uptime.get() + dtime);
475 Update time of day and overall game time
477 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
480 Send to clients at constant intervals
483 m_time_of_day_send_timer -= dtime;
484 if(m_time_of_day_send_timer < 0.0) {
485 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
486 u16 time = m_env->getTimeOfDay();
487 float time_speed = g_settings->getFloat("time_speed");
488 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
492 MutexAutoLock lock(m_env_mutex);
493 // Figure out and report maximum lag to environment
494 float max_lag = m_env->getMaxLagEstimate();
495 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
497 if(dtime > 0.1 && dtime > max_lag * 2.0)
498 infostream<<"Server: Maximum lag peaked to "<<dtime
502 m_env->reportMaxLagEstimate(max_lag);
504 ScopeProfiler sp(g_profiler, "SEnv step");
505 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
509 static const float map_timer_and_unload_dtime = 2.92;
510 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
512 MutexAutoLock lock(m_env_mutex);
513 // Run Map's timers and unload unused data
514 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
515 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
516 g_settings->getFloat("server_unload_unused_data_timeout"),
521 Listen to the admin chat, if available
524 if (!m_admin_chat->command_queue.empty()) {
525 MutexAutoLock lock(m_env_mutex);
526 while (!m_admin_chat->command_queue.empty()) {
527 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
528 handleChatInterfaceEvent(evt);
532 m_admin_chat->outgoing_queue.push_back(
533 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
540 /* Transform liquids */
541 m_liquid_transform_timer += dtime;
542 if(m_liquid_transform_timer >= m_liquid_transform_every)
544 m_liquid_transform_timer -= m_liquid_transform_every;
546 MutexAutoLock lock(m_env_mutex);
548 ScopeProfiler sp(g_profiler, "Server: liquid transform");
550 std::map<v3s16, MapBlock*> modified_blocks;
551 m_env->getMap().transformLiquids(modified_blocks, m_env);
556 core::map<v3s16, MapBlock*> lighting_modified_blocks;
557 ServerMap &map = ((ServerMap&)m_env->getMap());
558 map.updateLighting(modified_blocks, lighting_modified_blocks);
560 // Add blocks modified by lighting to modified_blocks
561 for(core::map<v3s16, MapBlock*>::Iterator
562 i = lighting_modified_blocks.getIterator();
563 i.atEnd() == false; i++)
565 MapBlock *block = i.getNode()->getValue();
566 modified_blocks.insert(block->getPos(), block);
570 Set the modified blocks unsent for all the clients
572 if(!modified_blocks.empty())
574 SetBlocksNotSent(modified_blocks);
577 m_clients.step(dtime);
579 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
581 // send masterserver announce
583 float &counter = m_masterserver_timer;
584 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
585 g_settings->getBool("server_announce")) {
586 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
587 ServerList::AA_START,
588 m_bind_addr.getPort(),
589 m_clients.getPlayerNames(),
591 m_env->getGameTime(),
594 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
604 Check added and deleted active objects
607 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
608 MutexAutoLock envlock(m_env_mutex);
611 RemoteClientMap clients = m_clients.getClientList();
612 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
614 // Radius inside which objects are active
615 static thread_local const s16 radius =
616 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
618 // Radius inside which players are active
619 static thread_local const bool is_transfer_limited =
620 g_settings->exists("unlimited_player_transfer_distance") &&
621 !g_settings->getBool("unlimited_player_transfer_distance");
622 static thread_local const s16 player_transfer_dist =
623 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
624 s16 player_radius = player_transfer_dist;
625 if (player_radius == 0 && is_transfer_limited)
626 player_radius = radius;
628 for (RemoteClientMap::iterator i = clients.begin();
629 i != clients.end(); ++i) {
630 RemoteClient *client = i->second;
632 // If definitions and textures have not been sent, don't
633 // send objects either
634 if (client->getState() < CS_DefinitionsSent)
637 RemotePlayer *player = m_env->getPlayer(client->peer_id);
638 if (player == NULL) {
639 // This can happen if the client timeouts somehow
640 /*warningstream<<FUNCTION_NAME<<": Client "
642 <<" has no associated player"<<std::endl;*/
646 PlayerSAO *playersao = player->getPlayerSAO();
647 if (playersao == NULL)
650 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
651 if (my_radius <= 0) my_radius = radius;
652 //infostream << "Server: Active Radius " << my_radius << std::endl;
654 std::queue<u16> removed_objects;
655 std::queue<u16> added_objects;
656 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
657 client->m_known_objects, removed_objects);
658 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
659 client->m_known_objects, added_objects);
661 // Ignore if nothing happened
662 if (removed_objects.empty() && added_objects.empty()) {
666 std::string data_buffer;
670 // Handle removed objects
671 writeU16((u8*)buf, removed_objects.size());
672 data_buffer.append(buf, 2);
673 while (!removed_objects.empty()) {
675 u16 id = removed_objects.front();
676 ServerActiveObject* obj = m_env->getActiveObject(id);
678 // Add to data buffer for sending
679 writeU16((u8*)buf, id);
680 data_buffer.append(buf, 2);
682 // Remove from known objects
683 client->m_known_objects.erase(id);
685 if(obj && obj->m_known_by_count > 0)
686 obj->m_known_by_count--;
687 removed_objects.pop();
690 // Handle added objects
691 writeU16((u8*)buf, added_objects.size());
692 data_buffer.append(buf, 2);
693 while (!added_objects.empty()) {
695 u16 id = added_objects.front();
696 ServerActiveObject* obj = m_env->getActiveObject(id);
699 u8 type = ACTIVEOBJECT_TYPE_INVALID;
701 warningstream<<FUNCTION_NAME
702 <<": NULL object"<<std::endl;
704 type = obj->getSendType();
706 // Add to data buffer for sending
707 writeU16((u8*)buf, id);
708 data_buffer.append(buf, 2);
709 writeU8((u8*)buf, type);
710 data_buffer.append(buf, 1);
713 data_buffer.append(serializeLongString(
714 obj->getClientInitializationData(client->net_proto_version)));
716 data_buffer.append(serializeLongString(""));
718 // Add to known objects
719 client->m_known_objects.insert(id);
722 obj->m_known_by_count++;
727 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
728 verbosestream << "Server: Sent object remove/add: "
729 << removed_objects.size() << " removed, "
730 << added_objects.size() << " added, "
731 << "packet size is " << pktSize << std::endl;
735 m_mod_storage_save_timer -= dtime;
736 if (m_mod_storage_save_timer <= 0.0f) {
737 infostream << "Saving registered mod storages." << std::endl;
738 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
739 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
740 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
741 if (it->second->isModified()) {
742 it->second->save(getModStoragePath());
752 MutexAutoLock envlock(m_env_mutex);
753 ScopeProfiler sp(g_profiler, "Server: sending object messages");
756 // Value = data sent by object
757 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
759 // Get active object messages from environment
761 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
765 std::vector<ActiveObjectMessage>* message_list = NULL;
766 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
767 n = buffered_messages.find(aom.id);
768 if (n == buffered_messages.end()) {
769 message_list = new std::vector<ActiveObjectMessage>;
770 buffered_messages[aom.id] = message_list;
773 message_list = n->second;
775 message_list->push_back(aom);
779 RemoteClientMap clients = m_clients.getClientList();
780 // Route data to every client
781 for (std::unordered_map<u16, RemoteClient*>::iterator i = clients.begin();
782 i != clients.end(); ++i) {
783 RemoteClient *client = i->second;
784 std::string reliable_data;
785 std::string unreliable_data;
786 // Go through all objects in message buffer
787 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
788 j = buffered_messages.begin();
789 j != buffered_messages.end(); ++j) {
790 // If object is not known by client, skip it
792 if (client->m_known_objects.find(id) == client->m_known_objects.end())
795 // Get message list of object
796 std::vector<ActiveObjectMessage>* list = j->second;
797 // Go through every message
798 for (std::vector<ActiveObjectMessage>::iterator
799 k = list->begin(); k != list->end(); ++k) {
800 // Compose the full new data with header
801 ActiveObjectMessage aom = *k;
802 std::string new_data;
805 writeU16((u8*)&buf[0], aom.id);
806 new_data.append(buf, 2);
808 new_data += serializeString(aom.datastring);
809 // Add data to buffer
811 reliable_data += new_data;
813 unreliable_data += new_data;
817 reliable_data and unreliable_data are now ready.
820 if(reliable_data.size() > 0) {
821 SendActiveObjectMessages(client->peer_id, reliable_data);
824 if(unreliable_data.size() > 0) {
825 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
830 // Clear buffered_messages
831 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
832 i = buffered_messages.begin();
833 i != buffered_messages.end(); ++i) {
839 Send queued-for-sending map edit events.
842 // We will be accessing the environment
843 MutexAutoLock lock(m_env_mutex);
845 // Don't send too many at a time
848 // Single change sending is disabled if queue size is not small
849 bool disable_single_change_sending = false;
850 if(m_unsent_map_edit_queue.size() >= 4)
851 disable_single_change_sending = true;
853 int event_count = m_unsent_map_edit_queue.size();
855 // We'll log the amount of each
858 while(m_unsent_map_edit_queue.size() != 0)
860 MapEditEvent* event = m_unsent_map_edit_queue.front();
861 m_unsent_map_edit_queue.pop();
863 // Players far away from the change are stored here.
864 // Instead of sending the changes, MapBlocks are set not sent
866 std::vector<u16> far_players;
868 switch (event->type) {
871 prof.add("MEET_ADDNODE", 1);
872 sendAddNode(event->p, event->n, event->already_known_by_peer,
873 &far_players, disable_single_change_sending ? 5 : 30,
874 event->type == MEET_ADDNODE);
876 case MEET_REMOVENODE:
877 prof.add("MEET_REMOVENODE", 1);
878 sendRemoveNode(event->p, event->already_known_by_peer,
879 &far_players, disable_single_change_sending ? 5 : 30);
881 case MEET_BLOCK_NODE_METADATA_CHANGED:
882 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
883 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
884 setBlockNotSent(event->p);
887 infostream << "Server: MEET_OTHER" << std::endl;
888 prof.add("MEET_OTHER", 1);
889 for(std::set<v3s16>::iterator
890 i = event->modified_blocks.begin();
891 i != event->modified_blocks.end(); ++i) {
896 prof.add("unknown", 1);
897 warningstream << "Server: Unknown MapEditEvent "
898 << ((u32)event->type) << std::endl;
903 Set blocks not sent to far players
905 if(!far_players.empty()) {
906 // Convert list format to that wanted by SetBlocksNotSent
907 std::map<v3s16, MapBlock*> modified_blocks2;
908 for(std::set<v3s16>::iterator
909 i = event->modified_blocks.begin();
910 i != event->modified_blocks.end(); ++i) {
911 modified_blocks2[*i] =
912 m_env->getMap().getBlockNoCreateNoEx(*i);
915 // Set blocks not sent
916 for(std::vector<u16>::iterator
917 i = far_players.begin();
918 i != far_players.end(); ++i) {
919 if(RemoteClient *client = getClient(*i))
920 client->SetBlocksNotSent(modified_blocks2);
926 /*// Don't send too many at a time
928 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
932 if(event_count >= 5){
933 infostream<<"Server: MapEditEvents:"<<std::endl;
934 prof.print(infostream);
935 } else if(event_count != 0){
936 verbosestream<<"Server: MapEditEvents:"<<std::endl;
937 prof.print(verbosestream);
943 Trigger emergethread (it somehow gets to a non-triggered but
944 bysy state sometimes)
947 float &counter = m_emergethread_trigger_timer;
949 if (counter >= 2.0) {
952 m_emerge->startThreads();
956 // Save map, players and auth stuff
958 float &counter = m_savemap_timer;
960 static thread_local const float save_interval =
961 g_settings->getFloat("server_map_save_interval");
962 if (counter >= save_interval) {
964 MutexAutoLock lock(m_env_mutex);
966 ScopeProfiler sp(g_profiler, "Server: saving stuff");
969 if (m_banmanager->isModified()) {
970 m_banmanager->save();
973 // Save changed parts of map
974 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
977 m_env->saveLoadedPlayers();
979 // Save environment metadata
985 static const float shutdown_msg_times[] =
987 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
990 if (m_shutdown_timer > 0.0f) {
991 // Automated messages
992 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
993 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
994 // If shutdown timer matches an automessage, shot it
995 if (m_shutdown_timer > shutdown_msg_times[i] &&
996 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
997 std::wstringstream ws;
999 ws << L"*** Server shutting down in "
1000 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1003 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1004 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1010 m_shutdown_timer -= dtime;
1011 if (m_shutdown_timer < 0.0f) {
1012 m_shutdown_timer = 0.0f;
1013 m_shutdown_requested = true;
1018 void Server::Receive()
1020 DSTACK(FUNCTION_NAME);
1021 SharedBuffer<u8> data;
1025 m_con.Receive(&pkt);
1026 peer_id = pkt.getPeerId();
1029 catch(con::InvalidIncomingDataException &e) {
1030 infostream<<"Server::Receive(): "
1031 "InvalidIncomingDataException: what()="
1032 <<e.what()<<std::endl;
1034 catch(SerializationError &e) {
1035 infostream<<"Server::Receive(): "
1036 "SerializationError: what()="
1037 <<e.what()<<std::endl;
1039 catch(ClientStateError &e) {
1040 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1041 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1042 L"Try reconnecting or updating your client");
1044 catch(con::PeerNotFoundException &e) {
1049 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1051 std::string playername = "";
1052 PlayerSAO *playersao = NULL;
1055 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1056 if (client != NULL) {
1057 playername = client->getName();
1058 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1060 } catch (std::exception &e) {
1066 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1068 // If failed, cancel
1069 if ((playersao == NULL) || (player == NULL)) {
1070 if (player && player->peer_id != 0) {
1071 actionstream << "Server: Failed to emerge player \"" << playername
1072 << "\" (player allocated to an another client)" << std::endl;
1073 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1074 L"name. If your client closed unexpectedly, try again in "
1077 errorstream << "Server: " << playername << ": Failed to emerge player"
1079 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1085 Send complete position information
1087 SendMovePlayer(peer_id);
1090 SendPlayerPrivileges(peer_id);
1092 // Send inventory formspec
1093 SendPlayerInventoryFormspec(peer_id);
1096 SendInventory(playersao);
1098 // Send HP or death screen
1099 if (playersao->isDead())
1100 SendDeathscreen(peer_id, false, v3f(0,0,0));
1102 SendPlayerHPOrDie(playersao);
1105 SendPlayerBreath(playersao);
1107 // Note things in chat if not in simple singleplayer mode
1108 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1109 // Send information about server to player in chat
1110 SendChatMessage(peer_id, getStatusString());
1112 Address addr = getPeerAddress(player->peer_id);
1113 std::string ip_str = addr.serializeString();
1114 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1119 const std::vector<std::string> &names = m_clients.getPlayerNames();
1121 actionstream << player->getName() << " joins game. List of players: ";
1123 for (std::vector<std::string>::const_iterator i = names.begin();
1124 i != names.end(); ++i) {
1125 actionstream << *i << " ";
1128 actionstream << player->getName() <<std::endl;
1133 inline void Server::handleCommand(NetworkPacket* pkt)
1135 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1136 (this->*opHandle.handler)(pkt);
1139 void Server::ProcessData(NetworkPacket *pkt)
1141 DSTACK(FUNCTION_NAME);
1142 // Environment is locked first.
1143 MutexAutoLock envlock(m_env_mutex);
1145 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1146 u32 peer_id = pkt->getPeerId();
1149 Address address = getPeerAddress(peer_id);
1150 std::string addr_s = address.serializeString();
1152 if(m_banmanager->isIpBanned(addr_s)) {
1153 std::string ban_name = m_banmanager->getBanName(addr_s);
1154 infostream << "Server: A banned client tried to connect from "
1155 << addr_s << "; banned name was "
1156 << ban_name << std::endl;
1157 // This actually doesn't seem to transfer to the client
1158 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1159 + utf8_to_wide(ban_name));
1163 catch(con::PeerNotFoundException &e) {
1165 * no peer for this packet found
1166 * most common reason is peer timeout, e.g. peer didn't
1167 * respond for some time, your server was overloaded or
1170 infostream << "Server::ProcessData(): Canceling: peer "
1171 << peer_id << " not found" << std::endl;
1176 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1178 // Command must be handled into ToServerCommandHandler
1179 if (command >= TOSERVER_NUM_MSG_TYPES) {
1180 infostream << "Server: Ignoring unknown command "
1181 << command << std::endl;
1185 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1190 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1192 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1193 errorstream << "Server::ProcessData(): Cancelling: Peer"
1194 " serialization format invalid or not initialized."
1195 " Skipping incoming command=" << command << std::endl;
1199 /* Handle commands related to client startup */
1200 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1205 if (m_clients.getClientState(peer_id) < CS_Active) {
1206 if (command == TOSERVER_PLAYERPOS) return;
1208 errorstream << "Got packet command: " << command << " for peer id "
1209 << peer_id << " but client isn't active yet. Dropping packet "
1215 } catch (SendFailedException &e) {
1216 errorstream << "Server::ProcessData(): SendFailedException: "
1217 << "what=" << e.what()
1219 } catch (PacketError &e) {
1220 actionstream << "Server::ProcessData(): PacketError: "
1221 << "what=" << e.what()
1226 void Server::setTimeOfDay(u32 time)
1228 m_env->setTimeOfDay(time);
1229 m_time_of_day_send_timer = 0;
1232 void Server::onMapEditEvent(MapEditEvent *event)
1234 if(m_ignore_map_edit_events)
1236 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1238 MapEditEvent *e = event->clone();
1239 m_unsent_map_edit_queue.push(e);
1242 Inventory* Server::getInventory(const InventoryLocation &loc)
1245 case InventoryLocation::UNDEFINED:
1246 case InventoryLocation::CURRENT_PLAYER:
1248 case InventoryLocation::PLAYER:
1250 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1253 PlayerSAO *playersao = player->getPlayerSAO();
1256 return playersao->getInventory();
1259 case InventoryLocation::NODEMETA:
1261 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1264 return meta->getInventory();
1267 case InventoryLocation::DETACHED:
1269 if(m_detached_inventories.count(loc.name) == 0)
1271 return m_detached_inventories[loc.name];
1275 sanity_check(false); // abort
1280 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1283 case InventoryLocation::UNDEFINED:
1285 case InventoryLocation::PLAYER:
1290 RemotePlayer *player =
1291 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1296 PlayerSAO *playersao = player->getPlayerSAO();
1300 SendInventory(playersao);
1303 case InventoryLocation::NODEMETA:
1305 v3s16 blockpos = getNodeBlockPos(loc.p);
1307 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1309 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1311 setBlockNotSent(blockpos);
1314 case InventoryLocation::DETACHED:
1316 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1320 sanity_check(false); // abort
1325 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1327 std::vector<u16> clients = m_clients.getClientIDs();
1329 // Set the modified blocks unsent for all the clients
1330 for (std::vector<u16>::iterator i = clients.begin();
1331 i != clients.end(); ++i) {
1332 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1333 client->SetBlocksNotSent(block);
1338 void Server::peerAdded(con::Peer *peer)
1340 DSTACK(FUNCTION_NAME);
1341 verbosestream<<"Server::peerAdded(): peer->id="
1342 <<peer->id<<std::endl;
1345 c.type = con::PEER_ADDED;
1346 c.peer_id = peer->id;
1348 m_peer_change_queue.push(c);
1351 void Server::deletingPeer(con::Peer *peer, bool timeout)
1353 DSTACK(FUNCTION_NAME);
1354 verbosestream<<"Server::deletingPeer(): peer->id="
1355 <<peer->id<<", timeout="<<timeout<<std::endl;
1357 m_clients.event(peer->id, CSE_Disconnect);
1359 c.type = con::PEER_REMOVED;
1360 c.peer_id = peer->id;
1361 c.timeout = timeout;
1362 m_peer_change_queue.push(c);
1365 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1367 *retval = m_con.getPeerStat(peer_id,type);
1368 if (*retval == -1) return false;
1372 bool Server::getClientInfo(
1381 std::string* vers_string
1384 *state = m_clients.getClientState(peer_id);
1386 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1388 if (client == NULL) {
1393 *uptime = client->uptime();
1394 *ser_vers = client->serialization_version;
1395 *prot_vers = client->net_proto_version;
1397 *major = client->getMajor();
1398 *minor = client->getMinor();
1399 *patch = client->getPatch();
1400 *vers_string = client->getPatch();
1407 void Server::handlePeerChanges()
1409 while(m_peer_change_queue.size() > 0)
1411 con::PeerChange c = m_peer_change_queue.front();
1412 m_peer_change_queue.pop();
1414 verbosestream<<"Server: Handling peer change: "
1415 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1420 case con::PEER_ADDED:
1421 m_clients.CreateClient(c.peer_id);
1424 case con::PEER_REMOVED:
1425 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1429 FATAL_ERROR("Invalid peer change event received!");
1435 void Server::printToConsoleOnly(const std::string &text)
1438 m_admin_chat->outgoing_queue.push_back(
1439 new ChatEventChat("", utf8_to_wide(text)));
1441 std::cout << text << std::endl;
1445 void Server::Send(NetworkPacket* pkt)
1447 m_clients.send(pkt->getPeerId(),
1448 clientCommandFactoryTable[pkt->getCommand()].channel,
1450 clientCommandFactoryTable[pkt->getCommand()].reliable);
1453 void Server::SendMovement(u16 peer_id)
1455 DSTACK(FUNCTION_NAME);
1456 std::ostringstream os(std::ios_base::binary);
1458 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1460 pkt << g_settings->getFloat("movement_acceleration_default");
1461 pkt << g_settings->getFloat("movement_acceleration_air");
1462 pkt << g_settings->getFloat("movement_acceleration_fast");
1463 pkt << g_settings->getFloat("movement_speed_walk");
1464 pkt << g_settings->getFloat("movement_speed_crouch");
1465 pkt << g_settings->getFloat("movement_speed_fast");
1466 pkt << g_settings->getFloat("movement_speed_climb");
1467 pkt << g_settings->getFloat("movement_speed_jump");
1468 pkt << g_settings->getFloat("movement_liquid_fluidity");
1469 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1470 pkt << g_settings->getFloat("movement_liquid_sink");
1471 pkt << g_settings->getFloat("movement_gravity");
1476 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1478 if (!g_settings->getBool("enable_damage"))
1481 u16 peer_id = playersao->getPeerID();
1482 bool is_alive = playersao->getHP() > 0;
1485 SendPlayerHP(peer_id);
1490 void Server::SendHP(u16 peer_id, u8 hp)
1492 DSTACK(FUNCTION_NAME);
1494 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1499 void Server::SendBreath(u16 peer_id, u16 breath)
1501 DSTACK(FUNCTION_NAME);
1503 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1504 pkt << (u16) breath;
1508 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1509 const std::string &custom_reason, bool reconnect)
1511 assert(reason < SERVER_ACCESSDENIED_MAX);
1513 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1515 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1516 pkt << custom_reason;
1517 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1518 reason == SERVER_ACCESSDENIED_CRASH)
1519 pkt << custom_reason << (u8)reconnect;
1523 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1525 DSTACK(FUNCTION_NAME);
1527 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1532 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1533 v3f camera_point_target)
1535 DSTACK(FUNCTION_NAME);
1537 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1538 pkt << set_camera_point_target << camera_point_target;
1542 void Server::SendItemDef(u16 peer_id,
1543 IItemDefManager *itemdef, u16 protocol_version)
1545 DSTACK(FUNCTION_NAME);
1547 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1551 u32 length of the next item
1552 zlib-compressed serialized ItemDefManager
1554 std::ostringstream tmp_os(std::ios::binary);
1555 itemdef->serialize(tmp_os, protocol_version);
1556 std::ostringstream tmp_os2(std::ios::binary);
1557 compressZlib(tmp_os.str(), tmp_os2);
1558 pkt.putLongString(tmp_os2.str());
1561 verbosestream << "Server: Sending item definitions to id(" << peer_id
1562 << "): size=" << pkt.getSize() << std::endl;
1567 void Server::SendNodeDef(u16 peer_id,
1568 INodeDefManager *nodedef, u16 protocol_version)
1570 DSTACK(FUNCTION_NAME);
1572 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1576 u32 length of the next item
1577 zlib-compressed serialized NodeDefManager
1579 std::ostringstream tmp_os(std::ios::binary);
1580 nodedef->serialize(tmp_os, protocol_version);
1581 std::ostringstream tmp_os2(std::ios::binary);
1582 compressZlib(tmp_os.str(), tmp_os2);
1584 pkt.putLongString(tmp_os2.str());
1587 verbosestream << "Server: Sending node definitions to id(" << peer_id
1588 << "): size=" << pkt.getSize() << std::endl;
1594 Non-static send methods
1597 void Server::SendInventory(PlayerSAO* playerSAO)
1599 DSTACK(FUNCTION_NAME);
1601 UpdateCrafting(playerSAO->getPlayer());
1607 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1609 std::ostringstream os;
1610 playerSAO->getInventory()->serialize(os);
1612 std::string s = os.str();
1614 pkt.putRawString(s.c_str(), s.size());
1618 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1620 DSTACK(FUNCTION_NAME);
1621 if (peer_id != PEER_ID_INEXISTENT) {
1622 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1624 if (m_clients.getProtocolVersion(peer_id) < 27)
1625 pkt << unescape_enriched(message);
1631 for (u16 id : m_clients.getClientIDs())
1632 SendChatMessage(id, message);
1636 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1637 const std::string &formname)
1639 DSTACK(FUNCTION_NAME);
1641 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1642 if (formspec == "" ){
1643 //the client should close the formspec
1644 pkt.putLongString("");
1646 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1653 // Spawns a particle on peer with peer_id
1654 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1655 v3f pos, v3f velocity, v3f acceleration,
1656 float expirationtime, float size, bool collisiondetection,
1657 bool collision_removal,
1658 bool vertical, const std::string &texture,
1659 const struct TileAnimationParams &animation, u8 glow)
1661 DSTACK(FUNCTION_NAME);
1662 static thread_local const float radius =
1663 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1665 if (peer_id == PEER_ID_INEXISTENT) {
1666 std::vector<u16> clients = m_clients.getClientIDs();
1668 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1669 RemotePlayer *player = m_env->getPlayer(*i);
1673 PlayerSAO *sao = player->getPlayerSAO();
1677 // Do not send to distant clients
1678 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1681 SendSpawnParticle(*i, player->protocol_version,
1682 pos, velocity, acceleration,
1683 expirationtime, size, collisiondetection,
1684 collision_removal, vertical, texture, animation, glow);
1689 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1691 pkt << pos << velocity << acceleration << expirationtime
1692 << size << collisiondetection;
1693 pkt.putLongString(texture);
1695 pkt << collision_removal;
1696 // This is horrible but required (why are there two ways to serialize pkts?)
1697 std::ostringstream os(std::ios_base::binary);
1698 animation.serialize(os, protocol_version);
1699 pkt.putRawString(os.str());
1705 // Adds a ParticleSpawner on peer with peer_id
1706 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1707 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1708 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1709 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1710 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1711 const struct TileAnimationParams &animation, u8 glow)
1713 DSTACK(FUNCTION_NAME);
1714 if (peer_id == PEER_ID_INEXISTENT) {
1715 // This sucks and should be replaced:
1716 std::vector<u16> clients = m_clients.getClientIDs();
1717 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1718 RemotePlayer *player = m_env->getPlayer(*i);
1721 SendAddParticleSpawner(*i, player->protocol_version,
1722 amount, spawntime, minpos, maxpos,
1723 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1724 minsize, maxsize, collisiondetection, collision_removal,
1725 attached_id, vertical, texture, id, animation, glow);
1730 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1732 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1733 << minacc << maxacc << minexptime << maxexptime << minsize
1734 << maxsize << collisiondetection;
1736 pkt.putLongString(texture);
1738 pkt << id << vertical;
1739 pkt << collision_removal;
1741 // This is horrible but required
1742 std::ostringstream os(std::ios_base::binary);
1743 animation.serialize(os, protocol_version);
1744 pkt.putRawString(os.str());
1750 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1752 DSTACK(FUNCTION_NAME);
1754 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1756 // Ugly error in this packet
1759 if (peer_id != PEER_ID_INEXISTENT) {
1763 m_clients.sendToAll(&pkt);
1768 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1770 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1772 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1773 << form->text << form->number << form->item << form->dir
1774 << form->align << form->offset << form->world_pos << form->size;
1779 void Server::SendHUDRemove(u16 peer_id, u32 id)
1781 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1786 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1788 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1789 pkt << id << (u8) stat;
1793 case HUD_STAT_SCALE:
1794 case HUD_STAT_ALIGN:
1795 case HUD_STAT_OFFSET:
1796 pkt << *(v2f *) value;
1800 pkt << *(std::string *) value;
1802 case HUD_STAT_WORLD_POS:
1803 pkt << *(v3f *) value;
1806 pkt << *(v2s32 *) value;
1808 case HUD_STAT_NUMBER:
1812 pkt << *(u32 *) value;
1819 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1821 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1823 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1825 pkt << flags << mask;
1830 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1832 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1833 pkt << param << value;
1837 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1838 const std::string &type, const std::vector<std::string> ¶ms,
1841 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1842 pkt << bgcolor << type << (u16) params.size();
1844 for(size_t i=0; i<params.size(); i++)
1852 void Server::SendCloudParams(u16 peer_id, float density,
1853 const video::SColor &color_bright,
1854 const video::SColor &color_ambient,
1859 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1860 pkt << density << color_bright << color_ambient
1861 << height << thickness << speed;
1866 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1869 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1872 pkt << do_override << (u16) (ratio * 65535);
1877 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1879 DSTACK(FUNCTION_NAME);
1881 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1882 pkt << time << time_speed;
1884 if (peer_id == PEER_ID_INEXISTENT) {
1885 m_clients.sendToAll(&pkt);
1892 void Server::SendPlayerHP(u16 peer_id)
1894 DSTACK(FUNCTION_NAME);
1895 PlayerSAO *playersao = getPlayerSAO(peer_id);
1896 // In some rare case if the player is disconnected
1897 // while Lua call l_punch, for example, this can be NULL
1901 SendHP(peer_id, playersao->getHP());
1902 m_script->player_event(playersao,"health_changed");
1904 // Send to other clients
1905 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1906 ActiveObjectMessage aom(playersao->getId(), true, str);
1907 playersao->m_messages_out.push(aom);
1910 void Server::SendPlayerBreath(PlayerSAO *sao)
1912 DSTACK(FUNCTION_NAME);
1915 m_script->player_event(sao, "breath_changed");
1916 SendBreath(sao->getPeerID(), sao->getBreath());
1919 void Server::SendMovePlayer(u16 peer_id)
1921 DSTACK(FUNCTION_NAME);
1922 RemotePlayer *player = m_env->getPlayer(peer_id);
1924 PlayerSAO *sao = player->getPlayerSAO();
1927 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1928 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1931 v3f pos = sao->getBasePosition();
1932 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1933 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1934 << " pitch=" << sao->getPitch()
1935 << " yaw=" << sao->getYaw()
1942 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1944 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1947 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1948 << animation_frames[3] << animation_speed;
1953 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1955 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1956 pkt << first << third;
1959 void Server::SendPlayerPrivileges(u16 peer_id)
1961 RemotePlayer *player = m_env->getPlayer(peer_id);
1963 if(player->peer_id == PEER_ID_INEXISTENT)
1966 std::set<std::string> privs;
1967 m_script->getAuth(player->getName(), NULL, &privs);
1969 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1970 pkt << (u16) privs.size();
1972 for(std::set<std::string>::const_iterator i = privs.begin();
1973 i != privs.end(); ++i) {
1980 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1982 RemotePlayer *player = m_env->getPlayer(peer_id);
1984 if(player->peer_id == PEER_ID_INEXISTENT)
1987 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1988 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1992 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1994 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1995 pkt.putRawString(datas.c_str(), datas.size());
1997 return pkt.getSize();
2000 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2002 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2003 datas.size(), peer_id);
2005 pkt.putRawString(datas.c_str(), datas.size());
2007 m_clients.send(pkt.getPeerId(),
2008 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2013 s32 Server::playSound(const SimpleSoundSpec &spec,
2014 const ServerSoundParams ¶ms)
2016 // Find out initial position of sound
2017 bool pos_exists = false;
2018 v3f pos = params.getPos(m_env, &pos_exists);
2019 // If position is not found while it should be, cancel sound
2020 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2023 // Filter destination clients
2024 std::vector<u16> dst_clients;
2025 if(params.to_player != "")
2027 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2029 infostream<<"Server::playSound: Player \""<<params.to_player
2030 <<"\" not found"<<std::endl;
2033 if(player->peer_id == PEER_ID_INEXISTENT){
2034 infostream<<"Server::playSound: Player \""<<params.to_player
2035 <<"\" not connected"<<std::endl;
2038 dst_clients.push_back(player->peer_id);
2041 std::vector<u16> clients = m_clients.getClientIDs();
2043 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2044 RemotePlayer *player = m_env->getPlayer(*i);
2048 PlayerSAO *sao = player->getPlayerSAO();
2053 if(sao->getBasePosition().getDistanceFrom(pos) >
2054 params.max_hear_distance)
2057 dst_clients.push_back(*i);
2061 if(dst_clients.empty())
2065 s32 id = m_next_sound_id++;
2066 // The sound will exist as a reference in m_playing_sounds
2067 m_playing_sounds[id] = ServerPlayingSound();
2068 ServerPlayingSound &psound = m_playing_sounds[id];
2069 psound.params = params;
2072 float gain = params.gain * spec.gain;
2073 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2074 pkt << id << spec.name << gain
2075 << (u8) params.type << pos << params.object
2076 << params.loop << params.fade << params.pitch;
2078 // Backwards compability
2079 bool play_sound = gain > 0;
2081 for (std::vector<u16>::iterator i = dst_clients.begin();
2082 i != dst_clients.end(); ++i) {
2083 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2084 psound.clients.insert(*i);
2085 m_clients.send(*i, 0, &pkt, true);
2090 void Server::stopSound(s32 handle)
2092 // Get sound reference
2093 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2094 m_playing_sounds.find(handle);
2095 if (i == m_playing_sounds.end())
2097 ServerPlayingSound &psound = i->second;
2099 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2102 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2103 si != psound.clients.end(); ++si) {
2105 m_clients.send(*si, 0, &pkt, true);
2107 // Remove sound reference
2108 m_playing_sounds.erase(i);
2111 void Server::fadeSound(s32 handle, float step, float gain)
2113 // Get sound reference
2114 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2115 m_playing_sounds.find(handle);
2116 if (i == m_playing_sounds.end())
2119 ServerPlayingSound &psound = i->second;
2120 psound.params.gain = gain;
2122 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2123 pkt << handle << step << gain;
2125 // Backwards compability
2126 bool play_sound = gain > 0;
2127 ServerPlayingSound compat_psound = psound;
2128 compat_psound.clients.clear();
2130 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2131 compat_pkt << handle;
2133 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2134 it != psound.clients.end();) {
2135 if (m_clients.getProtocolVersion(*it) >= 32) {
2137 m_clients.send(*it, 0, &pkt, true);
2140 compat_psound.clients.insert(*it);
2142 m_clients.send(*it, 0, &compat_pkt, true);
2143 psound.clients.erase(it++);
2147 // Remove sound reference
2148 if (!play_sound || psound.clients.size() == 0)
2149 m_playing_sounds.erase(i);
2151 if (play_sound && compat_psound.clients.size() > 0) {
2152 // Play new sound volume on older clients
2153 playSound(compat_psound.spec, compat_psound.params);
2157 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2158 std::vector<u16> *far_players, float far_d_nodes)
2160 float maxd = far_d_nodes*BS;
2161 v3f p_f = intToFloat(p, BS);
2163 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2166 std::vector<u16> clients = m_clients.getClientIDs();
2167 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2170 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2171 PlayerSAO *sao = player->getPlayerSAO();
2175 // If player is far away, only set modified blocks not sent
2176 v3f player_pos = sao->getBasePosition();
2177 if (player_pos.getDistanceFrom(p_f) > maxd) {
2178 far_players->push_back(*i);
2185 m_clients.send(*i, 0, &pkt, true);
2189 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2190 std::vector<u16> *far_players, float far_d_nodes,
2191 bool remove_metadata)
2193 float maxd = far_d_nodes*BS;
2194 v3f p_f = intToFloat(p, BS);
2196 std::vector<u16> clients = m_clients.getClientIDs();
2197 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2200 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2201 PlayerSAO *sao = player->getPlayerSAO();
2205 // If player is far away, only set modified blocks not sent
2206 v3f player_pos = sao->getBasePosition();
2207 if(player_pos.getDistanceFrom(p_f) > maxd) {
2208 far_players->push_back(*i);
2214 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2216 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2218 pkt << p << n.param0 << n.param1 << n.param2
2219 << (u8) (remove_metadata ? 0 : 1);
2224 if (pkt.getSize() > 0)
2225 m_clients.send(*i, 0, &pkt, true);
2229 void Server::setBlockNotSent(v3s16 p)
2231 std::vector<u16> clients = m_clients.getClientIDs();
2233 for(std::vector<u16>::iterator i = clients.begin();
2234 i != clients.end(); ++i) {
2235 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2236 client->SetBlockNotSent(p);
2241 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2243 DSTACK(FUNCTION_NAME);
2245 v3s16 p = block->getPos();
2248 Create a packet with the block in the right format
2251 std::ostringstream os(std::ios_base::binary);
2252 block->serialize(os, ver, false);
2253 block->serializeNetworkSpecific(os);
2254 std::string s = os.str();
2256 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2259 pkt.putRawString(s.c_str(), s.size());
2263 void Server::SendBlocks(float dtime)
2265 DSTACK(FUNCTION_NAME);
2267 MutexAutoLock envlock(m_env_mutex);
2268 //TODO check if one big lock could be faster then multiple small ones
2270 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2272 std::vector<PrioritySortedBlockTransfer> queue;
2274 s32 total_sending = 0;
2277 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2279 std::vector<u16> clients = m_clients.getClientIDs();
2282 for(std::vector<u16>::iterator i = clients.begin();
2283 i != clients.end(); ++i) {
2284 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2289 total_sending += client->SendingCount();
2290 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2296 // Lowest priority number comes first.
2297 // Lowest is most important.
2298 std::sort(queue.begin(), queue.end());
2301 for(u32 i=0; i<queue.size(); i++)
2303 //TODO: Calculate limit dynamically
2304 if(total_sending >= g_settings->getS32
2305 ("max_simultaneous_block_sends_server_total"))
2308 PrioritySortedBlockTransfer q = queue[i];
2310 MapBlock *block = NULL;
2313 block = m_env->getMap().getBlockNoCreate(q.pos);
2315 catch(InvalidPositionException &e)
2320 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2325 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2327 client->SentBlock(q.pos);
2333 void Server::fillMediaCache()
2335 DSTACK(FUNCTION_NAME);
2337 infostream<<"Server: Calculating media file checksums"<<std::endl;
2339 // Collect all media file paths
2340 std::vector<std::string> paths;
2341 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2342 i != m_mods.end(); ++i) {
2343 const ModSpec &mod = *i;
2344 paths.push_back(mod.path + DIR_DELIM + "textures");
2345 paths.push_back(mod.path + DIR_DELIM + "sounds");
2346 paths.push_back(mod.path + DIR_DELIM + "media");
2347 paths.push_back(mod.path + DIR_DELIM + "models");
2349 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2351 // Collect media file information from paths into cache
2352 for(std::vector<std::string>::iterator i = paths.begin();
2353 i != paths.end(); ++i) {
2354 std::string mediapath = *i;
2355 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2356 for (u32 j = 0; j < dirlist.size(); j++) {
2357 if (dirlist[j].dir) // Ignode dirs
2359 std::string filename = dirlist[j].name;
2360 // If name contains illegal characters, ignore the file
2361 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2362 infostream<<"Server: ignoring illegal file name: \""
2363 << filename << "\"" << std::endl;
2366 // If name is not in a supported format, ignore it
2367 const char *supported_ext[] = {
2368 ".png", ".jpg", ".bmp", ".tga",
2369 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2371 ".x", ".b3d", ".md2", ".obj",
2374 if (removeStringEnd(filename, supported_ext) == ""){
2375 infostream << "Server: ignoring unsupported file extension: \""
2376 << filename << "\"" << std::endl;
2379 // Ok, attempt to load the file and add to cache
2380 std::string filepath = mediapath + DIR_DELIM + filename;
2382 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2384 errorstream << "Server::fillMediaCache(): Could not open \""
2385 << filename << "\" for reading" << std::endl;
2388 std::ostringstream tmp_os(std::ios_base::binary);
2392 fis.read(buf, 1024);
2393 std::streamsize len = fis.gcount();
2394 tmp_os.write(buf, len);
2403 errorstream<<"Server::fillMediaCache(): Failed to read \""
2404 << filename << "\"" << std::endl;
2407 if(tmp_os.str().length() == 0) {
2408 errorstream << "Server::fillMediaCache(): Empty file \""
2409 << filepath << "\"" << std::endl;
2414 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2416 unsigned char *digest = sha1.getDigest();
2417 std::string sha1_base64 = base64_encode(digest, 20);
2418 std::string sha1_hex = hex_encode((char*)digest, 20);
2422 m_media[filename] = MediaInfo(filepath, sha1_base64);
2423 verbosestream << "Server: " << sha1_hex << " is " << filename
2429 void Server::sendMediaAnnouncement(u16 peer_id)
2431 DSTACK(FUNCTION_NAME);
2433 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2437 std::ostringstream os(std::ios_base::binary);
2439 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2440 pkt << (u16) m_media.size();
2442 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2443 i != m_media.end(); ++i) {
2444 pkt << i->first << i->second.sha1_digest;
2447 pkt << g_settings->get("remote_media");
2451 struct SendableMedia
2457 SendableMedia(const std::string &name_="", const std::string &path_="",
2458 const std::string &data_=""):
2465 void Server::sendRequestedMedia(u16 peer_id,
2466 const std::vector<std::string> &tosend)
2468 DSTACK(FUNCTION_NAME);
2470 verbosestream<<"Server::sendRequestedMedia(): "
2471 <<"Sending files to client"<<std::endl;
2475 // Put 5kB in one bunch (this is not accurate)
2476 u32 bytes_per_bunch = 5000;
2478 std::vector< std::vector<SendableMedia> > file_bunches;
2479 file_bunches.push_back(std::vector<SendableMedia>());
2481 u32 file_size_bunch_total = 0;
2483 for(std::vector<std::string>::const_iterator i = tosend.begin();
2484 i != tosend.end(); ++i) {
2485 const std::string &name = *i;
2487 if (m_media.find(name) == m_media.end()) {
2488 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2489 <<"unknown file \""<<(name)<<"\""<<std::endl;
2493 //TODO get path + name
2494 std::string tpath = m_media[name].path;
2497 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2498 if(fis.good() == false){
2499 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2500 <<tpath<<"\" for reading"<<std::endl;
2503 std::ostringstream tmp_os(std::ios_base::binary);
2507 fis.read(buf, 1024);
2508 std::streamsize len = fis.gcount();
2509 tmp_os.write(buf, len);
2510 file_size_bunch_total += len;
2519 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2520 <<name<<"\""<<std::endl;
2523 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2524 <<tname<<"\""<<std::endl;*/
2526 file_bunches[file_bunches.size()-1].push_back(
2527 SendableMedia(name, tpath, tmp_os.str()));
2529 // Start next bunch if got enough data
2530 if(file_size_bunch_total >= bytes_per_bunch) {
2531 file_bunches.push_back(std::vector<SendableMedia>());
2532 file_size_bunch_total = 0;
2537 /* Create and send packets */
2539 u16 num_bunches = file_bunches.size();
2540 for(u16 i = 0; i < num_bunches; i++) {
2543 u16 total number of texture bunches
2544 u16 index of this bunch
2545 u32 number of files in this bunch
2554 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2555 pkt << num_bunches << i << (u32) file_bunches[i].size();
2557 for(std::vector<SendableMedia>::iterator
2558 j = file_bunches[i].begin();
2559 j != file_bunches[i].end(); ++j) {
2561 pkt.putLongString(j->data);
2564 verbosestream << "Server::sendRequestedMedia(): bunch "
2565 << i << "/" << num_bunches
2566 << " files=" << file_bunches[i].size()
2567 << " size=" << pkt.getSize() << std::endl;
2572 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2574 if(m_detached_inventories.count(name) == 0) {
2575 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2578 Inventory *inv = m_detached_inventories[name];
2579 std::ostringstream os(std::ios_base::binary);
2581 os << serializeString(name);
2585 std::string s = os.str();
2587 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2588 pkt.putRawString(s.c_str(), s.size());
2590 const std::string &check = m_detached_inventories_player[name];
2591 if (peer_id == PEER_ID_INEXISTENT) {
2593 return m_clients.sendToAll(&pkt);
2594 RemotePlayer *p = m_env->getPlayer(check.c_str());
2596 m_clients.send(p->peer_id, 0, &pkt, true);
2598 if (check == "" || getPlayerName(peer_id) == check)
2603 void Server::sendDetachedInventories(u16 peer_id)
2605 DSTACK(FUNCTION_NAME);
2607 for(std::map<std::string, Inventory*>::iterator
2608 i = m_detached_inventories.begin();
2609 i != m_detached_inventories.end(); ++i) {
2610 const std::string &name = i->first;
2611 //Inventory *inv = i->second;
2612 sendDetachedInventory(name, peer_id);
2620 void Server::DiePlayer(u16 peer_id)
2622 DSTACK(FUNCTION_NAME);
2623 PlayerSAO *playersao = getPlayerSAO(peer_id);
2624 // In some rare cases this can be NULL -- if the player is disconnected
2625 // when a Lua function modifies l_punch, for example
2629 infostream << "Server::DiePlayer(): Player "
2630 << playersao->getPlayer()->getName()
2631 << " dies" << std::endl;
2633 playersao->setHP(0);
2635 // Trigger scripted stuff
2636 m_script->on_dieplayer(playersao);
2638 SendPlayerHP(peer_id);
2639 SendDeathscreen(peer_id, false, v3f(0,0,0));
2642 void Server::RespawnPlayer(u16 peer_id)
2644 DSTACK(FUNCTION_NAME);
2646 PlayerSAO *playersao = getPlayerSAO(peer_id);
2649 infostream << "Server::RespawnPlayer(): Player "
2650 << playersao->getPlayer()->getName()
2651 << " respawns" << std::endl;
2653 playersao->setHP(PLAYER_MAX_HP);
2654 playersao->setBreath(PLAYER_MAX_BREATH);
2656 bool repositioned = m_script->on_respawnplayer(playersao);
2657 if (!repositioned) {
2658 // setPos will send the new position to client
2659 playersao->setPos(findSpawnPos());
2662 SendPlayerHP(peer_id);
2666 void Server::DenySudoAccess(u16 peer_id)
2668 DSTACK(FUNCTION_NAME);
2670 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2675 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2676 const std::string &str_reason, bool reconnect)
2678 if (proto_ver >= 25) {
2679 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2681 std::wstring wreason = utf8_to_wide(
2682 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2683 accessDeniedStrings[(u8)reason]);
2684 SendAccessDenied_Legacy(peer_id, wreason);
2687 m_clients.event(peer_id, CSE_SetDenied);
2688 m_con.DisconnectPeer(peer_id);
2692 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2694 DSTACK(FUNCTION_NAME);
2696 SendAccessDenied(peer_id, reason, custom_reason);
2697 m_clients.event(peer_id, CSE_SetDenied);
2698 m_con.DisconnectPeer(peer_id);
2701 // 13/03/15: remove this function when protocol version 25 will become
2702 // the minimum version for MT users, maybe in 1 year
2703 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2705 DSTACK(FUNCTION_NAME);
2707 SendAccessDenied_Legacy(peer_id, reason);
2708 m_clients.event(peer_id, CSE_SetDenied);
2709 m_con.DisconnectPeer(peer_id);
2712 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2714 DSTACK(FUNCTION_NAME);
2717 RemoteClient* client = getClient(peer_id, CS_Invalid);
2719 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2721 // Right now, the auth mechs don't change between login and sudo mode.
2722 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2723 client->allowed_sudo_mechs = sudo_auth_mechs;
2725 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2726 << g_settings->getFloat("dedicated_server_step")
2730 m_clients.event(peer_id, CSE_AuthAccept);
2732 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2734 // We only support SRP right now
2735 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2737 resp_pkt << sudo_auth_mechs;
2739 m_clients.event(peer_id, CSE_SudoSuccess);
2743 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2745 DSTACK(FUNCTION_NAME);
2746 std::wstring message;
2749 Clear references to playing sounds
2751 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2752 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2753 ServerPlayingSound &psound = i->second;
2754 psound.clients.erase(peer_id);
2755 if (psound.clients.empty())
2756 m_playing_sounds.erase(i++);
2761 RemotePlayer *player = m_env->getPlayer(peer_id);
2763 /* Run scripts and remove from environment */
2764 if (player != NULL) {
2765 PlayerSAO *playersao = player->getPlayerSAO();
2768 // inform connected clients
2769 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2770 // (u16) 1 + std::string represents a vector serialization representation
2771 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2772 m_clients.sendToAll(¬ice);
2774 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2776 playersao->disconnected();
2783 if(player != NULL && reason != CDR_DENY) {
2784 std::ostringstream os(std::ios_base::binary);
2785 std::vector<u16> clients = m_clients.getClientIDs();
2787 for(std::vector<u16>::iterator i = clients.begin();
2788 i != clients.end(); ++i) {
2790 RemotePlayer *player = m_env->getPlayer(*i);
2794 // Get name of player
2795 os << player->getName() << " ";
2798 std::string name = player->getName();
2799 actionstream << name << " "
2800 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2801 << " List of players: " << os.str() << std::endl;
2803 m_admin_chat->outgoing_queue.push_back(
2804 new ChatEventNick(CET_NICK_REMOVE, name));
2808 MutexAutoLock env_lock(m_env_mutex);
2809 m_clients.DeleteClient(peer_id);
2813 // Send leave chat message to all remaining clients
2814 if(message.length() != 0)
2815 SendChatMessage(PEER_ID_INEXISTENT,message);
2818 void Server::UpdateCrafting(RemotePlayer *player)
2820 DSTACK(FUNCTION_NAME);
2822 // Get a preview for crafting
2824 InventoryLocation loc;
2825 loc.setPlayer(player->getName());
2826 std::vector<ItemStack> output_replacements;
2827 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2828 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2829 (&player->inventory)->getList("craft"), loc);
2831 // Put the new preview in
2832 InventoryList *plist = player->inventory.getList("craftpreview");
2833 sanity_check(plist);
2834 sanity_check(plist->getSize() >= 1);
2835 plist->changeItem(0, preview);
2838 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2840 if (evt->type == CET_NICK_ADD) {
2841 // The terminal informed us of its nick choice
2842 m_admin_nick = ((ChatEventNick *)evt)->nick;
2843 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2844 errorstream << "You haven't set up an account." << std::endl
2845 << "Please log in using the client as '"
2846 << m_admin_nick << "' with a secure password." << std::endl
2847 << "Until then, you can't execute admin tasks via the console," << std::endl
2848 << "and everybody can claim the user account instead of you," << std::endl
2849 << "giving them full control over this server." << std::endl;
2852 assert(evt->type == CET_CHAT);
2853 handleAdminChat((ChatEventChat *)evt);
2857 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2858 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2860 // If something goes wrong, this player is to blame
2861 RollbackScopeActor rollback_scope(m_rollback,
2862 std::string("player:") + name);
2864 if (g_settings->getBool("strip_color_codes"))
2865 wmessage = unescape_enriched(wmessage);
2868 switch (player->canSendChatMessage()) {
2869 case RPLAYER_CHATRESULT_FLOODING: {
2870 std::wstringstream ws;
2871 ws << L"You cannot send more messages. You are limited to "
2872 << g_settings->getFloat("chat_message_limit_per_10sec")
2873 << L" messages per 10 seconds.";
2876 case RPLAYER_CHATRESULT_KICK:
2877 DenyAccess_Legacy(player->peer_id,
2878 L"You have been kicked due to message flooding.");
2880 case RPLAYER_CHATRESULT_OK:
2883 FATAL_ERROR("Unhandled chat filtering result found.");
2887 if (m_max_chatmessage_length > 0
2888 && wmessage.length() > m_max_chatmessage_length) {
2889 return L"Your message exceed the maximum chat message limit set on the server. "
2890 L"It was refused. Send a shorter message";
2893 // Run script hook, exit if script ate the chat message
2894 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2899 // Whether to send line to the player that sent the message, or to all players
2900 bool broadcast_line = true;
2902 if (check_shout_priv && !checkPriv(name, "shout")) {
2903 line += L"-!- You don't have permission to shout.";
2904 broadcast_line = false;
2913 Tell calling method to send the message to sender
2915 if (!broadcast_line) {
2919 Send the message to others
2921 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2923 std::vector<u16> clients = m_clients.getClientIDs();
2926 Send the message back to the inital sender
2927 if they are using protocol version >= 29
2930 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2931 if (player && player->protocol_version >= 29)
2932 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2934 for (u16 i = 0; i < clients.size(); i++) {
2935 u16 cid = clients[i];
2936 if (cid != peer_id_to_avoid_sending)
2937 SendChatMessage(cid, line);
2943 void Server::handleAdminChat(const ChatEventChat *evt)
2945 std::string name = evt->nick;
2946 std::wstring wname = utf8_to_wide(name);
2947 std::wstring wmessage = evt->evt_msg;
2949 std::wstring answer = handleChat(name, wname, wmessage);
2951 // If asked to send answer to sender
2952 if (!answer.empty()) {
2953 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2957 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2959 RemoteClient *client = getClientNoEx(peer_id,state_min);
2961 throw ClientNotFoundException("Client not found");
2965 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2967 return m_clients.getClientNoEx(peer_id, state_min);
2970 std::string Server::getPlayerName(u16 peer_id)
2972 RemotePlayer *player = m_env->getPlayer(peer_id);
2974 return "[id="+itos(peer_id)+"]";
2975 return player->getName();
2978 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2980 RemotePlayer *player = m_env->getPlayer(peer_id);
2983 return player->getPlayerSAO();
2986 std::wstring Server::getStatusString()
2988 std::wostringstream os(std::ios_base::binary);
2991 os<<L"version="<<narrow_to_wide(g_version_string);
2993 os<<L", uptime="<<m_uptime.get();
2995 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2996 // Information about clients
2999 std::vector<u16> clients = m_clients.getClientIDs();
3000 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3002 RemotePlayer *player = m_env->getPlayer(*i);
3003 // Get name of player
3004 std::wstring name = L"unknown";
3006 name = narrow_to_wide(player->getName());
3007 // Add name to information string
3015 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3016 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3017 if(g_settings->get("motd") != "")
3018 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3022 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3024 std::set<std::string> privs;
3025 m_script->getAuth(name, NULL, &privs);
3029 bool Server::checkPriv(const std::string &name, const std::string &priv)
3031 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3032 return (privs.count(priv) != 0);
3035 void Server::reportPrivsModified(const std::string &name)
3038 std::vector<u16> clients = m_clients.getClientIDs();
3039 for(std::vector<u16>::iterator i = clients.begin();
3040 i != clients.end(); ++i) {
3041 RemotePlayer *player = m_env->getPlayer(*i);
3042 reportPrivsModified(player->getName());
3045 RemotePlayer *player = m_env->getPlayer(name.c_str());
3048 SendPlayerPrivileges(player->peer_id);
3049 PlayerSAO *sao = player->getPlayerSAO();
3052 sao->updatePrivileges(
3053 getPlayerEffectivePrivs(name),
3058 void Server::reportInventoryFormspecModified(const std::string &name)
3060 RemotePlayer *player = m_env->getPlayer(name.c_str());
3063 SendPlayerInventoryFormspec(player->peer_id);
3066 void Server::setIpBanned(const std::string &ip, const std::string &name)
3068 m_banmanager->add(ip, name);
3071 void Server::unsetIpBanned(const std::string &ip_or_name)
3073 m_banmanager->remove(ip_or_name);
3076 std::string Server::getBanDescription(const std::string &ip_or_name)
3078 return m_banmanager->getBanDescription(ip_or_name);
3081 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3083 // m_env will be NULL if the server is initializing
3087 if (m_admin_nick == name && !m_admin_nick.empty()) {
3088 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3091 RemotePlayer *player = m_env->getPlayer(name);
3096 if (player->peer_id == PEER_ID_INEXISTENT)
3099 SendChatMessage(player->peer_id, msg);
3102 bool Server::showFormspec(const char *playername, const std::string &formspec,
3103 const std::string &formname)
3105 // m_env will be NULL if the server is initializing
3109 RemotePlayer *player = m_env->getPlayer(playername);
3113 SendShowFormspecMessage(player->peer_id, formspec, formname);
3117 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3122 u32 id = player->addHud(form);
3124 SendHUDAdd(player->peer_id, id, form);
3129 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3133 HudElement* todel = player->removeHud(id);
3140 SendHUDRemove(player->peer_id, id);
3144 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3149 SendHUDChange(player->peer_id, id, stat, data);
3153 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3158 SendHUDSetFlags(player->peer_id, flags, mask);
3159 player->hud_flags &= ~mask;
3160 player->hud_flags |= flags;
3162 PlayerSAO* playersao = player->getPlayerSAO();
3164 if (playersao == NULL)
3167 m_script->player_event(playersao, "hud_changed");
3171 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3176 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3179 player->setHotbarItemcount(hotbar_itemcount);
3180 std::ostringstream os(std::ios::binary);
3181 writeS32(os, hotbar_itemcount);
3182 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3186 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3191 player->setHotbarImage(name);
3192 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3195 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3199 return player->getHotbarImage();
3202 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3207 player->setHotbarSelectedImage(name);
3208 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3211 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3212 v2s32 animation_frames[4], f32 frame_speed)
3217 player->setLocalAnimations(animation_frames, frame_speed);
3218 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3222 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3227 player->eye_offset_first = first;
3228 player->eye_offset_third = third;
3229 SendEyeOffset(player->peer_id, first, third);
3233 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3234 const std::string &type, const std::vector<std::string> ¶ms,
3240 player->setSky(bgcolor, type, params, clouds);
3241 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3245 bool Server::setClouds(RemotePlayer *player, float density,
3246 const video::SColor &color_bright,
3247 const video::SColor &color_ambient,
3255 SendCloudParams(player->peer_id, density,
3256 color_bright, color_ambient, height,
3261 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3267 player->overrideDayNightRatio(do_override, ratio);
3268 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3272 void Server::notifyPlayers(const std::wstring &msg)
3274 SendChatMessage(PEER_ID_INEXISTENT,msg);
3277 void Server::spawnParticle(const std::string &playername, v3f pos,
3278 v3f velocity, v3f acceleration,
3279 float expirationtime, float size, bool
3280 collisiondetection, bool collision_removal,
3281 bool vertical, const std::string &texture,
3282 const struct TileAnimationParams &animation, u8 glow)
3284 // m_env will be NULL if the server is initializing
3288 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3289 if (playername != "") {
3290 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3293 peer_id = player->peer_id;
3294 proto_ver = player->protocol_version;
3297 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3298 expirationtime, size, collisiondetection,
3299 collision_removal, vertical, texture, animation, glow);
3302 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3303 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3304 float minexptime, float maxexptime, float minsize, float maxsize,
3305 bool collisiondetection, bool collision_removal,
3306 ServerActiveObject *attached, bool vertical, const std::string &texture,
3307 const std::string &playername, const struct TileAnimationParams &animation,
3310 // m_env will be NULL if the server is initializing
3314 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3315 if (playername != "") {
3316 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3319 peer_id = player->peer_id;
3320 proto_ver = player->protocol_version;
3323 u16 attached_id = attached ? attached->getId() : 0;
3326 if (attached_id == 0)
3327 id = m_env->addParticleSpawner(spawntime);
3329 id = m_env->addParticleSpawner(spawntime, attached_id);
3331 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3332 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3333 minexptime, maxexptime, minsize, maxsize,
3334 collisiondetection, collision_removal, attached_id, vertical,
3335 texture, id, animation, glow);
3340 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3342 // m_env will be NULL if the server is initializing
3344 throw ServerError("Can't delete particle spawners during initialisation!");
3346 u16 peer_id = PEER_ID_INEXISTENT;
3347 if (playername != "") {
3348 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3351 peer_id = player->peer_id;
3354 m_env->deleteParticleSpawner(id);
3355 SendDeleteParticleSpawner(peer_id, id);
3358 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3360 if(m_detached_inventories.count(name) > 0){
3361 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3362 delete m_detached_inventories[name];
3364 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3366 Inventory *inv = new Inventory(m_itemdef);
3368 m_detached_inventories[name] = inv;
3369 m_detached_inventories_player[name] = player;
3370 //TODO find a better way to do this
3371 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3375 // actions: time-reversed list
3376 // Return value: success/failure
3377 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3378 std::list<std::string> *log)
3380 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3381 ServerMap *map = (ServerMap*)(&m_env->getMap());
3383 // Fail if no actions to handle
3384 if(actions.empty()){
3385 log->push_back("Nothing to do.");
3392 for(std::list<RollbackAction>::const_iterator
3393 i = actions.begin();
3394 i != actions.end(); ++i)
3396 const RollbackAction &action = *i;
3398 bool success = action.applyRevert(map, this, this);
3401 std::ostringstream os;
3402 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3403 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3405 log->push_back(os.str());
3407 std::ostringstream os;
3408 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3409 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3411 log->push_back(os.str());
3415 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3416 <<" failed"<<std::endl;
3418 // Call it done if less than half failed
3419 return num_failed <= num_tried/2;
3422 // IGameDef interface
3424 IItemDefManager *Server::getItemDefManager()
3429 INodeDefManager *Server::getNodeDefManager()
3434 ICraftDefManager *Server::getCraftDefManager()
3439 u16 Server::allocateUnknownNodeId(const std::string &name)
3441 return m_nodedef->allocateDummy(name);
3444 MtEventManager *Server::getEventManager()
3449 IWritableItemDefManager *Server::getWritableItemDefManager()
3454 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3459 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3464 const ModSpec *Server::getModSpec(const std::string &modname) const
3466 std::vector<ModSpec>::const_iterator it;
3467 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3468 const ModSpec &mod = *it;
3469 if (mod.name == modname)
3475 void Server::getModNames(std::vector<std::string> &modlist)
3477 std::vector<ModSpec>::iterator it;
3478 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3479 modlist.push_back(it->name);
3482 std::string Server::getBuiltinLuaPath()
3484 return porting::path_share + DIR_DELIM + "builtin";
3487 std::string Server::getModStoragePath() const
3489 return m_path_world + DIR_DELIM + "mod_storage";
3492 v3f Server::findSpawnPos()
3494 ServerMap &map = m_env->getServerMap();
3496 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3497 return nodeposf * BS;
3500 bool is_good = false;
3501 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3502 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3504 // Try to find a good place a few times
3505 for(s32 i = 0; i < 4000 && !is_good; i++) {
3506 s32 range = MYMIN(1 + i, range_max);
3507 // We're going to try to throw the player to this position
3508 v2s16 nodepos2d = v2s16(
3509 -range + (myrand() % (range * 2)),
3510 -range + (myrand() % (range * 2)));
3512 // Get spawn level at point
3513 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3514 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3515 // the mapgen to signify an unsuitable spawn position
3516 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3519 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3522 for (s32 i = 0; i < 10; i++) {
3523 v3s16 blockpos = getNodeBlockPos(nodepos);
3524 map.emergeBlock(blockpos, true);
3525 content_t c = map.getNodeNoEx(nodepos).getContent();
3526 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3528 if (air_count >= 2) {
3529 nodeposf = intToFloat(nodepos, BS);
3530 // Don't spawn the player outside map boundaries
3531 if (objectpos_over_limit(nodeposf))
3544 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3546 m_shutdown_timer = delay;
3547 m_shutdown_msg = msg;
3548 m_shutdown_ask_reconnect = reconnect;
3550 if (delay == 0.0f) {
3551 // No delay, shutdown immediately
3552 m_shutdown_requested = true;
3553 // only print to the infostream, a chat message saying
3554 // "Server Shutting Down" is sent when the server destructs.
3555 infostream << "*** Immediate Server shutdown requested." << std::endl;
3556 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3557 // Negative delay, cancel shutdown if requested
3558 m_shutdown_timer = 0.0f;
3559 m_shutdown_msg = "";
3560 m_shutdown_ask_reconnect = false;
3561 m_shutdown_requested = false;
3562 std::wstringstream ws;
3564 ws << L"*** Server shutdown canceled.";
3566 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3567 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3568 } else if (delay > 0.0f) {
3569 // Positive delay, tell the clients when the server will shut down
3570 std::wstringstream ws;
3572 ws << L"*** Server shutting down in "
3573 << duration_to_string(myround(m_shutdown_timer)).c_str()
3576 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3577 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3581 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3584 Try to get an existing player
3586 RemotePlayer *player = m_env->getPlayer(name);
3588 // If player is already connected, cancel
3589 if (player != NULL && player->peer_id != 0) {
3590 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3595 If player with the wanted peer_id already exists, cancel.
3597 if (m_env->getPlayer(peer_id) != NULL) {
3598 infostream<<"emergePlayer(): Player with wrong name but same"
3599 " peer_id already exists"<<std::endl;
3604 player = new RemotePlayer(name, idef());
3607 bool newplayer = false;
3610 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3612 // Complete init with server parts
3613 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3614 player->protocol_version = proto_version;
3618 m_script->on_newplayer(playersao);
3624 bool Server::registerModStorage(ModMetadata *storage)
3626 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3627 errorstream << "Unable to register same mod storage twice. Storage name: "
3628 << storage->getModName() << std::endl;
3632 m_mod_storages[storage->getModName()] = storage;
3636 void Server::unregisterModStorage(const std::string &name)
3638 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3639 if (it != m_mod_storages.end()) {
3640 // Save unconditionaly on unregistration
3641 it->second->save(getModStoragePath());
3642 m_mod_storages.erase(name);
3646 void dedicated_server_loop(Server &server, bool &kill)
3648 DSTACK(FUNCTION_NAME);
3650 verbosestream<<"dedicated_server_loop()"<<std::endl;
3652 IntervalLimiter m_profiler_interval;
3654 static thread_local const float steplen =
3655 g_settings->getFloat("dedicated_server_step");
3656 static thread_local const float profiler_print_interval =
3657 g_settings->getFloat("profiler_print_interval");
3660 // This is kind of a hack but can be done like this
3661 // because server.step() is very light
3663 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3664 sleep_ms((int)(steplen*1000.0));
3666 server.step(steplen);
3668 if (server.getShutdownRequested() || kill)
3674 if (profiler_print_interval != 0) {
3675 if(m_profiler_interval.step(steplen, profiler_print_interval))
3677 infostream<<"Profiler:"<<std::endl;
3678 g_profiler->print(infostream);
3679 g_profiler->clear();
3684 infostream << "Dedicated server quitting" << std::endl;
3686 if (g_settings->getBool("server_announce"))
3687 ServerList::sendAnnounce(ServerList::AA_DELETE,
3688 server.m_bind_addr.getPort());