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"
63 #include "chatmessage.h"
65 class ClientNotFoundException : public BaseException
68 ClientNotFoundException(const char *s):
73 class ServerThread : public Thread
77 ServerThread(Server *server):
88 void *ServerThread::run()
90 DSTACK(FUNCTION_NAME);
91 BEGIN_DEBUG_EXCEPTION_HANDLER
93 m_server->AsyncRunStep(true);
95 while (!stopRequested()) {
97 //TimeTaker timer("AsyncRunStep() + Receive()");
99 m_server->AsyncRunStep();
103 } catch (con::NoIncomingDataException &e) {
104 } catch (con::PeerNotFoundException &e) {
105 infostream<<"Server: PeerNotFoundException"<<std::endl;
106 } catch (ClientNotFoundException &e) {
107 } catch (con::ConnectionBindFailed &e) {
108 m_server->setAsyncFatalError(e.what());
109 } catch (LuaError &e) {
110 m_server->setAsyncFatalError(
111 "ServerThread::run 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,
155 m_path_world(path_world),
156 m_gamespec(gamespec),
157 m_simple_singleplayer_mode(simple_singleplayer_mode),
158 m_dedicated(dedicated),
159 m_async_fatal_error(""),
165 m_itemdef(createItemDefManager()),
166 m_nodedef(createNodeDefManager()),
167 m_craftdef(createCraftDefManager()),
168 m_event(new EventManager()),
173 m_lag = g_settings->getFloat("dedicated_server_step");
176 throw ServerError("Supplied empty world path");
178 if(!gamespec.isValid())
179 throw ServerError("Supplied invalid gamespec");
181 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
182 if(m_simple_singleplayer_mode)
183 infostream<<" in simple singleplayer mode"<<std::endl;
185 infostream<<std::endl;
186 infostream<<"- world: "<<m_path_world<<std::endl;
187 infostream<<"- game: "<<m_gamespec.path<<std::endl;
189 // Create world if it doesn't exist
190 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
191 throw ServerError("Failed to initialize world");
193 // Create server thread
194 m_thread = new ServerThread(this);
196 // Create emerge manager
197 m_emerge = new EmergeManager(this);
199 // Create ban manager
200 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
201 m_banmanager = new BanManager(ban_path);
203 ServerModConfiguration modconf(m_path_world);
204 m_mods = modconf.getMods();
205 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
206 // complain about mods with unsatisfied dependencies
207 if (!modconf.isConsistent()) {
208 modconf.printUnsatisfiedModsError();
212 MutexAutoLock envlock(m_env_mutex);
214 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
215 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
217 // Initialize scripting
218 infostream<<"Server: Initializing Lua"<<std::endl;
220 m_script = new ServerScripting(this);
222 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
225 infostream << "Server: Loading mods: ";
226 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
227 i != m_mods.end(); ++i) {
228 infostream << (*i).name << " ";
230 infostream << std::endl;
231 // Load and run "mod" scripts
232 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
233 it != m_mods.end(); ++it) {
234 const ModSpec &mod = *it;
235 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
236 throw ModError("Error loading mod \"" + mod.name +
237 "\": Mod name does not follow naming conventions: "
238 "Only characters [a-z0-9_] are allowed.");
240 std::string script_path = mod.path + DIR_DELIM + "init.lua";
241 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
242 << script_path << "\"]" << std::endl;
243 m_script->loadMod(script_path, mod.name);
246 // Read Textures and calculate sha1 sums
249 // Apply item aliases in the node definition manager
250 m_nodedef->updateAliases(m_itemdef);
252 // Apply texture overrides from texturepack/override.txt
253 std::string texture_path = g_settings->get("texture_path");
254 if (texture_path != "" && fs::IsDir(texture_path))
255 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
257 m_nodedef->setNodeRegistrationStatus(true);
259 // Perform pending node name resolutions
260 m_nodedef->runNodeResolveCallbacks();
262 // unmap node names for connected nodeboxes
263 m_nodedef->mapNodeboxConnections();
265 // init the recipe hashes to speed up crafting
266 m_craftdef->initHashes(this);
268 // Initialize Environment
269 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
271 m_clients.setEnv(m_env);
273 if (!servermap->settings_mgr.makeMapgenParams())
274 FATAL_ERROR("Couldn't create any mapgen type");
276 // Initialize mapgens
277 m_emerge->initMapgens(servermap->getMapgenParams());
279 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
280 if (m_enable_rollback_recording) {
281 // Create rollback manager
282 m_rollback = new RollbackManager(m_path_world, this);
285 // Give environment reference to scripting api
286 m_script->initializeEnvironment(m_env);
288 // Register us to receive map edit events
289 servermap->addEventReceiver(this);
291 // If file exists, load environment metadata
292 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
293 infostream << "Server: Loading environment metadata" << std::endl;
296 m_env->loadDefaultMeta();
299 m_liquid_transform_every = g_settings->getFloat("liquid_update");
300 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
305 infostream<<"Server destructing"<<std::endl;
307 // Send shutdown message
308 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
309 L"*** Server shutting down"));
312 MutexAutoLock envlock(m_env_mutex);
314 // Execute script shutdown hooks
315 m_script->on_shutdown();
317 infostream << "Server: Saving players" << std::endl;
318 m_env->saveLoadedPlayers();
320 infostream << "Server: Kicking players" << std::endl;
321 std::string kick_msg;
322 bool reconnect = false;
323 if (getShutdownRequested()) {
324 reconnect = m_shutdown_ask_reconnect;
325 kick_msg = m_shutdown_msg;
327 if (kick_msg == "") {
328 kick_msg = g_settings->get("kick_msg_shutdown");
330 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
331 kick_msg, reconnect);
333 infostream << "Server: Saving environment metadata" << std::endl;
341 // stop all emerge threads before deleting players that may have
342 // requested blocks to be emerged
343 m_emerge->stopThreads();
345 // Delete things in the reverse order of creation
355 // Deinitialize scripting
356 infostream<<"Server: Deinitializing scripting"<<std::endl;
359 // Delete detached inventories
360 for (std::map<std::string, Inventory*>::iterator
361 i = m_detached_inventories.begin();
362 i != m_detached_inventories.end(); ++i) {
367 void Server::start(Address bind_addr)
369 DSTACK(FUNCTION_NAME);
371 m_bind_addr = bind_addr;
373 infostream<<"Starting server on "
374 << bind_addr.serializeString() <<"..."<<std::endl;
376 // Stop thread if already running
379 // Initialize connection
380 m_con.SetTimeoutMs(30);
381 m_con.Serve(bind_addr);
386 // ASCII art for the win!
388 <<" .__ __ __ "<<std::endl
389 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
390 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
391 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
392 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
393 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
394 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
395 actionstream<<"Server for gameid=\""<<m_gamespec.id
396 <<"\" listening on "<<bind_addr.serializeString()<<":"
397 <<bind_addr.getPort() << "."<<std::endl;
402 DSTACK(FUNCTION_NAME);
404 infostream<<"Server: Stopping and waiting threads"<<std::endl;
406 // Stop threads (set run=false first so both start stopping)
408 //m_emergethread.setRun(false);
410 //m_emergethread.stop();
412 infostream<<"Server: Threads stopped"<<std::endl;
415 void Server::step(float dtime)
417 DSTACK(FUNCTION_NAME);
422 MutexAutoLock lock(m_step_dtime_mutex);
423 m_step_dtime += dtime;
425 // Throw if fatal error occurred in thread
426 std::string async_err = m_async_fatal_error.get();
427 if (!async_err.empty()) {
428 if (!m_simple_singleplayer_mode) {
429 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
430 g_settings->get("kick_msg_crash"),
431 g_settings->getBool("ask_reconnect_on_crash"));
433 throw ServerError("AsyncErr: " + async_err);
437 void Server::AsyncRunStep(bool initial_step)
439 DSTACK(FUNCTION_NAME);
441 g_profiler->add("Server::AsyncRunStep (num)", 1);
445 MutexAutoLock lock1(m_step_dtime_mutex);
446 dtime = m_step_dtime;
450 // Send blocks to clients
454 if((dtime < 0.001) && (initial_step == false))
457 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
459 //infostream<<"Server steps "<<dtime<<std::endl;
460 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
463 MutexAutoLock lock1(m_step_dtime_mutex);
464 m_step_dtime -= dtime;
471 m_uptime.set(m_uptime.get() + dtime);
477 Update time of day and overall game time
479 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
482 Send to clients at constant intervals
485 m_time_of_day_send_timer -= dtime;
486 if(m_time_of_day_send_timer < 0.0) {
487 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
488 u16 time = m_env->getTimeOfDay();
489 float time_speed = g_settings->getFloat("time_speed");
490 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
494 MutexAutoLock lock(m_env_mutex);
495 // Figure out and report maximum lag to environment
496 float max_lag = m_env->getMaxLagEstimate();
497 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
499 if(dtime > 0.1 && dtime > max_lag * 2.0)
500 infostream<<"Server: Maximum lag peaked to "<<dtime
504 m_env->reportMaxLagEstimate(max_lag);
506 ScopeProfiler sp(g_profiler, "SEnv step");
507 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
511 static const float map_timer_and_unload_dtime = 2.92;
512 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
514 MutexAutoLock lock(m_env_mutex);
515 // Run Map's timers and unload unused data
516 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
517 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
518 g_settings->getFloat("server_unload_unused_data_timeout"),
523 Listen to the admin chat, if available
526 if (!m_admin_chat->command_queue.empty()) {
527 MutexAutoLock lock(m_env_mutex);
528 while (!m_admin_chat->command_queue.empty()) {
529 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
530 handleChatInterfaceEvent(evt);
534 m_admin_chat->outgoing_queue.push_back(
535 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
542 /* Transform liquids */
543 m_liquid_transform_timer += dtime;
544 if(m_liquid_transform_timer >= m_liquid_transform_every)
546 m_liquid_transform_timer -= m_liquid_transform_every;
548 MutexAutoLock lock(m_env_mutex);
550 ScopeProfiler sp(g_profiler, "Server: liquid transform");
552 std::map<v3s16, MapBlock*> modified_blocks;
553 m_env->getMap().transformLiquids(modified_blocks, m_env);
558 core::map<v3s16, MapBlock*> lighting_modified_blocks;
559 ServerMap &map = ((ServerMap&)m_env->getMap());
560 map.updateLighting(modified_blocks, lighting_modified_blocks);
562 // Add blocks modified by lighting to modified_blocks
563 for(core::map<v3s16, MapBlock*>::Iterator
564 i = lighting_modified_blocks.getIterator();
565 i.atEnd() == false; i++)
567 MapBlock *block = i.getNode()->getValue();
568 modified_blocks.insert(block->getPos(), block);
572 Set the modified blocks unsent for all the clients
574 if(!modified_blocks.empty())
576 SetBlocksNotSent(modified_blocks);
579 m_clients.step(dtime);
581 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
583 // send masterserver announce
585 float &counter = m_masterserver_timer;
586 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
587 g_settings->getBool("server_announce")) {
588 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
589 ServerList::AA_START,
590 m_bind_addr.getPort(),
591 m_clients.getPlayerNames(),
593 m_env->getGameTime(),
596 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
606 Check added and deleted active objects
609 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
610 MutexAutoLock envlock(m_env_mutex);
613 RemoteClientMap clients = m_clients.getClientList();
614 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
616 // Radius inside which objects are active
617 static thread_local const s16 radius =
618 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
620 // Radius inside which players are active
621 static thread_local const bool is_transfer_limited =
622 g_settings->exists("unlimited_player_transfer_distance") &&
623 !g_settings->getBool("unlimited_player_transfer_distance");
624 static thread_local const s16 player_transfer_dist =
625 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
626 s16 player_radius = player_transfer_dist;
627 if (player_radius == 0 && is_transfer_limited)
628 player_radius = radius;
630 for (RemoteClientMap::iterator i = clients.begin();
631 i != clients.end(); ++i) {
632 RemoteClient *client = i->second;
634 // If definitions and textures have not been sent, don't
635 // send objects either
636 if (client->getState() < CS_DefinitionsSent)
639 RemotePlayer *player = m_env->getPlayer(client->peer_id);
640 if (player == NULL) {
641 // This can happen if the client timeouts somehow
642 /*warningstream<<FUNCTION_NAME<<": Client "
644 <<" has no associated player"<<std::endl;*/
648 PlayerSAO *playersao = player->getPlayerSAO();
649 if (playersao == NULL)
652 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
653 if (my_radius <= 0) my_radius = radius;
654 //infostream << "Server: Active Radius " << my_radius << std::endl;
656 std::queue<u16> removed_objects;
657 std::queue<u16> added_objects;
658 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
659 client->m_known_objects, removed_objects);
660 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
661 client->m_known_objects, added_objects);
663 // Ignore if nothing happened
664 if (removed_objects.empty() && added_objects.empty()) {
668 std::string data_buffer;
672 // Handle removed objects
673 writeU16((u8*)buf, removed_objects.size());
674 data_buffer.append(buf, 2);
675 while (!removed_objects.empty()) {
677 u16 id = removed_objects.front();
678 ServerActiveObject* obj = m_env->getActiveObject(id);
680 // Add to data buffer for sending
681 writeU16((u8*)buf, id);
682 data_buffer.append(buf, 2);
684 // Remove from known objects
685 client->m_known_objects.erase(id);
687 if(obj && obj->m_known_by_count > 0)
688 obj->m_known_by_count--;
689 removed_objects.pop();
692 // Handle added objects
693 writeU16((u8*)buf, added_objects.size());
694 data_buffer.append(buf, 2);
695 while (!added_objects.empty()) {
697 u16 id = added_objects.front();
698 ServerActiveObject* obj = m_env->getActiveObject(id);
701 u8 type = ACTIVEOBJECT_TYPE_INVALID;
703 warningstream<<FUNCTION_NAME
704 <<": NULL object"<<std::endl;
706 type = obj->getSendType();
708 // Add to data buffer for sending
709 writeU16((u8*)buf, id);
710 data_buffer.append(buf, 2);
711 writeU8((u8*)buf, type);
712 data_buffer.append(buf, 1);
715 data_buffer.append(serializeLongString(
716 obj->getClientInitializationData(client->net_proto_version)));
718 data_buffer.append(serializeLongString(""));
720 // Add to known objects
721 client->m_known_objects.insert(id);
724 obj->m_known_by_count++;
729 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
730 verbosestream << "Server: Sent object remove/add: "
731 << removed_objects.size() << " removed, "
732 << added_objects.size() << " added, "
733 << "packet size is " << pktSize << std::endl;
737 m_mod_storage_save_timer -= dtime;
738 if (m_mod_storage_save_timer <= 0.0f) {
739 infostream << "Saving registered mod storages." << std::endl;
740 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
741 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
742 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
743 if (it->second->isModified()) {
744 it->second->save(getModStoragePath());
754 MutexAutoLock envlock(m_env_mutex);
755 ScopeProfiler sp(g_profiler, "Server: sending object messages");
758 // Value = data sent by object
759 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
761 // Get active object messages from environment
763 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
767 std::vector<ActiveObjectMessage>* message_list = NULL;
768 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
769 n = buffered_messages.find(aom.id);
770 if (n == buffered_messages.end()) {
771 message_list = new std::vector<ActiveObjectMessage>;
772 buffered_messages[aom.id] = message_list;
775 message_list = n->second;
777 message_list->push_back(aom);
781 RemoteClientMap clients = m_clients.getClientList();
782 // Route data to every client
783 for (std::unordered_map<u16, RemoteClient*>::iterator i = clients.begin();
784 i != clients.end(); ++i) {
785 RemoteClient *client = i->second;
786 std::string reliable_data;
787 std::string unreliable_data;
788 // Go through all objects in message buffer
789 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
790 j = buffered_messages.begin();
791 j != buffered_messages.end(); ++j) {
792 // If object is not known by client, skip it
794 if (client->m_known_objects.find(id) == client->m_known_objects.end())
797 // Get message list of object
798 std::vector<ActiveObjectMessage>* list = j->second;
799 // Go through every message
800 for (std::vector<ActiveObjectMessage>::iterator
801 k = list->begin(); k != list->end(); ++k) {
802 // Compose the full new data with header
803 ActiveObjectMessage aom = *k;
804 std::string new_data;
807 writeU16((u8*)&buf[0], aom.id);
808 new_data.append(buf, 2);
810 new_data += serializeString(aom.datastring);
811 // Add data to buffer
813 reliable_data += new_data;
815 unreliable_data += new_data;
819 reliable_data and unreliable_data are now ready.
822 if(reliable_data.size() > 0) {
823 SendActiveObjectMessages(client->peer_id, reliable_data);
826 if(unreliable_data.size() > 0) {
827 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
832 // Clear buffered_messages
833 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
834 i = buffered_messages.begin();
835 i != buffered_messages.end(); ++i) {
841 Send queued-for-sending map edit events.
844 // We will be accessing the environment
845 MutexAutoLock lock(m_env_mutex);
847 // Don't send too many at a time
850 // Single change sending is disabled if queue size is not small
851 bool disable_single_change_sending = false;
852 if(m_unsent_map_edit_queue.size() >= 4)
853 disable_single_change_sending = true;
855 int event_count = m_unsent_map_edit_queue.size();
857 // We'll log the amount of each
860 while(m_unsent_map_edit_queue.size() != 0)
862 MapEditEvent* event = m_unsent_map_edit_queue.front();
863 m_unsent_map_edit_queue.pop();
865 // Players far away from the change are stored here.
866 // Instead of sending the changes, MapBlocks are set not sent
868 std::vector<u16> far_players;
870 switch (event->type) {
873 prof.add("MEET_ADDNODE", 1);
874 sendAddNode(event->p, event->n, event->already_known_by_peer,
875 &far_players, disable_single_change_sending ? 5 : 30,
876 event->type == MEET_ADDNODE);
878 case MEET_REMOVENODE:
879 prof.add("MEET_REMOVENODE", 1);
880 sendRemoveNode(event->p, event->already_known_by_peer,
881 &far_players, disable_single_change_sending ? 5 : 30);
883 case MEET_BLOCK_NODE_METADATA_CHANGED:
884 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
885 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
886 setBlockNotSent(event->p);
889 infostream << "Server: MEET_OTHER" << std::endl;
890 prof.add("MEET_OTHER", 1);
891 for(std::set<v3s16>::iterator
892 i = event->modified_blocks.begin();
893 i != event->modified_blocks.end(); ++i) {
898 prof.add("unknown", 1);
899 warningstream << "Server: Unknown MapEditEvent "
900 << ((u32)event->type) << std::endl;
905 Set blocks not sent to far players
907 if(!far_players.empty()) {
908 // Convert list format to that wanted by SetBlocksNotSent
909 std::map<v3s16, MapBlock*> modified_blocks2;
910 for(std::set<v3s16>::iterator
911 i = event->modified_blocks.begin();
912 i != event->modified_blocks.end(); ++i) {
913 modified_blocks2[*i] =
914 m_env->getMap().getBlockNoCreateNoEx(*i);
917 // Set blocks not sent
918 for(std::vector<u16>::iterator
919 i = far_players.begin();
920 i != far_players.end(); ++i) {
921 if(RemoteClient *client = getClient(*i))
922 client->SetBlocksNotSent(modified_blocks2);
928 /*// Don't send too many at a time
930 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
934 if(event_count >= 5){
935 infostream<<"Server: MapEditEvents:"<<std::endl;
936 prof.print(infostream);
937 } else if(event_count != 0){
938 verbosestream<<"Server: MapEditEvents:"<<std::endl;
939 prof.print(verbosestream);
945 Trigger emergethread (it somehow gets to a non-triggered but
946 bysy state sometimes)
949 float &counter = m_emergethread_trigger_timer;
951 if (counter >= 2.0) {
954 m_emerge->startThreads();
958 // Save map, players and auth stuff
960 float &counter = m_savemap_timer;
962 static thread_local const float save_interval =
963 g_settings->getFloat("server_map_save_interval");
964 if (counter >= save_interval) {
966 MutexAutoLock lock(m_env_mutex);
968 ScopeProfiler sp(g_profiler, "Server: saving stuff");
971 if (m_banmanager->isModified()) {
972 m_banmanager->save();
975 // Save changed parts of map
976 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
979 m_env->saveLoadedPlayers();
981 // Save environment metadata
987 static const float shutdown_msg_times[] =
989 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
992 if (m_shutdown_timer > 0.0f) {
993 // Automated messages
994 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
995 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
996 // If shutdown timer matches an automessage, shot it
997 if (m_shutdown_timer > shutdown_msg_times[i] &&
998 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
999 std::wstringstream ws;
1001 ws << L"*** Server shutting down in "
1002 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1005 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1006 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1012 m_shutdown_timer -= dtime;
1013 if (m_shutdown_timer < 0.0f) {
1014 m_shutdown_timer = 0.0f;
1015 m_shutdown_requested = true;
1020 void Server::Receive()
1022 DSTACK(FUNCTION_NAME);
1023 SharedBuffer<u8> data;
1027 m_con.Receive(&pkt);
1028 peer_id = pkt.getPeerId();
1031 catch(con::InvalidIncomingDataException &e) {
1032 infostream<<"Server::Receive(): "
1033 "InvalidIncomingDataException: what()="
1034 <<e.what()<<std::endl;
1036 catch(SerializationError &e) {
1037 infostream<<"Server::Receive(): "
1038 "SerializationError: what()="
1039 <<e.what()<<std::endl;
1041 catch(ClientStateError &e) {
1042 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1043 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1044 L"Try reconnecting or updating your client");
1046 catch(con::PeerNotFoundException &e) {
1051 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1053 std::string playername = "";
1054 PlayerSAO *playersao = NULL;
1057 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1058 if (client != NULL) {
1059 playername = client->getName();
1060 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1062 } catch (std::exception &e) {
1068 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1070 // If failed, cancel
1071 if ((playersao == NULL) || (player == NULL)) {
1072 if (player && player->peer_id != 0) {
1073 actionstream << "Server: Failed to emerge player \"" << playername
1074 << "\" (player allocated to an another client)" << std::endl;
1075 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1076 L"name. If your client closed unexpectedly, try again in "
1079 errorstream << "Server: " << playername << ": Failed to emerge player"
1081 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1087 Send complete position information
1089 SendMovePlayer(peer_id);
1092 SendPlayerPrivileges(peer_id);
1094 // Send inventory formspec
1095 SendPlayerInventoryFormspec(peer_id);
1098 SendInventory(playersao);
1100 // Send HP or death screen
1101 if (playersao->isDead())
1102 SendDeathscreen(peer_id, false, v3f(0,0,0));
1104 SendPlayerHPOrDie(playersao);
1107 SendPlayerBreath(playersao);
1109 // Note things in chat if not in simple singleplayer mode
1110 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1111 // Send information about server to player in chat
1112 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1114 Address addr = getPeerAddress(player->peer_id);
1115 std::string ip_str = addr.serializeString();
1116 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1121 const std::vector<std::string> &names = m_clients.getPlayerNames();
1123 actionstream << player->getName() << " joins game. List of players: ";
1125 for (std::vector<std::string>::const_iterator i = names.begin();
1126 i != names.end(); ++i) {
1127 actionstream << *i << " ";
1130 actionstream << player->getName() <<std::endl;
1135 inline void Server::handleCommand(NetworkPacket* pkt)
1137 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1138 (this->*opHandle.handler)(pkt);
1141 void Server::ProcessData(NetworkPacket *pkt)
1143 DSTACK(FUNCTION_NAME);
1144 // Environment is locked first.
1145 MutexAutoLock envlock(m_env_mutex);
1147 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1148 u32 peer_id = pkt->getPeerId();
1151 Address address = getPeerAddress(peer_id);
1152 std::string addr_s = address.serializeString();
1154 if(m_banmanager->isIpBanned(addr_s)) {
1155 std::string ban_name = m_banmanager->getBanName(addr_s);
1156 infostream << "Server: A banned client tried to connect from "
1157 << addr_s << "; banned name was "
1158 << ban_name << std::endl;
1159 // This actually doesn't seem to transfer to the client
1160 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1161 + utf8_to_wide(ban_name));
1165 catch(con::PeerNotFoundException &e) {
1167 * no peer for this packet found
1168 * most common reason is peer timeout, e.g. peer didn't
1169 * respond for some time, your server was overloaded or
1172 infostream << "Server::ProcessData(): Canceling: peer "
1173 << peer_id << " not found" << std::endl;
1178 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1180 // Command must be handled into ToServerCommandHandler
1181 if (command >= TOSERVER_NUM_MSG_TYPES) {
1182 infostream << "Server: Ignoring unknown command "
1183 << command << std::endl;
1187 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1192 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1194 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1195 errorstream << "Server::ProcessData(): Cancelling: Peer"
1196 " serialization format invalid or not initialized."
1197 " Skipping incoming command=" << command << std::endl;
1201 /* Handle commands related to client startup */
1202 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1207 if (m_clients.getClientState(peer_id) < CS_Active) {
1208 if (command == TOSERVER_PLAYERPOS) return;
1210 errorstream << "Got packet command: " << command << " for peer id "
1211 << peer_id << " but client isn't active yet. Dropping packet "
1217 } catch (SendFailedException &e) {
1218 errorstream << "Server::ProcessData(): SendFailedException: "
1219 << "what=" << e.what()
1221 } catch (PacketError &e) {
1222 actionstream << "Server::ProcessData(): PacketError: "
1223 << "what=" << e.what()
1228 void Server::setTimeOfDay(u32 time)
1230 m_env->setTimeOfDay(time);
1231 m_time_of_day_send_timer = 0;
1234 void Server::onMapEditEvent(MapEditEvent *event)
1236 if(m_ignore_map_edit_events)
1238 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1240 MapEditEvent *e = event->clone();
1241 m_unsent_map_edit_queue.push(e);
1244 Inventory* Server::getInventory(const InventoryLocation &loc)
1247 case InventoryLocation::UNDEFINED:
1248 case InventoryLocation::CURRENT_PLAYER:
1250 case InventoryLocation::PLAYER:
1252 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1255 PlayerSAO *playersao = player->getPlayerSAO();
1258 return playersao->getInventory();
1261 case InventoryLocation::NODEMETA:
1263 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1266 return meta->getInventory();
1269 case InventoryLocation::DETACHED:
1271 if(m_detached_inventories.count(loc.name) == 0)
1273 return m_detached_inventories[loc.name];
1277 sanity_check(false); // abort
1282 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1285 case InventoryLocation::UNDEFINED:
1287 case InventoryLocation::PLAYER:
1292 RemotePlayer *player =
1293 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1298 PlayerSAO *playersao = player->getPlayerSAO();
1302 SendInventory(playersao);
1305 case InventoryLocation::NODEMETA:
1307 v3s16 blockpos = getNodeBlockPos(loc.p);
1309 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1311 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1313 setBlockNotSent(blockpos);
1316 case InventoryLocation::DETACHED:
1318 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1322 sanity_check(false); // abort
1327 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1329 std::vector<u16> clients = m_clients.getClientIDs();
1331 // Set the modified blocks unsent for all the clients
1332 for (std::vector<u16>::iterator i = clients.begin();
1333 i != clients.end(); ++i) {
1334 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1335 client->SetBlocksNotSent(block);
1340 void Server::peerAdded(con::Peer *peer)
1342 DSTACK(FUNCTION_NAME);
1343 verbosestream<<"Server::peerAdded(): peer->id="
1344 <<peer->id<<std::endl;
1347 c.type = con::PEER_ADDED;
1348 c.peer_id = peer->id;
1350 m_peer_change_queue.push(c);
1353 void Server::deletingPeer(con::Peer *peer, bool timeout)
1355 DSTACK(FUNCTION_NAME);
1356 verbosestream<<"Server::deletingPeer(): peer->id="
1357 <<peer->id<<", timeout="<<timeout<<std::endl;
1359 m_clients.event(peer->id, CSE_Disconnect);
1361 c.type = con::PEER_REMOVED;
1362 c.peer_id = peer->id;
1363 c.timeout = timeout;
1364 m_peer_change_queue.push(c);
1367 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1369 *retval = m_con.getPeerStat(peer_id,type);
1370 if (*retval == -1) return false;
1374 bool Server::getClientInfo(
1383 std::string* vers_string
1386 *state = m_clients.getClientState(peer_id);
1388 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1390 if (client == NULL) {
1395 *uptime = client->uptime();
1396 *ser_vers = client->serialization_version;
1397 *prot_vers = client->net_proto_version;
1399 *major = client->getMajor();
1400 *minor = client->getMinor();
1401 *patch = client->getPatch();
1402 *vers_string = client->getPatch();
1409 void Server::handlePeerChanges()
1411 while(m_peer_change_queue.size() > 0)
1413 con::PeerChange c = m_peer_change_queue.front();
1414 m_peer_change_queue.pop();
1416 verbosestream<<"Server: Handling peer change: "
1417 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1422 case con::PEER_ADDED:
1423 m_clients.CreateClient(c.peer_id);
1426 case con::PEER_REMOVED:
1427 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1431 FATAL_ERROR("Invalid peer change event received!");
1437 void Server::printToConsoleOnly(const std::string &text)
1440 m_admin_chat->outgoing_queue.push_back(
1441 new ChatEventChat("", utf8_to_wide(text)));
1443 std::cout << text << std::endl;
1447 void Server::Send(NetworkPacket* pkt)
1449 m_clients.send(pkt->getPeerId(),
1450 clientCommandFactoryTable[pkt->getCommand()].channel,
1452 clientCommandFactoryTable[pkt->getCommand()].reliable);
1455 void Server::SendMovement(u16 peer_id)
1457 DSTACK(FUNCTION_NAME);
1458 std::ostringstream os(std::ios_base::binary);
1460 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1462 pkt << g_settings->getFloat("movement_acceleration_default");
1463 pkt << g_settings->getFloat("movement_acceleration_air");
1464 pkt << g_settings->getFloat("movement_acceleration_fast");
1465 pkt << g_settings->getFloat("movement_speed_walk");
1466 pkt << g_settings->getFloat("movement_speed_crouch");
1467 pkt << g_settings->getFloat("movement_speed_fast");
1468 pkt << g_settings->getFloat("movement_speed_climb");
1469 pkt << g_settings->getFloat("movement_speed_jump");
1470 pkt << g_settings->getFloat("movement_liquid_fluidity");
1471 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1472 pkt << g_settings->getFloat("movement_liquid_sink");
1473 pkt << g_settings->getFloat("movement_gravity");
1478 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1480 if (!g_settings->getBool("enable_damage"))
1483 u16 peer_id = playersao->getPeerID();
1484 bool is_alive = playersao->getHP() > 0;
1487 SendPlayerHP(peer_id);
1492 void Server::SendHP(u16 peer_id, u8 hp)
1494 DSTACK(FUNCTION_NAME);
1496 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1501 void Server::SendBreath(u16 peer_id, u16 breath)
1503 DSTACK(FUNCTION_NAME);
1505 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1506 pkt << (u16) breath;
1510 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1511 const std::string &custom_reason, bool reconnect)
1513 assert(reason < SERVER_ACCESSDENIED_MAX);
1515 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1517 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1518 pkt << custom_reason;
1519 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1520 reason == SERVER_ACCESSDENIED_CRASH)
1521 pkt << custom_reason << (u8)reconnect;
1525 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1527 DSTACK(FUNCTION_NAME);
1529 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1534 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1535 v3f camera_point_target)
1537 DSTACK(FUNCTION_NAME);
1539 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1540 pkt << set_camera_point_target << camera_point_target;
1544 void Server::SendItemDef(u16 peer_id,
1545 IItemDefManager *itemdef, u16 protocol_version)
1547 DSTACK(FUNCTION_NAME);
1549 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1553 u32 length of the next item
1554 zlib-compressed serialized ItemDefManager
1556 std::ostringstream tmp_os(std::ios::binary);
1557 itemdef->serialize(tmp_os, protocol_version);
1558 std::ostringstream tmp_os2(std::ios::binary);
1559 compressZlib(tmp_os.str(), tmp_os2);
1560 pkt.putLongString(tmp_os2.str());
1563 verbosestream << "Server: Sending item definitions to id(" << peer_id
1564 << "): size=" << pkt.getSize() << std::endl;
1569 void Server::SendNodeDef(u16 peer_id,
1570 INodeDefManager *nodedef, u16 protocol_version)
1572 DSTACK(FUNCTION_NAME);
1574 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1578 u32 length of the next item
1579 zlib-compressed serialized NodeDefManager
1581 std::ostringstream tmp_os(std::ios::binary);
1582 nodedef->serialize(tmp_os, protocol_version);
1583 std::ostringstream tmp_os2(std::ios::binary);
1584 compressZlib(tmp_os.str(), tmp_os2);
1586 pkt.putLongString(tmp_os2.str());
1589 verbosestream << "Server: Sending node definitions to id(" << peer_id
1590 << "): size=" << pkt.getSize() << std::endl;
1596 Non-static send methods
1599 void Server::SendInventory(PlayerSAO* playerSAO)
1601 DSTACK(FUNCTION_NAME);
1603 UpdateCrafting(playerSAO->getPlayer());
1609 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1611 std::ostringstream os;
1612 playerSAO->getInventory()->serialize(os);
1614 std::string s = os.str();
1616 pkt.putRawString(s.c_str(), s.size());
1620 void Server::SendChatMessage(u16 peer_id, const ChatMessage &message)
1622 DSTACK(FUNCTION_NAME);
1624 NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
1625 legacypkt << message.message;
1627 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1629 u8 type = message.type;
1630 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1632 if (peer_id != PEER_ID_INEXISTENT) {
1633 RemotePlayer *player = m_env->getPlayer(peer_id);
1637 if (player->protocol_version < 35)
1642 m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
1646 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1647 const std::string &formname)
1649 DSTACK(FUNCTION_NAME);
1651 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1652 if (formspec == "" ){
1653 //the client should close the formspec
1654 pkt.putLongString("");
1656 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1663 // Spawns a particle on peer with peer_id
1664 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1665 v3f pos, v3f velocity, v3f acceleration,
1666 float expirationtime, float size, bool collisiondetection,
1667 bool collision_removal,
1668 bool vertical, const std::string &texture,
1669 const struct TileAnimationParams &animation, u8 glow)
1671 DSTACK(FUNCTION_NAME);
1672 static thread_local const float radius =
1673 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1675 if (peer_id == PEER_ID_INEXISTENT) {
1676 std::vector<u16> clients = m_clients.getClientIDs();
1678 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1679 RemotePlayer *player = m_env->getPlayer(*i);
1683 PlayerSAO *sao = player->getPlayerSAO();
1687 // Do not send to distant clients
1688 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1691 SendSpawnParticle(*i, player->protocol_version,
1692 pos, velocity, acceleration,
1693 expirationtime, size, collisiondetection,
1694 collision_removal, vertical, texture, animation, glow);
1699 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1701 pkt << pos << velocity << acceleration << expirationtime
1702 << size << collisiondetection;
1703 pkt.putLongString(texture);
1705 pkt << collision_removal;
1706 // This is horrible but required (why are there two ways to serialize pkts?)
1707 std::ostringstream os(std::ios_base::binary);
1708 animation.serialize(os, protocol_version);
1709 pkt.putRawString(os.str());
1715 // Adds a ParticleSpawner on peer with peer_id
1716 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1717 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1718 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1719 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1720 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1721 const struct TileAnimationParams &animation, u8 glow)
1723 DSTACK(FUNCTION_NAME);
1724 if (peer_id == PEER_ID_INEXISTENT) {
1725 // This sucks and should be replaced:
1726 std::vector<u16> clients = m_clients.getClientIDs();
1727 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1728 RemotePlayer *player = m_env->getPlayer(*i);
1731 SendAddParticleSpawner(*i, player->protocol_version,
1732 amount, spawntime, minpos, maxpos,
1733 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1734 minsize, maxsize, collisiondetection, collision_removal,
1735 attached_id, vertical, texture, id, animation, glow);
1740 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1742 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1743 << minacc << maxacc << minexptime << maxexptime << minsize
1744 << maxsize << collisiondetection;
1746 pkt.putLongString(texture);
1748 pkt << id << vertical;
1749 pkt << collision_removal;
1751 // This is horrible but required
1752 std::ostringstream os(std::ios_base::binary);
1753 animation.serialize(os, protocol_version);
1754 pkt.putRawString(os.str());
1760 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1762 DSTACK(FUNCTION_NAME);
1764 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1766 // Ugly error in this packet
1769 if (peer_id != PEER_ID_INEXISTENT) {
1773 m_clients.sendToAll(&pkt);
1778 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1780 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1782 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1783 << form->text << form->number << form->item << form->dir
1784 << form->align << form->offset << form->world_pos << form->size;
1789 void Server::SendHUDRemove(u16 peer_id, u32 id)
1791 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1796 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1798 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1799 pkt << id << (u8) stat;
1803 case HUD_STAT_SCALE:
1804 case HUD_STAT_ALIGN:
1805 case HUD_STAT_OFFSET:
1806 pkt << *(v2f *) value;
1810 pkt << *(std::string *) value;
1812 case HUD_STAT_WORLD_POS:
1813 pkt << *(v3f *) value;
1816 pkt << *(v2s32 *) value;
1818 case HUD_STAT_NUMBER:
1822 pkt << *(u32 *) value;
1829 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1831 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1833 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1835 pkt << flags << mask;
1840 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1842 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1843 pkt << param << value;
1847 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1848 const std::string &type, const std::vector<std::string> ¶ms,
1851 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1852 pkt << bgcolor << type << (u16) params.size();
1854 for(size_t i=0; i<params.size(); i++)
1862 void Server::SendCloudParams(u16 peer_id, float density,
1863 const video::SColor &color_bright,
1864 const video::SColor &color_ambient,
1869 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1870 pkt << density << color_bright << color_ambient
1871 << height << thickness << speed;
1876 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1879 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1882 pkt << do_override << (u16) (ratio * 65535);
1887 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1889 DSTACK(FUNCTION_NAME);
1891 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1892 pkt << time << time_speed;
1894 if (peer_id == PEER_ID_INEXISTENT) {
1895 m_clients.sendToAll(&pkt);
1902 void Server::SendPlayerHP(u16 peer_id)
1904 DSTACK(FUNCTION_NAME);
1905 PlayerSAO *playersao = getPlayerSAO(peer_id);
1906 // In some rare case if the player is disconnected
1907 // while Lua call l_punch, for example, this can be NULL
1911 SendHP(peer_id, playersao->getHP());
1912 m_script->player_event(playersao,"health_changed");
1914 // Send to other clients
1915 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1916 ActiveObjectMessage aom(playersao->getId(), true, str);
1917 playersao->m_messages_out.push(aom);
1920 void Server::SendPlayerBreath(PlayerSAO *sao)
1922 DSTACK(FUNCTION_NAME);
1925 m_script->player_event(sao, "breath_changed");
1926 SendBreath(sao->getPeerID(), sao->getBreath());
1929 void Server::SendMovePlayer(u16 peer_id)
1931 DSTACK(FUNCTION_NAME);
1932 RemotePlayer *player = m_env->getPlayer(peer_id);
1934 PlayerSAO *sao = player->getPlayerSAO();
1937 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1938 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1941 v3f pos = sao->getBasePosition();
1942 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1943 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1944 << " pitch=" << sao->getPitch()
1945 << " yaw=" << sao->getYaw()
1952 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1954 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1957 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1958 << animation_frames[3] << animation_speed;
1963 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1965 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1966 pkt << first << third;
1969 void Server::SendPlayerPrivileges(u16 peer_id)
1971 RemotePlayer *player = m_env->getPlayer(peer_id);
1973 if(player->peer_id == PEER_ID_INEXISTENT)
1976 std::set<std::string> privs;
1977 m_script->getAuth(player->getName(), NULL, &privs);
1979 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1980 pkt << (u16) privs.size();
1982 for(std::set<std::string>::const_iterator i = privs.begin();
1983 i != privs.end(); ++i) {
1990 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1992 RemotePlayer *player = m_env->getPlayer(peer_id);
1994 if(player->peer_id == PEER_ID_INEXISTENT)
1997 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1998 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2002 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2004 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2005 pkt.putRawString(datas.c_str(), datas.size());
2007 return pkt.getSize();
2010 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2012 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2013 datas.size(), peer_id);
2015 pkt.putRawString(datas.c_str(), datas.size());
2017 m_clients.send(pkt.getPeerId(),
2018 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2023 s32 Server::playSound(const SimpleSoundSpec &spec,
2024 const ServerSoundParams ¶ms)
2026 // Find out initial position of sound
2027 bool pos_exists = false;
2028 v3f pos = params.getPos(m_env, &pos_exists);
2029 // If position is not found while it should be, cancel sound
2030 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2033 // Filter destination clients
2034 std::vector<u16> dst_clients;
2035 if(params.to_player != "")
2037 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2039 infostream<<"Server::playSound: Player \""<<params.to_player
2040 <<"\" not found"<<std::endl;
2043 if(player->peer_id == PEER_ID_INEXISTENT){
2044 infostream<<"Server::playSound: Player \""<<params.to_player
2045 <<"\" not connected"<<std::endl;
2048 dst_clients.push_back(player->peer_id);
2051 std::vector<u16> clients = m_clients.getClientIDs();
2053 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2054 RemotePlayer *player = m_env->getPlayer(*i);
2058 PlayerSAO *sao = player->getPlayerSAO();
2063 if(sao->getBasePosition().getDistanceFrom(pos) >
2064 params.max_hear_distance)
2067 dst_clients.push_back(*i);
2071 if(dst_clients.empty())
2075 s32 id = m_next_sound_id++;
2076 // The sound will exist as a reference in m_playing_sounds
2077 m_playing_sounds[id] = ServerPlayingSound();
2078 ServerPlayingSound &psound = m_playing_sounds[id];
2079 psound.params = params;
2082 float gain = params.gain * spec.gain;
2083 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2084 pkt << id << spec.name << gain
2085 << (u8) params.type << pos << params.object
2086 << params.loop << params.fade << params.pitch;
2088 // Backwards compability
2089 bool play_sound = gain > 0;
2091 for (std::vector<u16>::iterator i = dst_clients.begin();
2092 i != dst_clients.end(); ++i) {
2093 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2094 psound.clients.insert(*i);
2095 m_clients.send(*i, 0, &pkt, true);
2100 void Server::stopSound(s32 handle)
2102 // Get sound reference
2103 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2104 m_playing_sounds.find(handle);
2105 if (i == m_playing_sounds.end())
2107 ServerPlayingSound &psound = i->second;
2109 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2112 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2113 si != psound.clients.end(); ++si) {
2115 m_clients.send(*si, 0, &pkt, true);
2117 // Remove sound reference
2118 m_playing_sounds.erase(i);
2121 void Server::fadeSound(s32 handle, float step, float gain)
2123 // Get sound reference
2124 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2125 m_playing_sounds.find(handle);
2126 if (i == m_playing_sounds.end())
2129 ServerPlayingSound &psound = i->second;
2130 psound.params.gain = gain;
2132 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2133 pkt << handle << step << gain;
2135 // Backwards compability
2136 bool play_sound = gain > 0;
2137 ServerPlayingSound compat_psound = psound;
2138 compat_psound.clients.clear();
2140 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2141 compat_pkt << handle;
2143 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2144 it != psound.clients.end();) {
2145 if (m_clients.getProtocolVersion(*it) >= 32) {
2147 m_clients.send(*it, 0, &pkt, true);
2150 compat_psound.clients.insert(*it);
2152 m_clients.send(*it, 0, &compat_pkt, true);
2153 psound.clients.erase(it++);
2157 // Remove sound reference
2158 if (!play_sound || psound.clients.size() == 0)
2159 m_playing_sounds.erase(i);
2161 if (play_sound && compat_psound.clients.size() > 0) {
2162 // Play new sound volume on older clients
2163 playSound(compat_psound.spec, compat_psound.params);
2167 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2168 std::vector<u16> *far_players, float far_d_nodes)
2170 float maxd = far_d_nodes*BS;
2171 v3f p_f = intToFloat(p, BS);
2173 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2176 std::vector<u16> clients = m_clients.getClientIDs();
2177 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2180 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2181 PlayerSAO *sao = player->getPlayerSAO();
2185 // If player is far away, only set modified blocks not sent
2186 v3f player_pos = sao->getBasePosition();
2187 if (player_pos.getDistanceFrom(p_f) > maxd) {
2188 far_players->push_back(*i);
2195 m_clients.send(*i, 0, &pkt, true);
2199 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2200 std::vector<u16> *far_players, float far_d_nodes,
2201 bool remove_metadata)
2203 float maxd = far_d_nodes*BS;
2204 v3f p_f = intToFloat(p, BS);
2206 std::vector<u16> clients = m_clients.getClientIDs();
2207 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2210 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2211 PlayerSAO *sao = player->getPlayerSAO();
2215 // If player is far away, only set modified blocks not sent
2216 v3f player_pos = sao->getBasePosition();
2217 if(player_pos.getDistanceFrom(p_f) > maxd) {
2218 far_players->push_back(*i);
2224 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2226 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2228 pkt << p << n.param0 << n.param1 << n.param2
2229 << (u8) (remove_metadata ? 0 : 1);
2234 if (pkt.getSize() > 0)
2235 m_clients.send(*i, 0, &pkt, true);
2239 void Server::setBlockNotSent(v3s16 p)
2241 std::vector<u16> clients = m_clients.getClientIDs();
2243 for(std::vector<u16>::iterator i = clients.begin();
2244 i != clients.end(); ++i) {
2245 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2246 client->SetBlockNotSent(p);
2251 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2253 DSTACK(FUNCTION_NAME);
2255 v3s16 p = block->getPos();
2258 Create a packet with the block in the right format
2261 std::ostringstream os(std::ios_base::binary);
2262 block->serialize(os, ver, false);
2263 block->serializeNetworkSpecific(os);
2264 std::string s = os.str();
2266 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2269 pkt.putRawString(s.c_str(), s.size());
2273 void Server::SendBlocks(float dtime)
2275 DSTACK(FUNCTION_NAME);
2277 MutexAutoLock envlock(m_env_mutex);
2278 //TODO check if one big lock could be faster then multiple small ones
2280 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2282 std::vector<PrioritySortedBlockTransfer> queue;
2284 s32 total_sending = 0;
2287 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2289 std::vector<u16> clients = m_clients.getClientIDs();
2292 for(std::vector<u16>::iterator i = clients.begin();
2293 i != clients.end(); ++i) {
2294 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2299 total_sending += client->SendingCount();
2300 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2306 // Lowest priority number comes first.
2307 // Lowest is most important.
2308 std::sort(queue.begin(), queue.end());
2311 for(u32 i=0; i<queue.size(); i++)
2313 //TODO: Calculate limit dynamically
2314 if(total_sending >= g_settings->getS32
2315 ("max_simultaneous_block_sends_server_total"))
2318 PrioritySortedBlockTransfer q = queue[i];
2320 MapBlock *block = NULL;
2323 block = m_env->getMap().getBlockNoCreate(q.pos);
2325 catch(InvalidPositionException &e)
2330 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2335 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2337 client->SentBlock(q.pos);
2343 void Server::fillMediaCache()
2345 DSTACK(FUNCTION_NAME);
2347 infostream<<"Server: Calculating media file checksums"<<std::endl;
2349 // Collect all media file paths
2350 std::vector<std::string> paths;
2351 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2352 i != m_mods.end(); ++i) {
2353 const ModSpec &mod = *i;
2354 paths.push_back(mod.path + DIR_DELIM + "textures");
2355 paths.push_back(mod.path + DIR_DELIM + "sounds");
2356 paths.push_back(mod.path + DIR_DELIM + "media");
2357 paths.push_back(mod.path + DIR_DELIM + "models");
2359 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2361 // Collect media file information from paths into cache
2362 for(std::vector<std::string>::iterator i = paths.begin();
2363 i != paths.end(); ++i) {
2364 std::string mediapath = *i;
2365 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2366 for (u32 j = 0; j < dirlist.size(); j++) {
2367 if (dirlist[j].dir) // Ignode dirs
2369 std::string filename = dirlist[j].name;
2370 // If name contains illegal characters, ignore the file
2371 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2372 infostream<<"Server: ignoring illegal file name: \""
2373 << filename << "\"" << std::endl;
2376 // If name is not in a supported format, ignore it
2377 const char *supported_ext[] = {
2378 ".png", ".jpg", ".bmp", ".tga",
2379 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2381 ".x", ".b3d", ".md2", ".obj",
2384 if (removeStringEnd(filename, supported_ext) == ""){
2385 infostream << "Server: ignoring unsupported file extension: \""
2386 << filename << "\"" << std::endl;
2389 // Ok, attempt to load the file and add to cache
2390 std::string filepath = mediapath + DIR_DELIM + filename;
2392 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2394 errorstream << "Server::fillMediaCache(): Could not open \""
2395 << filename << "\" for reading" << std::endl;
2398 std::ostringstream tmp_os(std::ios_base::binary);
2402 fis.read(buf, 1024);
2403 std::streamsize len = fis.gcount();
2404 tmp_os.write(buf, len);
2413 errorstream<<"Server::fillMediaCache(): Failed to read \""
2414 << filename << "\"" << std::endl;
2417 if(tmp_os.str().length() == 0) {
2418 errorstream << "Server::fillMediaCache(): Empty file \""
2419 << filepath << "\"" << std::endl;
2424 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2426 unsigned char *digest = sha1.getDigest();
2427 std::string sha1_base64 = base64_encode(digest, 20);
2428 std::string sha1_hex = hex_encode((char*)digest, 20);
2432 m_media[filename] = MediaInfo(filepath, sha1_base64);
2433 verbosestream << "Server: " << sha1_hex << " is " << filename
2439 void Server::sendMediaAnnouncement(u16 peer_id)
2441 DSTACK(FUNCTION_NAME);
2443 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2447 std::ostringstream os(std::ios_base::binary);
2449 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2450 pkt << (u16) m_media.size();
2452 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2453 i != m_media.end(); ++i) {
2454 pkt << i->first << i->second.sha1_digest;
2457 pkt << g_settings->get("remote_media");
2461 struct SendableMedia
2467 SendableMedia(const std::string &name_="", const std::string &path_="",
2468 const std::string &data_=""):
2475 void Server::sendRequestedMedia(u16 peer_id,
2476 const std::vector<std::string> &tosend)
2478 DSTACK(FUNCTION_NAME);
2480 verbosestream<<"Server::sendRequestedMedia(): "
2481 <<"Sending files to client"<<std::endl;
2485 // Put 5kB in one bunch (this is not accurate)
2486 u32 bytes_per_bunch = 5000;
2488 std::vector< std::vector<SendableMedia> > file_bunches;
2489 file_bunches.push_back(std::vector<SendableMedia>());
2491 u32 file_size_bunch_total = 0;
2493 for(std::vector<std::string>::const_iterator i = tosend.begin();
2494 i != tosend.end(); ++i) {
2495 const std::string &name = *i;
2497 if (m_media.find(name) == m_media.end()) {
2498 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2499 <<"unknown file \""<<(name)<<"\""<<std::endl;
2503 //TODO get path + name
2504 std::string tpath = m_media[name].path;
2507 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2508 if(fis.good() == false){
2509 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2510 <<tpath<<"\" for reading"<<std::endl;
2513 std::ostringstream tmp_os(std::ios_base::binary);
2517 fis.read(buf, 1024);
2518 std::streamsize len = fis.gcount();
2519 tmp_os.write(buf, len);
2520 file_size_bunch_total += len;
2529 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2530 <<name<<"\""<<std::endl;
2533 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2534 <<tname<<"\""<<std::endl;*/
2536 file_bunches[file_bunches.size()-1].push_back(
2537 SendableMedia(name, tpath, tmp_os.str()));
2539 // Start next bunch if got enough data
2540 if(file_size_bunch_total >= bytes_per_bunch) {
2541 file_bunches.push_back(std::vector<SendableMedia>());
2542 file_size_bunch_total = 0;
2547 /* Create and send packets */
2549 u16 num_bunches = file_bunches.size();
2550 for(u16 i = 0; i < num_bunches; i++) {
2553 u16 total number of texture bunches
2554 u16 index of this bunch
2555 u32 number of files in this bunch
2564 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2565 pkt << num_bunches << i << (u32) file_bunches[i].size();
2567 for(std::vector<SendableMedia>::iterator
2568 j = file_bunches[i].begin();
2569 j != file_bunches[i].end(); ++j) {
2571 pkt.putLongString(j->data);
2574 verbosestream << "Server::sendRequestedMedia(): bunch "
2575 << i << "/" << num_bunches
2576 << " files=" << file_bunches[i].size()
2577 << " size=" << pkt.getSize() << std::endl;
2582 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2584 if(m_detached_inventories.count(name) == 0) {
2585 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2588 Inventory *inv = m_detached_inventories[name];
2589 std::ostringstream os(std::ios_base::binary);
2591 os << serializeString(name);
2595 std::string s = os.str();
2597 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2598 pkt.putRawString(s.c_str(), s.size());
2600 const std::string &check = m_detached_inventories_player[name];
2601 if (peer_id == PEER_ID_INEXISTENT) {
2603 return m_clients.sendToAll(&pkt);
2604 RemotePlayer *p = m_env->getPlayer(check.c_str());
2606 m_clients.send(p->peer_id, 0, &pkt, true);
2608 if (check == "" || getPlayerName(peer_id) == check)
2613 void Server::sendDetachedInventories(u16 peer_id)
2615 DSTACK(FUNCTION_NAME);
2617 for(std::map<std::string, Inventory*>::iterator
2618 i = m_detached_inventories.begin();
2619 i != m_detached_inventories.end(); ++i) {
2620 const std::string &name = i->first;
2621 //Inventory *inv = i->second;
2622 sendDetachedInventory(name, peer_id);
2630 void Server::DiePlayer(u16 peer_id)
2632 DSTACK(FUNCTION_NAME);
2633 PlayerSAO *playersao = getPlayerSAO(peer_id);
2634 // In some rare cases this can be NULL -- if the player is disconnected
2635 // when a Lua function modifies l_punch, for example
2639 infostream << "Server::DiePlayer(): Player "
2640 << playersao->getPlayer()->getName()
2641 << " dies" << std::endl;
2643 playersao->setHP(0);
2645 // Trigger scripted stuff
2646 m_script->on_dieplayer(playersao);
2648 SendPlayerHP(peer_id);
2649 SendDeathscreen(peer_id, false, v3f(0,0,0));
2652 void Server::RespawnPlayer(u16 peer_id)
2654 DSTACK(FUNCTION_NAME);
2656 PlayerSAO *playersao = getPlayerSAO(peer_id);
2659 infostream << "Server::RespawnPlayer(): Player "
2660 << playersao->getPlayer()->getName()
2661 << " respawns" << std::endl;
2663 playersao->setHP(PLAYER_MAX_HP);
2664 playersao->setBreath(PLAYER_MAX_BREATH);
2666 bool repositioned = m_script->on_respawnplayer(playersao);
2667 if (!repositioned) {
2668 // setPos will send the new position to client
2669 playersao->setPos(findSpawnPos());
2672 SendPlayerHP(peer_id);
2676 void Server::DenySudoAccess(u16 peer_id)
2678 DSTACK(FUNCTION_NAME);
2680 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2685 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2686 const std::string &str_reason, bool reconnect)
2688 if (proto_ver >= 25) {
2689 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2691 std::wstring wreason = utf8_to_wide(
2692 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2693 accessDeniedStrings[(u8)reason]);
2694 SendAccessDenied_Legacy(peer_id, wreason);
2697 m_clients.event(peer_id, CSE_SetDenied);
2698 m_con.DisconnectPeer(peer_id);
2702 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2704 DSTACK(FUNCTION_NAME);
2706 SendAccessDenied(peer_id, reason, custom_reason);
2707 m_clients.event(peer_id, CSE_SetDenied);
2708 m_con.DisconnectPeer(peer_id);
2711 // 13/03/15: remove this function when protocol version 25 will become
2712 // the minimum version for MT users, maybe in 1 year
2713 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2715 DSTACK(FUNCTION_NAME);
2717 SendAccessDenied_Legacy(peer_id, reason);
2718 m_clients.event(peer_id, CSE_SetDenied);
2719 m_con.DisconnectPeer(peer_id);
2722 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2724 DSTACK(FUNCTION_NAME);
2727 RemoteClient* client = getClient(peer_id, CS_Invalid);
2729 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2731 // Right now, the auth mechs don't change between login and sudo mode.
2732 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2733 client->allowed_sudo_mechs = sudo_auth_mechs;
2735 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2736 << g_settings->getFloat("dedicated_server_step")
2740 m_clients.event(peer_id, CSE_AuthAccept);
2742 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2744 // We only support SRP right now
2745 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2747 resp_pkt << sudo_auth_mechs;
2749 m_clients.event(peer_id, CSE_SudoSuccess);
2753 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2755 DSTACK(FUNCTION_NAME);
2756 std::wstring message;
2759 Clear references to playing sounds
2761 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2762 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2763 ServerPlayingSound &psound = i->second;
2764 psound.clients.erase(peer_id);
2765 if (psound.clients.empty())
2766 m_playing_sounds.erase(i++);
2771 RemotePlayer *player = m_env->getPlayer(peer_id);
2773 /* Run scripts and remove from environment */
2774 if (player != NULL) {
2775 PlayerSAO *playersao = player->getPlayerSAO();
2778 // inform connected clients
2779 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2780 // (u16) 1 + std::string represents a vector serialization representation
2781 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2782 m_clients.sendToAll(¬ice);
2784 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2786 playersao->disconnected();
2793 if(player != NULL && reason != CDR_DENY) {
2794 std::ostringstream os(std::ios_base::binary);
2795 std::vector<u16> clients = m_clients.getClientIDs();
2797 for(std::vector<u16>::iterator i = clients.begin();
2798 i != clients.end(); ++i) {
2800 RemotePlayer *player = m_env->getPlayer(*i);
2804 // Get name of player
2805 os << player->getName() << " ";
2808 std::string name = player->getName();
2809 actionstream << name << " "
2810 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2811 << " List of players: " << os.str() << std::endl;
2813 m_admin_chat->outgoing_queue.push_back(
2814 new ChatEventNick(CET_NICK_REMOVE, name));
2818 MutexAutoLock env_lock(m_env_mutex);
2819 m_clients.DeleteClient(peer_id);
2823 // Send leave chat message to all remaining clients
2824 if (!message.empty()) {
2825 SendChatMessage(PEER_ID_INEXISTENT,
2826 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2830 void Server::UpdateCrafting(RemotePlayer *player)
2832 DSTACK(FUNCTION_NAME);
2834 // Get a preview for crafting
2836 InventoryLocation loc;
2837 loc.setPlayer(player->getName());
2838 std::vector<ItemStack> output_replacements;
2839 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2840 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2841 (&player->inventory)->getList("craft"), loc);
2843 // Put the new preview in
2844 InventoryList *plist = player->inventory.getList("craftpreview");
2845 sanity_check(plist);
2846 sanity_check(plist->getSize() >= 1);
2847 plist->changeItem(0, preview);
2850 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2852 if (evt->type == CET_NICK_ADD) {
2853 // The terminal informed us of its nick choice
2854 m_admin_nick = ((ChatEventNick *)evt)->nick;
2855 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2856 errorstream << "You haven't set up an account." << std::endl
2857 << "Please log in using the client as '"
2858 << m_admin_nick << "' with a secure password." << std::endl
2859 << "Until then, you can't execute admin tasks via the console," << std::endl
2860 << "and everybody can claim the user account instead of you," << std::endl
2861 << "giving them full control over this server." << std::endl;
2864 assert(evt->type == CET_CHAT);
2865 handleAdminChat((ChatEventChat *)evt);
2869 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2870 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2872 // If something goes wrong, this player is to blame
2873 RollbackScopeActor rollback_scope(m_rollback,
2874 std::string("player:") + name);
2876 if (g_settings->getBool("strip_color_codes"))
2877 wmessage = unescape_enriched(wmessage);
2880 switch (player->canSendChatMessage()) {
2881 case RPLAYER_CHATRESULT_FLOODING: {
2882 std::wstringstream ws;
2883 ws << L"You cannot send more messages. You are limited to "
2884 << g_settings->getFloat("chat_message_limit_per_10sec")
2885 << L" messages per 10 seconds.";
2888 case RPLAYER_CHATRESULT_KICK:
2889 DenyAccess_Legacy(player->peer_id,
2890 L"You have been kicked due to message flooding.");
2892 case RPLAYER_CHATRESULT_OK:
2895 FATAL_ERROR("Unhandled chat filtering result found.");
2899 if (m_max_chatmessage_length > 0
2900 && wmessage.length() > m_max_chatmessage_length) {
2901 return L"Your message exceed the maximum chat message limit set on the server. "
2902 L"It was refused. Send a shorter message";
2905 // Run script hook, exit if script ate the chat message
2906 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2911 // Whether to send line to the player that sent the message, or to all players
2912 bool broadcast_line = true;
2914 if (check_shout_priv && !checkPriv(name, "shout")) {
2915 line += L"-!- You don't have permission to shout.";
2916 broadcast_line = false;
2925 Tell calling method to send the message to sender
2927 if (!broadcast_line) {
2931 Send the message to others
2933 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2935 std::vector<u16> clients = m_clients.getClientIDs();
2938 Send the message back to the inital sender
2939 if they are using protocol version >= 29
2942 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2943 if (player && player->protocol_version >= 29)
2944 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2946 for (u16 i = 0; i < clients.size(); i++) {
2947 u16 cid = clients[i];
2948 if (cid != peer_id_to_avoid_sending)
2949 SendChatMessage(cid, ChatMessage(line));
2955 void Server::handleAdminChat(const ChatEventChat *evt)
2957 std::string name = evt->nick;
2958 std::wstring wname = utf8_to_wide(name);
2959 std::wstring wmessage = evt->evt_msg;
2961 std::wstring answer = handleChat(name, wname, wmessage);
2963 // If asked to send answer to sender
2964 if (!answer.empty()) {
2965 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2969 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2971 RemoteClient *client = getClientNoEx(peer_id,state_min);
2973 throw ClientNotFoundException("Client not found");
2977 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2979 return m_clients.getClientNoEx(peer_id, state_min);
2982 std::string Server::getPlayerName(u16 peer_id)
2984 RemotePlayer *player = m_env->getPlayer(peer_id);
2986 return "[id="+itos(peer_id)+"]";
2987 return player->getName();
2990 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2992 RemotePlayer *player = m_env->getPlayer(peer_id);
2995 return player->getPlayerSAO();
2998 std::wstring Server::getStatusString()
3000 std::wostringstream os(std::ios_base::binary);
3003 os<<L"version="<<narrow_to_wide(g_version_string);
3005 os<<L", uptime="<<m_uptime.get();
3007 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3008 // Information about clients
3011 std::vector<u16> clients = m_clients.getClientIDs();
3012 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3014 RemotePlayer *player = m_env->getPlayer(*i);
3015 // Get name of player
3016 std::wstring name = L"unknown";
3018 name = narrow_to_wide(player->getName());
3019 // Add name to information string
3027 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3028 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3029 if(g_settings->get("motd") != "")
3030 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3034 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3036 std::set<std::string> privs;
3037 m_script->getAuth(name, NULL, &privs);
3041 bool Server::checkPriv(const std::string &name, const std::string &priv)
3043 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3044 return (privs.count(priv) != 0);
3047 void Server::reportPrivsModified(const std::string &name)
3050 std::vector<u16> clients = m_clients.getClientIDs();
3051 for(std::vector<u16>::iterator i = clients.begin();
3052 i != clients.end(); ++i) {
3053 RemotePlayer *player = m_env->getPlayer(*i);
3054 reportPrivsModified(player->getName());
3057 RemotePlayer *player = m_env->getPlayer(name.c_str());
3060 SendPlayerPrivileges(player->peer_id);
3061 PlayerSAO *sao = player->getPlayerSAO();
3064 sao->updatePrivileges(
3065 getPlayerEffectivePrivs(name),
3070 void Server::reportInventoryFormspecModified(const std::string &name)
3072 RemotePlayer *player = m_env->getPlayer(name.c_str());
3075 SendPlayerInventoryFormspec(player->peer_id);
3078 void Server::setIpBanned(const std::string &ip, const std::string &name)
3080 m_banmanager->add(ip, name);
3083 void Server::unsetIpBanned(const std::string &ip_or_name)
3085 m_banmanager->remove(ip_or_name);
3088 std::string Server::getBanDescription(const std::string &ip_or_name)
3090 return m_banmanager->getBanDescription(ip_or_name);
3093 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3095 // m_env will be NULL if the server is initializing
3099 if (m_admin_nick == name && !m_admin_nick.empty()) {
3100 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3103 RemotePlayer *player = m_env->getPlayer(name);
3108 if (player->peer_id == PEER_ID_INEXISTENT)
3111 SendChatMessage(player->peer_id, ChatMessage(msg));
3114 bool Server::showFormspec(const char *playername, const std::string &formspec,
3115 const std::string &formname)
3117 // m_env will be NULL if the server is initializing
3121 RemotePlayer *player = m_env->getPlayer(playername);
3125 SendShowFormspecMessage(player->peer_id, formspec, formname);
3129 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3134 u32 id = player->addHud(form);
3136 SendHUDAdd(player->peer_id, id, form);
3141 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3145 HudElement* todel = player->removeHud(id);
3152 SendHUDRemove(player->peer_id, id);
3156 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3161 SendHUDChange(player->peer_id, id, stat, data);
3165 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3170 SendHUDSetFlags(player->peer_id, flags, mask);
3171 player->hud_flags &= ~mask;
3172 player->hud_flags |= flags;
3174 PlayerSAO* playersao = player->getPlayerSAO();
3176 if (playersao == NULL)
3179 m_script->player_event(playersao, "hud_changed");
3183 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3188 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3191 player->setHotbarItemcount(hotbar_itemcount);
3192 std::ostringstream os(std::ios::binary);
3193 writeS32(os, hotbar_itemcount);
3194 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3198 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3203 player->setHotbarImage(name);
3204 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3207 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3211 return player->getHotbarImage();
3214 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3219 player->setHotbarSelectedImage(name);
3220 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3223 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3224 v2s32 animation_frames[4], f32 frame_speed)
3229 player->setLocalAnimations(animation_frames, frame_speed);
3230 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3234 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3239 player->eye_offset_first = first;
3240 player->eye_offset_third = third;
3241 SendEyeOffset(player->peer_id, first, third);
3245 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3246 const std::string &type, const std::vector<std::string> ¶ms,
3252 player->setSky(bgcolor, type, params, clouds);
3253 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3257 bool Server::setClouds(RemotePlayer *player, float density,
3258 const video::SColor &color_bright,
3259 const video::SColor &color_ambient,
3267 SendCloudParams(player->peer_id, density,
3268 color_bright, color_ambient, height,
3273 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3279 player->overrideDayNightRatio(do_override, ratio);
3280 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3284 void Server::notifyPlayers(const std::wstring &msg)
3286 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3289 void Server::spawnParticle(const std::string &playername, v3f pos,
3290 v3f velocity, v3f acceleration,
3291 float expirationtime, float size, bool
3292 collisiondetection, bool collision_removal,
3293 bool vertical, const std::string &texture,
3294 const struct TileAnimationParams &animation, u8 glow)
3296 // m_env will be NULL if the server is initializing
3300 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3301 if (playername != "") {
3302 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3305 peer_id = player->peer_id;
3306 proto_ver = player->protocol_version;
3309 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3310 expirationtime, size, collisiondetection,
3311 collision_removal, vertical, texture, animation, glow);
3314 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3315 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3316 float minexptime, float maxexptime, float minsize, float maxsize,
3317 bool collisiondetection, bool collision_removal,
3318 ServerActiveObject *attached, bool vertical, const std::string &texture,
3319 const std::string &playername, const struct TileAnimationParams &animation,
3322 // m_env will be NULL if the server is initializing
3326 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3327 if (playername != "") {
3328 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3331 peer_id = player->peer_id;
3332 proto_ver = player->protocol_version;
3335 u16 attached_id = attached ? attached->getId() : 0;
3338 if (attached_id == 0)
3339 id = m_env->addParticleSpawner(spawntime);
3341 id = m_env->addParticleSpawner(spawntime, attached_id);
3343 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3344 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3345 minexptime, maxexptime, minsize, maxsize,
3346 collisiondetection, collision_removal, attached_id, vertical,
3347 texture, id, animation, glow);
3352 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3354 // m_env will be NULL if the server is initializing
3356 throw ServerError("Can't delete particle spawners during initialisation!");
3358 u16 peer_id = PEER_ID_INEXISTENT;
3359 if (playername != "") {
3360 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3363 peer_id = player->peer_id;
3366 m_env->deleteParticleSpawner(id);
3367 SendDeleteParticleSpawner(peer_id, id);
3370 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3372 if(m_detached_inventories.count(name) > 0){
3373 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3374 delete m_detached_inventories[name];
3376 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3378 Inventory *inv = new Inventory(m_itemdef);
3380 m_detached_inventories[name] = inv;
3381 m_detached_inventories_player[name] = player;
3382 //TODO find a better way to do this
3383 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3387 // actions: time-reversed list
3388 // Return value: success/failure
3389 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3390 std::list<std::string> *log)
3392 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3393 ServerMap *map = (ServerMap*)(&m_env->getMap());
3395 // Fail if no actions to handle
3396 if(actions.empty()){
3397 log->push_back("Nothing to do.");
3404 for(std::list<RollbackAction>::const_iterator
3405 i = actions.begin();
3406 i != actions.end(); ++i)
3408 const RollbackAction &action = *i;
3410 bool success = action.applyRevert(map, this, this);
3413 std::ostringstream os;
3414 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3415 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3417 log->push_back(os.str());
3419 std::ostringstream os;
3420 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3421 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3423 log->push_back(os.str());
3427 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3428 <<" failed"<<std::endl;
3430 // Call it done if less than half failed
3431 return num_failed <= num_tried/2;
3434 // IGameDef interface
3436 IItemDefManager *Server::getItemDefManager()
3441 INodeDefManager *Server::getNodeDefManager()
3446 ICraftDefManager *Server::getCraftDefManager()
3451 u16 Server::allocateUnknownNodeId(const std::string &name)
3453 return m_nodedef->allocateDummy(name);
3456 MtEventManager *Server::getEventManager()
3461 IWritableItemDefManager *Server::getWritableItemDefManager()
3466 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3471 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3476 const ModSpec *Server::getModSpec(const std::string &modname) const
3478 std::vector<ModSpec>::const_iterator it;
3479 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3480 const ModSpec &mod = *it;
3481 if (mod.name == modname)
3487 void Server::getModNames(std::vector<std::string> &modlist)
3489 std::vector<ModSpec>::iterator it;
3490 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3491 modlist.push_back(it->name);
3494 std::string Server::getBuiltinLuaPath()
3496 return porting::path_share + DIR_DELIM + "builtin";
3499 std::string Server::getModStoragePath() const
3501 return m_path_world + DIR_DELIM + "mod_storage";
3504 v3f Server::findSpawnPos()
3506 ServerMap &map = m_env->getServerMap();
3508 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3509 return nodeposf * BS;
3512 bool is_good = false;
3513 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3514 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3516 // Try to find a good place a few times
3517 for(s32 i = 0; i < 4000 && !is_good; i++) {
3518 s32 range = MYMIN(1 + i, range_max);
3519 // We're going to try to throw the player to this position
3520 v2s16 nodepos2d = v2s16(
3521 -range + (myrand() % (range * 2)),
3522 -range + (myrand() % (range * 2)));
3524 // Get spawn level at point
3525 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3526 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3527 // the mapgen to signify an unsuitable spawn position
3528 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3531 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3534 for (s32 i = 0; i < 10; i++) {
3535 v3s16 blockpos = getNodeBlockPos(nodepos);
3536 map.emergeBlock(blockpos, true);
3537 content_t c = map.getNodeNoEx(nodepos).getContent();
3538 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3540 if (air_count >= 2) {
3541 nodeposf = intToFloat(nodepos, BS);
3542 // Don't spawn the player outside map boundaries
3543 if (objectpos_over_limit(nodeposf))
3556 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3558 m_shutdown_timer = delay;
3559 m_shutdown_msg = msg;
3560 m_shutdown_ask_reconnect = reconnect;
3562 if (delay == 0.0f) {
3563 // No delay, shutdown immediately
3564 m_shutdown_requested = true;
3565 // only print to the infostream, a chat message saying
3566 // "Server Shutting Down" is sent when the server destructs.
3567 infostream << "*** Immediate Server shutdown requested." << std::endl;
3568 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3569 // Negative delay, cancel shutdown if requested
3570 m_shutdown_timer = 0.0f;
3571 m_shutdown_msg = "";
3572 m_shutdown_ask_reconnect = false;
3573 m_shutdown_requested = false;
3574 std::wstringstream ws;
3576 ws << L"*** Server shutdown canceled.";
3578 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3579 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3580 } else if (delay > 0.0f) {
3581 // Positive delay, tell the clients when the server will shut down
3582 std::wstringstream ws;
3584 ws << L"*** Server shutting down in "
3585 << duration_to_string(myround(m_shutdown_timer)).c_str()
3588 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3589 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3593 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3596 Try to get an existing player
3598 RemotePlayer *player = m_env->getPlayer(name);
3600 // If player is already connected, cancel
3601 if (player != NULL && player->peer_id != 0) {
3602 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3607 If player with the wanted peer_id already exists, cancel.
3609 if (m_env->getPlayer(peer_id) != NULL) {
3610 infostream<<"emergePlayer(): Player with wrong name but same"
3611 " peer_id already exists"<<std::endl;
3616 player = new RemotePlayer(name, idef());
3619 bool newplayer = false;
3622 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3624 // Complete init with server parts
3625 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3626 player->protocol_version = proto_version;
3630 m_script->on_newplayer(playersao);
3636 bool Server::registerModStorage(ModMetadata *storage)
3638 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3639 errorstream << "Unable to register same mod storage twice. Storage name: "
3640 << storage->getModName() << std::endl;
3644 m_mod_storages[storage->getModName()] = storage;
3648 void Server::unregisterModStorage(const std::string &name)
3650 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3651 if (it != m_mod_storages.end()) {
3652 // Save unconditionaly on unregistration
3653 it->second->save(getModStoragePath());
3654 m_mod_storages.erase(name);
3658 void dedicated_server_loop(Server &server, bool &kill)
3660 DSTACK(FUNCTION_NAME);
3662 verbosestream<<"dedicated_server_loop()"<<std::endl;
3664 IntervalLimiter m_profiler_interval;
3666 static thread_local const float steplen =
3667 g_settings->getFloat("dedicated_server_step");
3668 static thread_local const float profiler_print_interval =
3669 g_settings->getFloat("profiler_print_interval");
3672 // This is kind of a hack but can be done like this
3673 // because server.step() is very light
3675 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3676 sleep_ms((int)(steplen*1000.0));
3678 server.step(steplen);
3680 if (server.getShutdownRequested() || kill)
3686 if (profiler_print_interval != 0) {
3687 if(m_profiler_interval.step(steplen, profiler_print_interval))
3689 infostream<<"Profiler:"<<std::endl;
3690 g_profiler->print(infostream);
3691 g_profiler->clear();
3696 infostream << "Dedicated server quitting" << std::endl;
3698 if (g_settings->getBool("server_announce"))
3699 ServerList::sendAnnounce(ServerList::AA_DELETE,
3700 server.m_bind_addr.getPort());