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_abm.h"
51 #include "content_sao.h"
53 #include "event_manager.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "util/base64.h"
61 #include "util/sha1.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(""),
168 m_enable_rollback_recording(false),
171 m_itemdef(createItemDefManager()),
172 m_nodedef(createNodeDefManager()),
173 m_craftdef(createCraftDefManager()),
174 m_event(new EventManager()),
176 m_time_of_day_send_timer(0),
179 m_shutdown_requested(false),
180 m_shutdown_ask_reconnect(false),
181 m_shutdown_timer(0.0f),
183 m_ignore_map_edit_events(false),
184 m_ignore_map_edit_events_peer_id(0),
186 m_mod_storage_save_timer(10.0f)
188 m_liquid_transform_timer = 0.0;
189 m_liquid_transform_every = 1.0;
190 m_masterserver_timer = 0.0;
191 m_emergethread_trigger_timer = 0.0;
192 m_savemap_timer = 0.0;
195 m_lag = g_settings->getFloat("dedicated_server_step");
198 throw ServerError("Supplied empty world path");
200 if(!gamespec.isValid())
201 throw ServerError("Supplied invalid gamespec");
203 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
204 if(m_simple_singleplayer_mode)
205 infostream<<" in simple singleplayer mode"<<std::endl;
207 infostream<<std::endl;
208 infostream<<"- world: "<<m_path_world<<std::endl;
209 infostream<<"- game: "<<m_gamespec.path<<std::endl;
211 // Create world if it doesn't exist
212 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
213 throw ServerError("Failed to initialize world");
215 // Create server thread
216 m_thread = new ServerThread(this);
218 // Create emerge manager
219 m_emerge = new EmergeManager(this);
221 // Create ban manager
222 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
223 m_banmanager = new BanManager(ban_path);
225 ServerModConfiguration modconf(m_path_world);
226 m_mods = modconf.getMods();
227 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
228 // complain about mods with unsatisfied dependencies
229 if (!modconf.isConsistent()) {
230 modconf.printUnsatisfiedModsError();
234 MutexAutoLock envlock(m_env_mutex);
236 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
237 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
239 // Initialize scripting
240 infostream<<"Server: Initializing Lua"<<std::endl;
242 m_script = new ServerScripting(this);
244 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
247 infostream << "Server: Loading mods: ";
248 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
249 i != m_mods.end(); ++i) {
250 infostream << (*i).name << " ";
252 infostream << std::endl;
253 // Load and run "mod" scripts
254 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
255 it != m_mods.end(); ++it) {
256 const ModSpec &mod = *it;
257 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
258 throw ModError("Error loading mod \"" + mod.name +
259 "\": Mod name does not follow naming conventions: "
260 "Only characters [a-z0-9_] are allowed.");
262 std::string script_path = mod.path + DIR_DELIM + "init.lua";
263 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
264 << script_path << "\"]" << std::endl;
265 m_script->loadMod(script_path, mod.name);
268 // Read Textures and calculate sha1 sums
271 // Apply item aliases in the node definition manager
272 m_nodedef->updateAliases(m_itemdef);
274 // Apply texture overrides from texturepack/override.txt
275 std::string texture_path = g_settings->get("texture_path");
276 if (texture_path != "" && fs::IsDir(texture_path))
277 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
279 m_nodedef->setNodeRegistrationStatus(true);
281 // Perform pending node name resolutions
282 m_nodedef->runNodeResolveCallbacks();
284 // unmap node names for connected nodeboxes
285 m_nodedef->mapNodeboxConnections();
287 // init the recipe hashes to speed up crafting
288 m_craftdef->initHashes(this);
290 // Initialize Environment
291 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
293 m_clients.setEnv(m_env);
295 if (!servermap->settings_mgr.makeMapgenParams())
296 FATAL_ERROR("Couldn't create any mapgen type");
298 // Initialize mapgens
299 m_emerge->initMapgens(servermap->getMapgenParams());
301 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
302 if (m_enable_rollback_recording) {
303 // Create rollback manager
304 m_rollback = new RollbackManager(m_path_world, this);
307 // Give environment reference to scripting api
308 m_script->initializeEnvironment(m_env);
310 // Register us to receive map edit events
311 servermap->addEventReceiver(this);
313 // If file exists, load environment metadata
314 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
315 infostream << "Server: Loading environment metadata" << std::endl;
318 m_env->loadDefaultMeta();
321 // Add some test ActiveBlockModifiers to environment
322 add_legacy_abms(m_env, m_nodedef);
324 m_liquid_transform_every = g_settings->getFloat("liquid_update");
325 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
330 infostream<<"Server destructing"<<std::endl;
332 // Send shutdown message
333 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
336 MutexAutoLock envlock(m_env_mutex);
338 // Execute script shutdown hooks
339 m_script->on_shutdown();
341 infostream << "Server: Saving players" << std::endl;
342 m_env->saveLoadedPlayers();
344 infostream << "Server: Kicking players" << std::endl;
345 std::string kick_msg;
346 bool reconnect = false;
347 if (getShutdownRequested()) {
348 reconnect = m_shutdown_ask_reconnect;
349 kick_msg = m_shutdown_msg;
351 if (kick_msg == "") {
352 kick_msg = g_settings->get("kick_msg_shutdown");
354 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
355 kick_msg, reconnect);
357 infostream << "Server: Saving environment metadata" << std::endl;
365 // stop all emerge threads before deleting players that may have
366 // requested blocks to be emerged
367 m_emerge->stopThreads();
369 // Delete things in the reverse order of creation
379 // Deinitialize scripting
380 infostream<<"Server: Deinitializing scripting"<<std::endl;
383 // Delete detached inventories
384 for (std::map<std::string, Inventory*>::iterator
385 i = m_detached_inventories.begin();
386 i != m_detached_inventories.end(); ++i) {
391 void Server::start(Address bind_addr)
393 DSTACK(FUNCTION_NAME);
395 m_bind_addr = bind_addr;
397 infostream<<"Starting server on "
398 << bind_addr.serializeString() <<"..."<<std::endl;
400 // Stop thread if already running
403 // Initialize connection
404 m_con.SetTimeoutMs(30);
405 m_con.Serve(bind_addr);
410 // ASCII art for the win!
412 <<" .__ __ __ "<<std::endl
413 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
414 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
415 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
416 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
417 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
418 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
419 actionstream<<"Server for gameid=\""<<m_gamespec.id
420 <<"\" listening on "<<bind_addr.serializeString()<<":"
421 <<bind_addr.getPort() << "."<<std::endl;
426 DSTACK(FUNCTION_NAME);
428 infostream<<"Server: Stopping and waiting threads"<<std::endl;
430 // Stop threads (set run=false first so both start stopping)
432 //m_emergethread.setRun(false);
434 //m_emergethread.stop();
436 infostream<<"Server: Threads stopped"<<std::endl;
439 void Server::step(float dtime)
441 DSTACK(FUNCTION_NAME);
446 MutexAutoLock lock(m_step_dtime_mutex);
447 m_step_dtime += dtime;
449 // Throw if fatal error occurred in thread
450 std::string async_err = m_async_fatal_error.get();
451 if (!async_err.empty()) {
452 if (!m_simple_singleplayer_mode) {
453 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
454 g_settings->get("kick_msg_crash"),
455 g_settings->getBool("ask_reconnect_on_crash"));
457 throw ServerError("AsyncErr: " + async_err);
461 void Server::AsyncRunStep(bool initial_step)
463 DSTACK(FUNCTION_NAME);
465 g_profiler->add("Server::AsyncRunStep (num)", 1);
469 MutexAutoLock lock1(m_step_dtime_mutex);
470 dtime = m_step_dtime;
474 // Send blocks to clients
478 if((dtime < 0.001) && (initial_step == false))
481 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
483 //infostream<<"Server steps "<<dtime<<std::endl;
484 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
487 MutexAutoLock lock1(m_step_dtime_mutex);
488 m_step_dtime -= dtime;
495 m_uptime.set(m_uptime.get() + dtime);
501 Update time of day and overall game time
503 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
506 Send to clients at constant intervals
509 m_time_of_day_send_timer -= dtime;
510 if(m_time_of_day_send_timer < 0.0) {
511 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
512 u16 time = m_env->getTimeOfDay();
513 float time_speed = g_settings->getFloat("time_speed");
514 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
518 MutexAutoLock lock(m_env_mutex);
519 // Figure out and report maximum lag to environment
520 float max_lag = m_env->getMaxLagEstimate();
521 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
523 if(dtime > 0.1 && dtime > max_lag * 2.0)
524 infostream<<"Server: Maximum lag peaked to "<<dtime
528 m_env->reportMaxLagEstimate(max_lag);
530 ScopeProfiler sp(g_profiler, "SEnv step");
531 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
535 static const float map_timer_and_unload_dtime = 2.92;
536 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
538 MutexAutoLock lock(m_env_mutex);
539 // Run Map's timers and unload unused data
540 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
541 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
542 g_settings->getFloat("server_unload_unused_data_timeout"),
547 Listen to the admin chat, if available
550 if (!m_admin_chat->command_queue.empty()) {
551 MutexAutoLock lock(m_env_mutex);
552 while (!m_admin_chat->command_queue.empty()) {
553 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
554 handleChatInterfaceEvent(evt);
558 m_admin_chat->outgoing_queue.push_back(
559 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
566 /* Transform liquids */
567 m_liquid_transform_timer += dtime;
568 if(m_liquid_transform_timer >= m_liquid_transform_every)
570 m_liquid_transform_timer -= m_liquid_transform_every;
572 MutexAutoLock lock(m_env_mutex);
574 ScopeProfiler sp(g_profiler, "Server: liquid transform");
576 std::map<v3s16, MapBlock*> modified_blocks;
577 m_env->getMap().transformLiquids(modified_blocks, m_env);
582 core::map<v3s16, MapBlock*> lighting_modified_blocks;
583 ServerMap &map = ((ServerMap&)m_env->getMap());
584 map.updateLighting(modified_blocks, lighting_modified_blocks);
586 // Add blocks modified by lighting to modified_blocks
587 for(core::map<v3s16, MapBlock*>::Iterator
588 i = lighting_modified_blocks.getIterator();
589 i.atEnd() == false; i++)
591 MapBlock *block = i.getNode()->getValue();
592 modified_blocks.insert(block->getPos(), block);
596 Set the modified blocks unsent for all the clients
598 if(!modified_blocks.empty())
600 SetBlocksNotSent(modified_blocks);
603 m_clients.step(dtime);
605 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
607 // send masterserver announce
609 float &counter = m_masterserver_timer;
610 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
611 g_settings->getBool("server_announce")) {
612 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
613 ServerList::AA_START,
614 m_bind_addr.getPort(),
615 m_clients.getPlayerNames(),
617 m_env->getGameTime(),
620 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
630 Check added and deleted active objects
633 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
634 MutexAutoLock envlock(m_env_mutex);
637 RemoteClientMap clients = m_clients.getClientList();
638 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
640 // Radius inside which objects are active
641 static const s16 radius =
642 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
644 // Radius inside which players are active
645 static const bool is_transfer_limited =
646 g_settings->exists("unlimited_player_transfer_distance") &&
647 !g_settings->getBool("unlimited_player_transfer_distance");
648 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
649 s16 player_radius = player_transfer_dist;
650 if (player_radius == 0 && is_transfer_limited)
651 player_radius = radius;
653 for (RemoteClientMap::iterator i = clients.begin();
654 i != clients.end(); ++i) {
655 RemoteClient *client = i->second;
657 // If definitions and textures have not been sent, don't
658 // send objects either
659 if (client->getState() < CS_DefinitionsSent)
662 RemotePlayer *player = m_env->getPlayer(client->peer_id);
663 if (player == NULL) {
664 // This can happen if the client timeouts somehow
665 /*warningstream<<FUNCTION_NAME<<": Client "
667 <<" has no associated player"<<std::endl;*/
671 PlayerSAO *playersao = player->getPlayerSAO();
672 if (playersao == NULL)
675 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
676 if (my_radius <= 0) my_radius = radius;
677 //infostream << "Server: Active Radius " << my_radius << std::endl;
679 std::queue<u16> removed_objects;
680 std::queue<u16> added_objects;
681 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
682 client->m_known_objects, removed_objects);
683 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
684 client->m_known_objects, added_objects);
686 // Ignore if nothing happened
687 if (removed_objects.empty() && added_objects.empty()) {
691 std::string data_buffer;
695 // Handle removed objects
696 writeU16((u8*)buf, removed_objects.size());
697 data_buffer.append(buf, 2);
698 while (!removed_objects.empty()) {
700 u16 id = removed_objects.front();
701 ServerActiveObject* obj = m_env->getActiveObject(id);
703 // Add to data buffer for sending
704 writeU16((u8*)buf, id);
705 data_buffer.append(buf, 2);
707 // Remove from known objects
708 client->m_known_objects.erase(id);
710 if(obj && obj->m_known_by_count > 0)
711 obj->m_known_by_count--;
712 removed_objects.pop();
715 // Handle added objects
716 writeU16((u8*)buf, added_objects.size());
717 data_buffer.append(buf, 2);
718 while (!added_objects.empty()) {
720 u16 id = added_objects.front();
721 ServerActiveObject* obj = m_env->getActiveObject(id);
724 u8 type = ACTIVEOBJECT_TYPE_INVALID;
726 warningstream<<FUNCTION_NAME
727 <<": NULL object"<<std::endl;
729 type = obj->getSendType();
731 // Add to data buffer for sending
732 writeU16((u8*)buf, id);
733 data_buffer.append(buf, 2);
734 writeU8((u8*)buf, type);
735 data_buffer.append(buf, 1);
738 data_buffer.append(serializeLongString(
739 obj->getClientInitializationData(client->net_proto_version)));
741 data_buffer.append(serializeLongString(""));
743 // Add to known objects
744 client->m_known_objects.insert(id);
747 obj->m_known_by_count++;
752 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
753 verbosestream << "Server: Sent object remove/add: "
754 << removed_objects.size() << " removed, "
755 << added_objects.size() << " added, "
756 << "packet size is " << pktSize << std::endl;
760 m_mod_storage_save_timer -= dtime;
761 if (m_mod_storage_save_timer <= 0.0f) {
762 infostream << "Saving registered mod storages." << std::endl;
763 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
764 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
765 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
766 if (it->second->isModified()) {
767 it->second->save(getModStoragePath());
777 MutexAutoLock envlock(m_env_mutex);
778 ScopeProfiler sp(g_profiler, "Server: sending object messages");
781 // Value = data sent by object
782 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
784 // Get active object messages from environment
786 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
790 std::vector<ActiveObjectMessage>* message_list = NULL;
791 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
792 n = buffered_messages.find(aom.id);
793 if (n == buffered_messages.end()) {
794 message_list = new std::vector<ActiveObjectMessage>;
795 buffered_messages[aom.id] = message_list;
798 message_list = n->second;
800 message_list->push_back(aom);
804 RemoteClientMap clients = m_clients.getClientList();
805 // Route data to every client
806 for (std::unordered_map<u16, RemoteClient*>::iterator i = clients.begin();
807 i != clients.end(); ++i) {
808 RemoteClient *client = i->second;
809 std::string reliable_data;
810 std::string unreliable_data;
811 // Go through all objects in message buffer
812 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
813 j = buffered_messages.begin();
814 j != buffered_messages.end(); ++j) {
815 // If object is not known by client, skip it
817 if (client->m_known_objects.find(id) == client->m_known_objects.end())
820 // Get message list of object
821 std::vector<ActiveObjectMessage>* list = j->second;
822 // Go through every message
823 for (std::vector<ActiveObjectMessage>::iterator
824 k = list->begin(); k != list->end(); ++k) {
825 // Compose the full new data with header
826 ActiveObjectMessage aom = *k;
827 std::string new_data;
830 writeU16((u8*)&buf[0], aom.id);
831 new_data.append(buf, 2);
833 new_data += serializeString(aom.datastring);
834 // Add data to buffer
836 reliable_data += new_data;
838 unreliable_data += new_data;
842 reliable_data and unreliable_data are now ready.
845 if(reliable_data.size() > 0) {
846 SendActiveObjectMessages(client->peer_id, reliable_data);
849 if(unreliable_data.size() > 0) {
850 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
855 // Clear buffered_messages
856 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
857 i = buffered_messages.begin();
858 i != buffered_messages.end(); ++i) {
864 Send queued-for-sending map edit events.
867 // We will be accessing the environment
868 MutexAutoLock lock(m_env_mutex);
870 // Don't send too many at a time
873 // Single change sending is disabled if queue size is not small
874 bool disable_single_change_sending = false;
875 if(m_unsent_map_edit_queue.size() >= 4)
876 disable_single_change_sending = true;
878 int event_count = m_unsent_map_edit_queue.size();
880 // We'll log the amount of each
883 while(m_unsent_map_edit_queue.size() != 0)
885 MapEditEvent* event = m_unsent_map_edit_queue.front();
886 m_unsent_map_edit_queue.pop();
888 // Players far away from the change are stored here.
889 // Instead of sending the changes, MapBlocks are set not sent
891 std::vector<u16> far_players;
893 switch (event->type) {
896 prof.add("MEET_ADDNODE", 1);
897 sendAddNode(event->p, event->n, event->already_known_by_peer,
898 &far_players, disable_single_change_sending ? 5 : 30,
899 event->type == MEET_ADDNODE);
901 case MEET_REMOVENODE:
902 prof.add("MEET_REMOVENODE", 1);
903 sendRemoveNode(event->p, event->already_known_by_peer,
904 &far_players, disable_single_change_sending ? 5 : 30);
906 case MEET_BLOCK_NODE_METADATA_CHANGED:
907 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
908 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
909 setBlockNotSent(event->p);
912 infostream << "Server: MEET_OTHER" << std::endl;
913 prof.add("MEET_OTHER", 1);
914 for(std::set<v3s16>::iterator
915 i = event->modified_blocks.begin();
916 i != event->modified_blocks.end(); ++i) {
921 prof.add("unknown", 1);
922 warningstream << "Server: Unknown MapEditEvent "
923 << ((u32)event->type) << std::endl;
928 Set blocks not sent to far players
930 if(!far_players.empty()) {
931 // Convert list format to that wanted by SetBlocksNotSent
932 std::map<v3s16, MapBlock*> modified_blocks2;
933 for(std::set<v3s16>::iterator
934 i = event->modified_blocks.begin();
935 i != event->modified_blocks.end(); ++i) {
936 modified_blocks2[*i] =
937 m_env->getMap().getBlockNoCreateNoEx(*i);
940 // Set blocks not sent
941 for(std::vector<u16>::iterator
942 i = far_players.begin();
943 i != far_players.end(); ++i) {
944 if(RemoteClient *client = getClient(*i))
945 client->SetBlocksNotSent(modified_blocks2);
951 /*// Don't send too many at a time
953 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
957 if(event_count >= 5){
958 infostream<<"Server: MapEditEvents:"<<std::endl;
959 prof.print(infostream);
960 } else if(event_count != 0){
961 verbosestream<<"Server: MapEditEvents:"<<std::endl;
962 prof.print(verbosestream);
968 Trigger emergethread (it somehow gets to a non-triggered but
969 bysy state sometimes)
972 float &counter = m_emergethread_trigger_timer;
974 if (counter >= 2.0) {
977 m_emerge->startThreads();
981 // Save map, players and auth stuff
983 float &counter = m_savemap_timer;
985 static const float save_interval =
986 g_settings->getFloat("server_map_save_interval");
987 if (counter >= save_interval) {
989 MutexAutoLock lock(m_env_mutex);
991 ScopeProfiler sp(g_profiler, "Server: saving stuff");
994 if (m_banmanager->isModified()) {
995 m_banmanager->save();
998 // Save changed parts of map
999 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1002 m_env->saveLoadedPlayers();
1004 // Save environment metadata
1010 static const float shutdown_msg_times[] =
1012 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
1015 if (m_shutdown_timer > 0.0f) {
1016 // Automated messages
1017 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
1018 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
1019 // If shutdown timer matches an automessage, shot it
1020 if (m_shutdown_timer > shutdown_msg_times[i] &&
1021 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1022 std::wstringstream ws;
1024 ws << L"*** Server shutting down in "
1025 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1028 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1029 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1035 m_shutdown_timer -= dtime;
1036 if (m_shutdown_timer < 0.0f) {
1037 m_shutdown_timer = 0.0f;
1038 m_shutdown_requested = true;
1043 void Server::Receive()
1045 DSTACK(FUNCTION_NAME);
1046 SharedBuffer<u8> data;
1050 m_con.Receive(&pkt);
1051 peer_id = pkt.getPeerId();
1054 catch(con::InvalidIncomingDataException &e) {
1055 infostream<<"Server::Receive(): "
1056 "InvalidIncomingDataException: what()="
1057 <<e.what()<<std::endl;
1059 catch(SerializationError &e) {
1060 infostream<<"Server::Receive(): "
1061 "SerializationError: what()="
1062 <<e.what()<<std::endl;
1064 catch(ClientStateError &e) {
1065 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1066 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1067 L"Try reconnecting or updating your client");
1069 catch(con::PeerNotFoundException &e) {
1074 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1076 std::string playername = "";
1077 PlayerSAO *playersao = NULL;
1080 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1081 if (client != NULL) {
1082 playername = client->getName();
1083 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1085 } catch (std::exception &e) {
1091 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1093 // If failed, cancel
1094 if ((playersao == NULL) || (player == NULL)) {
1095 if (player && player->peer_id != 0) {
1096 actionstream << "Server: Failed to emerge player \"" << playername
1097 << "\" (player allocated to an another client)" << std::endl;
1098 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1099 L"name. If your client closed unexpectedly, try again in "
1102 errorstream << "Server: " << playername << ": Failed to emerge player"
1104 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1110 Send complete position information
1112 SendMovePlayer(peer_id);
1115 SendPlayerPrivileges(peer_id);
1117 // Send inventory formspec
1118 SendPlayerInventoryFormspec(peer_id);
1121 SendInventory(playersao);
1123 // Send HP or death screen
1124 if (playersao->isDead())
1125 SendDeathscreen(peer_id, false, v3f(0,0,0));
1127 SendPlayerHPOrDie(playersao);
1130 SendPlayerBreath(playersao);
1132 // Note things in chat if not in simple singleplayer mode
1133 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1134 // Send information about server to player in chat
1135 SendChatMessage(peer_id, getStatusString());
1137 Address addr = getPeerAddress(player->peer_id);
1138 std::string ip_str = addr.serializeString();
1139 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1144 const std::vector<std::string> &names = m_clients.getPlayerNames();
1146 actionstream << player->getName() << " joins game. List of players: ";
1148 for (std::vector<std::string>::const_iterator i = names.begin();
1149 i != names.end(); ++i) {
1150 actionstream << *i << " ";
1153 actionstream << player->getName() <<std::endl;
1158 inline void Server::handleCommand(NetworkPacket* pkt)
1160 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1161 (this->*opHandle.handler)(pkt);
1164 void Server::ProcessData(NetworkPacket *pkt)
1166 DSTACK(FUNCTION_NAME);
1167 // Environment is locked first.
1168 MutexAutoLock envlock(m_env_mutex);
1170 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1171 u32 peer_id = pkt->getPeerId();
1174 Address address = getPeerAddress(peer_id);
1175 std::string addr_s = address.serializeString();
1177 if(m_banmanager->isIpBanned(addr_s)) {
1178 std::string ban_name = m_banmanager->getBanName(addr_s);
1179 infostream << "Server: A banned client tried to connect from "
1180 << addr_s << "; banned name was "
1181 << ban_name << std::endl;
1182 // This actually doesn't seem to transfer to the client
1183 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1184 + utf8_to_wide(ban_name));
1188 catch(con::PeerNotFoundException &e) {
1190 * no peer for this packet found
1191 * most common reason is peer timeout, e.g. peer didn't
1192 * respond for some time, your server was overloaded or
1195 infostream << "Server::ProcessData(): Canceling: peer "
1196 << peer_id << " not found" << std::endl;
1201 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1203 // Command must be handled into ToServerCommandHandler
1204 if (command >= TOSERVER_NUM_MSG_TYPES) {
1205 infostream << "Server: Ignoring unknown command "
1206 << command << std::endl;
1210 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1215 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1217 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1218 errorstream << "Server::ProcessData(): Cancelling: Peer"
1219 " serialization format invalid or not initialized."
1220 " Skipping incoming command=" << command << std::endl;
1224 /* Handle commands related to client startup */
1225 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1230 if (m_clients.getClientState(peer_id) < CS_Active) {
1231 if (command == TOSERVER_PLAYERPOS) return;
1233 errorstream << "Got packet command: " << command << " for peer id "
1234 << peer_id << " but client isn't active yet. Dropping packet "
1240 } catch (SendFailedException &e) {
1241 errorstream << "Server::ProcessData(): SendFailedException: "
1242 << "what=" << e.what()
1244 } catch (PacketError &e) {
1245 actionstream << "Server::ProcessData(): PacketError: "
1246 << "what=" << e.what()
1251 void Server::setTimeOfDay(u32 time)
1253 m_env->setTimeOfDay(time);
1254 m_time_of_day_send_timer = 0;
1257 void Server::onMapEditEvent(MapEditEvent *event)
1259 if(m_ignore_map_edit_events)
1261 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1263 MapEditEvent *e = event->clone();
1264 m_unsent_map_edit_queue.push(e);
1267 Inventory* Server::getInventory(const InventoryLocation &loc)
1270 case InventoryLocation::UNDEFINED:
1271 case InventoryLocation::CURRENT_PLAYER:
1273 case InventoryLocation::PLAYER:
1275 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1278 PlayerSAO *playersao = player->getPlayerSAO();
1281 return playersao->getInventory();
1284 case InventoryLocation::NODEMETA:
1286 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1289 return meta->getInventory();
1292 case InventoryLocation::DETACHED:
1294 if(m_detached_inventories.count(loc.name) == 0)
1296 return m_detached_inventories[loc.name];
1300 sanity_check(false); // abort
1305 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1308 case InventoryLocation::UNDEFINED:
1310 case InventoryLocation::PLAYER:
1315 RemotePlayer *player =
1316 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1321 PlayerSAO *playersao = player->getPlayerSAO();
1325 SendInventory(playersao);
1328 case InventoryLocation::NODEMETA:
1330 v3s16 blockpos = getNodeBlockPos(loc.p);
1332 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1334 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1336 setBlockNotSent(blockpos);
1339 case InventoryLocation::DETACHED:
1341 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1345 sanity_check(false); // abort
1350 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1352 std::vector<u16> clients = m_clients.getClientIDs();
1354 // Set the modified blocks unsent for all the clients
1355 for (std::vector<u16>::iterator i = clients.begin();
1356 i != clients.end(); ++i) {
1357 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1358 client->SetBlocksNotSent(block);
1363 void Server::peerAdded(con::Peer *peer)
1365 DSTACK(FUNCTION_NAME);
1366 verbosestream<<"Server::peerAdded(): peer->id="
1367 <<peer->id<<std::endl;
1370 c.type = con::PEER_ADDED;
1371 c.peer_id = peer->id;
1373 m_peer_change_queue.push(c);
1376 void Server::deletingPeer(con::Peer *peer, bool timeout)
1378 DSTACK(FUNCTION_NAME);
1379 verbosestream<<"Server::deletingPeer(): peer->id="
1380 <<peer->id<<", timeout="<<timeout<<std::endl;
1382 m_clients.event(peer->id, CSE_Disconnect);
1384 c.type = con::PEER_REMOVED;
1385 c.peer_id = peer->id;
1386 c.timeout = timeout;
1387 m_peer_change_queue.push(c);
1390 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1392 *retval = m_con.getPeerStat(peer_id,type);
1393 if (*retval == -1) return false;
1397 bool Server::getClientInfo(
1406 std::string* vers_string
1409 *state = m_clients.getClientState(peer_id);
1411 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1413 if (client == NULL) {
1418 *uptime = client->uptime();
1419 *ser_vers = client->serialization_version;
1420 *prot_vers = client->net_proto_version;
1422 *major = client->getMajor();
1423 *minor = client->getMinor();
1424 *patch = client->getPatch();
1425 *vers_string = client->getPatch();
1432 void Server::handlePeerChanges()
1434 while(m_peer_change_queue.size() > 0)
1436 con::PeerChange c = m_peer_change_queue.front();
1437 m_peer_change_queue.pop();
1439 verbosestream<<"Server: Handling peer change: "
1440 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1445 case con::PEER_ADDED:
1446 m_clients.CreateClient(c.peer_id);
1449 case con::PEER_REMOVED:
1450 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1454 FATAL_ERROR("Invalid peer change event received!");
1460 void Server::printToConsoleOnly(const std::string &text)
1463 m_admin_chat->outgoing_queue.push_back(
1464 new ChatEventChat("", utf8_to_wide(text)));
1466 std::cout << text << std::endl;
1470 void Server::Send(NetworkPacket* pkt)
1472 m_clients.send(pkt->getPeerId(),
1473 clientCommandFactoryTable[pkt->getCommand()].channel,
1475 clientCommandFactoryTable[pkt->getCommand()].reliable);
1478 void Server::SendMovement(u16 peer_id)
1480 DSTACK(FUNCTION_NAME);
1481 std::ostringstream os(std::ios_base::binary);
1483 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1485 pkt << g_settings->getFloat("movement_acceleration_default");
1486 pkt << g_settings->getFloat("movement_acceleration_air");
1487 pkt << g_settings->getFloat("movement_acceleration_fast");
1488 pkt << g_settings->getFloat("movement_speed_walk");
1489 pkt << g_settings->getFloat("movement_speed_crouch");
1490 pkt << g_settings->getFloat("movement_speed_fast");
1491 pkt << g_settings->getFloat("movement_speed_climb");
1492 pkt << g_settings->getFloat("movement_speed_jump");
1493 pkt << g_settings->getFloat("movement_liquid_fluidity");
1494 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1495 pkt << g_settings->getFloat("movement_liquid_sink");
1496 pkt << g_settings->getFloat("movement_gravity");
1501 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1503 if (!g_settings->getBool("enable_damage"))
1506 u16 peer_id = playersao->getPeerID();
1507 bool is_alive = playersao->getHP() > 0;
1510 SendPlayerHP(peer_id);
1515 void Server::SendHP(u16 peer_id, u8 hp)
1517 DSTACK(FUNCTION_NAME);
1519 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1524 void Server::SendBreath(u16 peer_id, u16 breath)
1526 DSTACK(FUNCTION_NAME);
1528 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1529 pkt << (u16) breath;
1533 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1534 const std::string &custom_reason, bool reconnect)
1536 assert(reason < SERVER_ACCESSDENIED_MAX);
1538 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1540 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1541 pkt << custom_reason;
1542 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1543 reason == SERVER_ACCESSDENIED_CRASH)
1544 pkt << custom_reason << (u8)reconnect;
1548 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1550 DSTACK(FUNCTION_NAME);
1552 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1557 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1558 v3f camera_point_target)
1560 DSTACK(FUNCTION_NAME);
1562 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1563 pkt << set_camera_point_target << camera_point_target;
1567 void Server::SendItemDef(u16 peer_id,
1568 IItemDefManager *itemdef, u16 protocol_version)
1570 DSTACK(FUNCTION_NAME);
1572 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1576 u32 length of the next item
1577 zlib-compressed serialized ItemDefManager
1579 std::ostringstream tmp_os(std::ios::binary);
1580 itemdef->serialize(tmp_os, protocol_version);
1581 std::ostringstream tmp_os2(std::ios::binary);
1582 compressZlib(tmp_os.str(), tmp_os2);
1583 pkt.putLongString(tmp_os2.str());
1586 verbosestream << "Server: Sending item definitions to id(" << peer_id
1587 << "): size=" << pkt.getSize() << std::endl;
1592 void Server::SendNodeDef(u16 peer_id,
1593 INodeDefManager *nodedef, u16 protocol_version)
1595 DSTACK(FUNCTION_NAME);
1597 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1601 u32 length of the next item
1602 zlib-compressed serialized NodeDefManager
1604 std::ostringstream tmp_os(std::ios::binary);
1605 nodedef->serialize(tmp_os, protocol_version);
1606 std::ostringstream tmp_os2(std::ios::binary);
1607 compressZlib(tmp_os.str(), tmp_os2);
1609 pkt.putLongString(tmp_os2.str());
1612 verbosestream << "Server: Sending node definitions to id(" << peer_id
1613 << "): size=" << pkt.getSize() << std::endl;
1619 Non-static send methods
1622 void Server::SendInventory(PlayerSAO* playerSAO)
1624 DSTACK(FUNCTION_NAME);
1626 UpdateCrafting(playerSAO->getPlayer());
1632 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1634 std::ostringstream os;
1635 playerSAO->getInventory()->serialize(os);
1637 std::string s = os.str();
1639 pkt.putRawString(s.c_str(), s.size());
1643 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1645 DSTACK(FUNCTION_NAME);
1646 if (peer_id != PEER_ID_INEXISTENT) {
1647 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1649 if (m_clients.getProtocolVersion(peer_id) < 27)
1650 pkt << unescape_enriched(message);
1656 for (u16 id : m_clients.getClientIDs())
1657 SendChatMessage(id, message);
1661 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1662 const std::string &formname)
1664 DSTACK(FUNCTION_NAME);
1666 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1667 if (formspec == "" ){
1668 //the client should close the formspec
1669 pkt.putLongString("");
1671 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1678 // Spawns a particle on peer with peer_id
1679 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1680 v3f pos, v3f velocity, v3f acceleration,
1681 float expirationtime, float size, bool collisiondetection,
1682 bool collision_removal,
1683 bool vertical, const std::string &texture,
1684 const struct TileAnimationParams &animation, u8 glow)
1686 DSTACK(FUNCTION_NAME);
1687 static const float radius =
1688 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1690 if (peer_id == PEER_ID_INEXISTENT) {
1691 std::vector<u16> clients = m_clients.getClientIDs();
1693 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1694 RemotePlayer *player = m_env->getPlayer(*i);
1698 PlayerSAO *sao = player->getPlayerSAO();
1702 // Do not send to distant clients
1703 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1706 SendSpawnParticle(*i, player->protocol_version,
1707 pos, velocity, acceleration,
1708 expirationtime, size, collisiondetection,
1709 collision_removal, vertical, texture, animation, glow);
1714 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1716 pkt << pos << velocity << acceleration << expirationtime
1717 << size << collisiondetection;
1718 pkt.putLongString(texture);
1720 pkt << collision_removal;
1721 // This is horrible but required (why are there two ways to serialize pkts?)
1722 std::ostringstream os(std::ios_base::binary);
1723 animation.serialize(os, protocol_version);
1724 pkt.putRawString(os.str());
1730 // Adds a ParticleSpawner on peer with peer_id
1731 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1732 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1733 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1734 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1735 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1736 const struct TileAnimationParams &animation, u8 glow)
1738 DSTACK(FUNCTION_NAME);
1739 if (peer_id == PEER_ID_INEXISTENT) {
1740 // This sucks and should be replaced:
1741 std::vector<u16> clients = m_clients.getClientIDs();
1742 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1743 RemotePlayer *player = m_env->getPlayer(*i);
1746 SendAddParticleSpawner(*i, player->protocol_version,
1747 amount, spawntime, minpos, maxpos,
1748 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1749 minsize, maxsize, collisiondetection, collision_removal,
1750 attached_id, vertical, texture, id, animation, glow);
1755 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1757 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1758 << minacc << maxacc << minexptime << maxexptime << minsize
1759 << maxsize << collisiondetection;
1761 pkt.putLongString(texture);
1763 pkt << id << vertical;
1764 pkt << collision_removal;
1766 // This is horrible but required
1767 std::ostringstream os(std::ios_base::binary);
1768 animation.serialize(os, protocol_version);
1769 pkt.putRawString(os.str());
1775 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1777 DSTACK(FUNCTION_NAME);
1779 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1781 // Ugly error in this packet
1784 if (peer_id != PEER_ID_INEXISTENT) {
1788 m_clients.sendToAll(&pkt);
1793 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1795 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1797 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1798 << form->text << form->number << form->item << form->dir
1799 << form->align << form->offset << form->world_pos << form->size;
1804 void Server::SendHUDRemove(u16 peer_id, u32 id)
1806 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1811 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1813 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1814 pkt << id << (u8) stat;
1818 case HUD_STAT_SCALE:
1819 case HUD_STAT_ALIGN:
1820 case HUD_STAT_OFFSET:
1821 pkt << *(v2f *) value;
1825 pkt << *(std::string *) value;
1827 case HUD_STAT_WORLD_POS:
1828 pkt << *(v3f *) value;
1831 pkt << *(v2s32 *) value;
1833 case HUD_STAT_NUMBER:
1837 pkt << *(u32 *) value;
1844 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1846 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1848 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1850 pkt << flags << mask;
1855 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1857 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1858 pkt << param << value;
1862 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1863 const std::string &type, const std::vector<std::string> ¶ms,
1866 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1867 pkt << bgcolor << type << (u16) params.size();
1869 for(size_t i=0; i<params.size(); i++)
1877 void Server::SendCloudParams(u16 peer_id, float density,
1878 const video::SColor &color_bright,
1879 const video::SColor &color_ambient,
1884 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1885 pkt << density << color_bright << color_ambient
1886 << height << thickness << speed;
1891 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1894 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1897 pkt << do_override << (u16) (ratio * 65535);
1902 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1904 DSTACK(FUNCTION_NAME);
1906 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1907 pkt << time << time_speed;
1909 if (peer_id == PEER_ID_INEXISTENT) {
1910 m_clients.sendToAll(&pkt);
1917 void Server::SendPlayerHP(u16 peer_id)
1919 DSTACK(FUNCTION_NAME);
1920 PlayerSAO *playersao = getPlayerSAO(peer_id);
1921 // In some rare case if the player is disconnected
1922 // while Lua call l_punch, for example, this can be NULL
1926 SendHP(peer_id, playersao->getHP());
1927 m_script->player_event(playersao,"health_changed");
1929 // Send to other clients
1930 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1931 ActiveObjectMessage aom(playersao->getId(), true, str);
1932 playersao->m_messages_out.push(aom);
1935 void Server::SendPlayerBreath(PlayerSAO *sao)
1937 DSTACK(FUNCTION_NAME);
1940 m_script->player_event(sao, "breath_changed");
1941 SendBreath(sao->getPeerID(), sao->getBreath());
1944 void Server::SendMovePlayer(u16 peer_id)
1946 DSTACK(FUNCTION_NAME);
1947 RemotePlayer *player = m_env->getPlayer(peer_id);
1949 PlayerSAO *sao = player->getPlayerSAO();
1952 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1953 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1956 v3f pos = sao->getBasePosition();
1957 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1958 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1959 << " pitch=" << sao->getPitch()
1960 << " yaw=" << sao->getYaw()
1967 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1969 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1972 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1973 << animation_frames[3] << animation_speed;
1978 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1980 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1981 pkt << first << third;
1984 void Server::SendPlayerPrivileges(u16 peer_id)
1986 RemotePlayer *player = m_env->getPlayer(peer_id);
1988 if(player->peer_id == PEER_ID_INEXISTENT)
1991 std::set<std::string> privs;
1992 m_script->getAuth(player->getName(), NULL, &privs);
1994 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1995 pkt << (u16) privs.size();
1997 for(std::set<std::string>::const_iterator i = privs.begin();
1998 i != privs.end(); ++i) {
2005 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2007 RemotePlayer *player = m_env->getPlayer(peer_id);
2009 if(player->peer_id == PEER_ID_INEXISTENT)
2012 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2013 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2017 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2019 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2020 pkt.putRawString(datas.c_str(), datas.size());
2022 return pkt.getSize();
2025 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2027 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2028 datas.size(), peer_id);
2030 pkt.putRawString(datas.c_str(), datas.size());
2032 m_clients.send(pkt.getPeerId(),
2033 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2038 s32 Server::playSound(const SimpleSoundSpec &spec,
2039 const ServerSoundParams ¶ms)
2041 // Find out initial position of sound
2042 bool pos_exists = false;
2043 v3f pos = params.getPos(m_env, &pos_exists);
2044 // If position is not found while it should be, cancel sound
2045 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2048 // Filter destination clients
2049 std::vector<u16> dst_clients;
2050 if(params.to_player != "")
2052 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2054 infostream<<"Server::playSound: Player \""<<params.to_player
2055 <<"\" not found"<<std::endl;
2058 if(player->peer_id == PEER_ID_INEXISTENT){
2059 infostream<<"Server::playSound: Player \""<<params.to_player
2060 <<"\" not connected"<<std::endl;
2063 dst_clients.push_back(player->peer_id);
2066 std::vector<u16> clients = m_clients.getClientIDs();
2068 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2069 RemotePlayer *player = m_env->getPlayer(*i);
2073 PlayerSAO *sao = player->getPlayerSAO();
2078 if(sao->getBasePosition().getDistanceFrom(pos) >
2079 params.max_hear_distance)
2082 dst_clients.push_back(*i);
2086 if(dst_clients.empty())
2090 s32 id = m_next_sound_id++;
2091 // The sound will exist as a reference in m_playing_sounds
2092 m_playing_sounds[id] = ServerPlayingSound();
2093 ServerPlayingSound &psound = m_playing_sounds[id];
2094 psound.params = params;
2097 float gain = params.gain * spec.gain;
2098 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2099 pkt << id << spec.name << gain
2100 << (u8) params.type << pos << params.object
2101 << params.loop << params.fade;
2103 // Backwards compability
2104 bool play_sound = gain > 0;
2106 for (std::vector<u16>::iterator i = dst_clients.begin();
2107 i != dst_clients.end(); ++i) {
2108 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2109 psound.clients.insert(*i);
2110 m_clients.send(*i, 0, &pkt, true);
2115 void Server::stopSound(s32 handle)
2117 // Get sound reference
2118 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2119 m_playing_sounds.find(handle);
2120 if (i == m_playing_sounds.end())
2122 ServerPlayingSound &psound = i->second;
2124 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2127 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2128 si != psound.clients.end(); ++si) {
2130 m_clients.send(*si, 0, &pkt, true);
2132 // Remove sound reference
2133 m_playing_sounds.erase(i);
2136 void Server::fadeSound(s32 handle, float step, float gain)
2138 // Get sound reference
2139 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2140 m_playing_sounds.find(handle);
2141 if (i == m_playing_sounds.end())
2144 ServerPlayingSound &psound = i->second;
2145 psound.params.gain = gain;
2147 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2148 pkt << handle << step << gain;
2150 // Backwards compability
2151 bool play_sound = gain > 0;
2152 ServerPlayingSound compat_psound = psound;
2153 compat_psound.clients.clear();
2155 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2156 compat_pkt << handle;
2158 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2159 it != psound.clients.end();) {
2160 if (m_clients.getProtocolVersion(*it) >= 32) {
2162 m_clients.send(*it, 0, &pkt, true);
2165 compat_psound.clients.insert(*it);
2167 m_clients.send(*it, 0, &compat_pkt, true);
2168 psound.clients.erase(it++);
2172 // Remove sound reference
2173 if (!play_sound || psound.clients.size() == 0)
2174 m_playing_sounds.erase(i);
2176 if (play_sound && compat_psound.clients.size() > 0) {
2177 // Play new sound volume on older clients
2178 playSound(compat_psound.spec, compat_psound.params);
2182 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2183 std::vector<u16> *far_players, float far_d_nodes)
2185 float maxd = far_d_nodes*BS;
2186 v3f p_f = intToFloat(p, BS);
2188 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2191 std::vector<u16> clients = m_clients.getClientIDs();
2192 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2195 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2196 PlayerSAO *sao = player->getPlayerSAO();
2200 // If player is far away, only set modified blocks not sent
2201 v3f player_pos = sao->getBasePosition();
2202 if (player_pos.getDistanceFrom(p_f) > maxd) {
2203 far_players->push_back(*i);
2210 m_clients.send(*i, 0, &pkt, true);
2214 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2215 std::vector<u16> *far_players, float far_d_nodes,
2216 bool remove_metadata)
2218 float maxd = far_d_nodes*BS;
2219 v3f p_f = intToFloat(p, BS);
2221 std::vector<u16> clients = m_clients.getClientIDs();
2222 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2225 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2226 PlayerSAO *sao = player->getPlayerSAO();
2230 // If player is far away, only set modified blocks not sent
2231 v3f player_pos = sao->getBasePosition();
2232 if(player_pos.getDistanceFrom(p_f) > maxd) {
2233 far_players->push_back(*i);
2239 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2241 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2243 pkt << p << n.param0 << n.param1 << n.param2
2244 << (u8) (remove_metadata ? 0 : 1);
2249 if (pkt.getSize() > 0)
2250 m_clients.send(*i, 0, &pkt, true);
2254 void Server::setBlockNotSent(v3s16 p)
2256 std::vector<u16> clients = m_clients.getClientIDs();
2258 for(std::vector<u16>::iterator i = clients.begin();
2259 i != clients.end(); ++i) {
2260 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2261 client->SetBlockNotSent(p);
2266 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2268 DSTACK(FUNCTION_NAME);
2270 v3s16 p = block->getPos();
2273 Create a packet with the block in the right format
2276 std::ostringstream os(std::ios_base::binary);
2277 block->serialize(os, ver, false);
2278 block->serializeNetworkSpecific(os);
2279 std::string s = os.str();
2281 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2284 pkt.putRawString(s.c_str(), s.size());
2288 void Server::SendBlocks(float dtime)
2290 DSTACK(FUNCTION_NAME);
2292 MutexAutoLock envlock(m_env_mutex);
2293 //TODO check if one big lock could be faster then multiple small ones
2295 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2297 std::vector<PrioritySortedBlockTransfer> queue;
2299 s32 total_sending = 0;
2302 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2304 std::vector<u16> clients = m_clients.getClientIDs();
2307 for(std::vector<u16>::iterator i = clients.begin();
2308 i != clients.end(); ++i) {
2309 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2314 total_sending += client->SendingCount();
2315 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2321 // Lowest priority number comes first.
2322 // Lowest is most important.
2323 std::sort(queue.begin(), queue.end());
2326 for(u32 i=0; i<queue.size(); i++)
2328 //TODO: Calculate limit dynamically
2329 if(total_sending >= g_settings->getS32
2330 ("max_simultaneous_block_sends_server_total"))
2333 PrioritySortedBlockTransfer q = queue[i];
2335 MapBlock *block = NULL;
2338 block = m_env->getMap().getBlockNoCreate(q.pos);
2340 catch(InvalidPositionException &e)
2345 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2350 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2352 client->SentBlock(q.pos);
2358 void Server::fillMediaCache()
2360 DSTACK(FUNCTION_NAME);
2362 infostream<<"Server: Calculating media file checksums"<<std::endl;
2364 // Collect all media file paths
2365 std::vector<std::string> paths;
2366 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2367 i != m_mods.end(); ++i) {
2368 const ModSpec &mod = *i;
2369 paths.push_back(mod.path + DIR_DELIM + "textures");
2370 paths.push_back(mod.path + DIR_DELIM + "sounds");
2371 paths.push_back(mod.path + DIR_DELIM + "media");
2372 paths.push_back(mod.path + DIR_DELIM + "models");
2374 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2376 // Collect media file information from paths into cache
2377 for(std::vector<std::string>::iterator i = paths.begin();
2378 i != paths.end(); ++i) {
2379 std::string mediapath = *i;
2380 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2381 for (u32 j = 0; j < dirlist.size(); j++) {
2382 if (dirlist[j].dir) // Ignode dirs
2384 std::string filename = dirlist[j].name;
2385 // If name contains illegal characters, ignore the file
2386 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2387 infostream<<"Server: ignoring illegal file name: \""
2388 << filename << "\"" << std::endl;
2391 // If name is not in a supported format, ignore it
2392 const char *supported_ext[] = {
2393 ".png", ".jpg", ".bmp", ".tga",
2394 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2396 ".x", ".b3d", ".md2", ".obj",
2399 if (removeStringEnd(filename, supported_ext) == ""){
2400 infostream << "Server: ignoring unsupported file extension: \""
2401 << filename << "\"" << std::endl;
2404 // Ok, attempt to load the file and add to cache
2405 std::string filepath = mediapath + DIR_DELIM + filename;
2407 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2409 errorstream << "Server::fillMediaCache(): Could not open \""
2410 << filename << "\" for reading" << std::endl;
2413 std::ostringstream tmp_os(std::ios_base::binary);
2417 fis.read(buf, 1024);
2418 std::streamsize len = fis.gcount();
2419 tmp_os.write(buf, len);
2428 errorstream<<"Server::fillMediaCache(): Failed to read \""
2429 << filename << "\"" << std::endl;
2432 if(tmp_os.str().length() == 0) {
2433 errorstream << "Server::fillMediaCache(): Empty file \""
2434 << filepath << "\"" << std::endl;
2439 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2441 unsigned char *digest = sha1.getDigest();
2442 std::string sha1_base64 = base64_encode(digest, 20);
2443 std::string sha1_hex = hex_encode((char*)digest, 20);
2447 m_media[filename] = MediaInfo(filepath, sha1_base64);
2448 verbosestream << "Server: " << sha1_hex << " is " << filename
2454 void Server::sendMediaAnnouncement(u16 peer_id)
2456 DSTACK(FUNCTION_NAME);
2458 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2462 std::ostringstream os(std::ios_base::binary);
2464 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2465 pkt << (u16) m_media.size();
2467 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2468 i != m_media.end(); ++i) {
2469 pkt << i->first << i->second.sha1_digest;
2472 pkt << g_settings->get("remote_media");
2476 struct SendableMedia
2482 SendableMedia(const std::string &name_="", const std::string &path_="",
2483 const std::string &data_=""):
2490 void Server::sendRequestedMedia(u16 peer_id,
2491 const std::vector<std::string> &tosend)
2493 DSTACK(FUNCTION_NAME);
2495 verbosestream<<"Server::sendRequestedMedia(): "
2496 <<"Sending files to client"<<std::endl;
2500 // Put 5kB in one bunch (this is not accurate)
2501 u32 bytes_per_bunch = 5000;
2503 std::vector< std::vector<SendableMedia> > file_bunches;
2504 file_bunches.push_back(std::vector<SendableMedia>());
2506 u32 file_size_bunch_total = 0;
2508 for(std::vector<std::string>::const_iterator i = tosend.begin();
2509 i != tosend.end(); ++i) {
2510 const std::string &name = *i;
2512 if (m_media.find(name) == m_media.end()) {
2513 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2514 <<"unknown file \""<<(name)<<"\""<<std::endl;
2518 //TODO get path + name
2519 std::string tpath = m_media[name].path;
2522 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2523 if(fis.good() == false){
2524 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2525 <<tpath<<"\" for reading"<<std::endl;
2528 std::ostringstream tmp_os(std::ios_base::binary);
2532 fis.read(buf, 1024);
2533 std::streamsize len = fis.gcount();
2534 tmp_os.write(buf, len);
2535 file_size_bunch_total += len;
2544 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2545 <<name<<"\""<<std::endl;
2548 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2549 <<tname<<"\""<<std::endl;*/
2551 file_bunches[file_bunches.size()-1].push_back(
2552 SendableMedia(name, tpath, tmp_os.str()));
2554 // Start next bunch if got enough data
2555 if(file_size_bunch_total >= bytes_per_bunch) {
2556 file_bunches.push_back(std::vector<SendableMedia>());
2557 file_size_bunch_total = 0;
2562 /* Create and send packets */
2564 u16 num_bunches = file_bunches.size();
2565 for(u16 i = 0; i < num_bunches; i++) {
2568 u16 total number of texture bunches
2569 u16 index of this bunch
2570 u32 number of files in this bunch
2579 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2580 pkt << num_bunches << i << (u32) file_bunches[i].size();
2582 for(std::vector<SendableMedia>::iterator
2583 j = file_bunches[i].begin();
2584 j != file_bunches[i].end(); ++j) {
2586 pkt.putLongString(j->data);
2589 verbosestream << "Server::sendRequestedMedia(): bunch "
2590 << i << "/" << num_bunches
2591 << " files=" << file_bunches[i].size()
2592 << " size=" << pkt.getSize() << std::endl;
2597 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2599 if(m_detached_inventories.count(name) == 0) {
2600 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2603 Inventory *inv = m_detached_inventories[name];
2604 std::ostringstream os(std::ios_base::binary);
2606 os << serializeString(name);
2610 std::string s = os.str();
2612 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2613 pkt.putRawString(s.c_str(), s.size());
2615 const std::string &check = m_detached_inventories_player[name];
2616 if (peer_id == PEER_ID_INEXISTENT) {
2618 return m_clients.sendToAll(&pkt);
2619 RemotePlayer *p = m_env->getPlayer(check.c_str());
2621 m_clients.send(p->peer_id, 0, &pkt, true);
2623 if (check == "" || getPlayerName(peer_id) == check)
2628 void Server::sendDetachedInventories(u16 peer_id)
2630 DSTACK(FUNCTION_NAME);
2632 for(std::map<std::string, Inventory*>::iterator
2633 i = m_detached_inventories.begin();
2634 i != m_detached_inventories.end(); ++i) {
2635 const std::string &name = i->first;
2636 //Inventory *inv = i->second;
2637 sendDetachedInventory(name, peer_id);
2645 void Server::DiePlayer(u16 peer_id)
2647 DSTACK(FUNCTION_NAME);
2648 PlayerSAO *playersao = getPlayerSAO(peer_id);
2649 // In some rare cases this can be NULL -- if the player is disconnected
2650 // when a Lua function modifies l_punch, for example
2654 infostream << "Server::DiePlayer(): Player "
2655 << playersao->getPlayer()->getName()
2656 << " dies" << std::endl;
2658 playersao->setHP(0);
2660 // Trigger scripted stuff
2661 m_script->on_dieplayer(playersao);
2663 SendPlayerHP(peer_id);
2664 SendDeathscreen(peer_id, false, v3f(0,0,0));
2667 void Server::RespawnPlayer(u16 peer_id)
2669 DSTACK(FUNCTION_NAME);
2671 PlayerSAO *playersao = getPlayerSAO(peer_id);
2674 infostream << "Server::RespawnPlayer(): Player "
2675 << playersao->getPlayer()->getName()
2676 << " respawns" << std::endl;
2678 playersao->setHP(PLAYER_MAX_HP);
2679 playersao->setBreath(PLAYER_MAX_BREATH);
2681 bool repositioned = m_script->on_respawnplayer(playersao);
2682 if (!repositioned) {
2683 // setPos will send the new position to client
2684 playersao->setPos(findSpawnPos());
2687 SendPlayerHP(peer_id);
2691 void Server::DenySudoAccess(u16 peer_id)
2693 DSTACK(FUNCTION_NAME);
2695 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2700 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2701 const std::string &str_reason, bool reconnect)
2703 if (proto_ver >= 25) {
2704 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2706 std::wstring wreason = utf8_to_wide(
2707 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2708 accessDeniedStrings[(u8)reason]);
2709 SendAccessDenied_Legacy(peer_id, wreason);
2712 m_clients.event(peer_id, CSE_SetDenied);
2713 m_con.DisconnectPeer(peer_id);
2717 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2719 DSTACK(FUNCTION_NAME);
2721 SendAccessDenied(peer_id, reason, custom_reason);
2722 m_clients.event(peer_id, CSE_SetDenied);
2723 m_con.DisconnectPeer(peer_id);
2726 // 13/03/15: remove this function when protocol version 25 will become
2727 // the minimum version for MT users, maybe in 1 year
2728 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2730 DSTACK(FUNCTION_NAME);
2732 SendAccessDenied_Legacy(peer_id, reason);
2733 m_clients.event(peer_id, CSE_SetDenied);
2734 m_con.DisconnectPeer(peer_id);
2737 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2739 DSTACK(FUNCTION_NAME);
2742 RemoteClient* client = getClient(peer_id, CS_Invalid);
2744 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2746 // Right now, the auth mechs don't change between login and sudo mode.
2747 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2748 client->allowed_sudo_mechs = sudo_auth_mechs;
2750 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2751 << g_settings->getFloat("dedicated_server_step")
2755 m_clients.event(peer_id, CSE_AuthAccept);
2757 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2759 // We only support SRP right now
2760 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2762 resp_pkt << sudo_auth_mechs;
2764 m_clients.event(peer_id, CSE_SudoSuccess);
2768 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2770 DSTACK(FUNCTION_NAME);
2771 std::wstring message;
2774 Clear references to playing sounds
2776 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2777 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2778 ServerPlayingSound &psound = i->second;
2779 psound.clients.erase(peer_id);
2780 if (psound.clients.empty())
2781 m_playing_sounds.erase(i++);
2786 RemotePlayer *player = m_env->getPlayer(peer_id);
2788 /* Run scripts and remove from environment */
2789 if (player != NULL) {
2790 PlayerSAO *playersao = player->getPlayerSAO();
2793 // inform connected clients
2794 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2795 // (u16) 1 + std::string represents a vector serialization representation
2796 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2797 m_clients.sendToAll(¬ice);
2799 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2801 playersao->disconnected();
2808 if(player != NULL && reason != CDR_DENY) {
2809 std::ostringstream os(std::ios_base::binary);
2810 std::vector<u16> clients = m_clients.getClientIDs();
2812 for(std::vector<u16>::iterator i = clients.begin();
2813 i != clients.end(); ++i) {
2815 RemotePlayer *player = m_env->getPlayer(*i);
2819 // Get name of player
2820 os << player->getName() << " ";
2823 std::string name = player->getName();
2824 actionstream << name << " "
2825 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2826 << " List of players: " << os.str() << std::endl;
2828 m_admin_chat->outgoing_queue.push_back(
2829 new ChatEventNick(CET_NICK_REMOVE, name));
2833 MutexAutoLock env_lock(m_env_mutex);
2834 m_clients.DeleteClient(peer_id);
2838 // Send leave chat message to all remaining clients
2839 if(message.length() != 0)
2840 SendChatMessage(PEER_ID_INEXISTENT,message);
2843 void Server::UpdateCrafting(RemotePlayer *player)
2845 DSTACK(FUNCTION_NAME);
2847 // Get a preview for crafting
2849 InventoryLocation loc;
2850 loc.setPlayer(player->getName());
2851 std::vector<ItemStack> output_replacements;
2852 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2853 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2854 (&player->inventory)->getList("craft"), loc);
2856 // Put the new preview in
2857 InventoryList *plist = player->inventory.getList("craftpreview");
2858 sanity_check(plist);
2859 sanity_check(plist->getSize() >= 1);
2860 plist->changeItem(0, preview);
2863 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2865 if (evt->type == CET_NICK_ADD) {
2866 // The terminal informed us of its nick choice
2867 m_admin_nick = ((ChatEventNick *)evt)->nick;
2868 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2869 errorstream << "You haven't set up an account." << std::endl
2870 << "Please log in using the client as '"
2871 << m_admin_nick << "' with a secure password." << std::endl
2872 << "Until then, you can't execute admin tasks via the console," << std::endl
2873 << "and everybody can claim the user account instead of you," << std::endl
2874 << "giving them full control over this server." << std::endl;
2877 assert(evt->type == CET_CHAT);
2878 handleAdminChat((ChatEventChat *)evt);
2882 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2883 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2885 // If something goes wrong, this player is to blame
2886 RollbackScopeActor rollback_scope(m_rollback,
2887 std::string("player:") + name);
2889 if (g_settings->getBool("strip_color_codes"))
2890 wmessage = unescape_enriched(wmessage);
2893 switch (player->canSendChatMessage()) {
2894 case RPLAYER_CHATRESULT_FLOODING: {
2895 std::wstringstream ws;
2896 ws << L"You cannot send more messages. You are limited to "
2897 << g_settings->getFloat("chat_message_limit_per_10sec")
2898 << L" messages per 10 seconds.";
2901 case RPLAYER_CHATRESULT_KICK:
2902 DenyAccess_Legacy(player->peer_id,
2903 L"You have been kicked due to message flooding.");
2905 case RPLAYER_CHATRESULT_OK:
2908 FATAL_ERROR("Unhandled chat filtering result found.");
2912 if (m_max_chatmessage_length > 0
2913 && wmessage.length() > m_max_chatmessage_length) {
2914 return L"Your message exceed the maximum chat message limit set on the server. "
2915 L"It was refused. Send a shorter message";
2918 // Run script hook, exit if script ate the chat message
2919 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2924 // Whether to send line to the player that sent the message, or to all players
2925 bool broadcast_line = true;
2927 if (check_shout_priv && !checkPriv(name, "shout")) {
2928 line += L"-!- You don't have permission to shout.";
2929 broadcast_line = false;
2938 Tell calling method to send the message to sender
2940 if (!broadcast_line) {
2944 Send the message to others
2946 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2948 std::vector<u16> clients = m_clients.getClientIDs();
2951 Send the message back to the inital sender
2952 if they are using protocol version >= 29
2955 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2956 if (player && player->protocol_version >= 29)
2957 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2959 for (u16 i = 0; i < clients.size(); i++) {
2960 u16 cid = clients[i];
2961 if (cid != peer_id_to_avoid_sending)
2962 SendChatMessage(cid, line);
2968 void Server::handleAdminChat(const ChatEventChat *evt)
2970 std::string name = evt->nick;
2971 std::wstring wname = utf8_to_wide(name);
2972 std::wstring wmessage = evt->evt_msg;
2974 std::wstring answer = handleChat(name, wname, wmessage);
2976 // If asked to send answer to sender
2977 if (!answer.empty()) {
2978 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2982 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2984 RemoteClient *client = getClientNoEx(peer_id,state_min);
2986 throw ClientNotFoundException("Client not found");
2990 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2992 return m_clients.getClientNoEx(peer_id, state_min);
2995 std::string Server::getPlayerName(u16 peer_id)
2997 RemotePlayer *player = m_env->getPlayer(peer_id);
2999 return "[id="+itos(peer_id)+"]";
3000 return player->getName();
3003 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3005 RemotePlayer *player = m_env->getPlayer(peer_id);
3008 return player->getPlayerSAO();
3011 std::wstring Server::getStatusString()
3013 std::wostringstream os(std::ios_base::binary);
3016 os<<L"version="<<narrow_to_wide(g_version_string);
3018 os<<L", uptime="<<m_uptime.get();
3020 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3021 // Information about clients
3024 std::vector<u16> clients = m_clients.getClientIDs();
3025 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3027 RemotePlayer *player = m_env->getPlayer(*i);
3028 // Get name of player
3029 std::wstring name = L"unknown";
3031 name = narrow_to_wide(player->getName());
3032 // Add name to information string
3040 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3041 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3042 if(g_settings->get("motd") != "")
3043 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3047 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3049 std::set<std::string> privs;
3050 m_script->getAuth(name, NULL, &privs);
3054 bool Server::checkPriv(const std::string &name, const std::string &priv)
3056 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3057 return (privs.count(priv) != 0);
3060 void Server::reportPrivsModified(const std::string &name)
3063 std::vector<u16> clients = m_clients.getClientIDs();
3064 for(std::vector<u16>::iterator i = clients.begin();
3065 i != clients.end(); ++i) {
3066 RemotePlayer *player = m_env->getPlayer(*i);
3067 reportPrivsModified(player->getName());
3070 RemotePlayer *player = m_env->getPlayer(name.c_str());
3073 SendPlayerPrivileges(player->peer_id);
3074 PlayerSAO *sao = player->getPlayerSAO();
3077 sao->updatePrivileges(
3078 getPlayerEffectivePrivs(name),
3083 void Server::reportInventoryFormspecModified(const std::string &name)
3085 RemotePlayer *player = m_env->getPlayer(name.c_str());
3088 SendPlayerInventoryFormspec(player->peer_id);
3091 void Server::setIpBanned(const std::string &ip, const std::string &name)
3093 m_banmanager->add(ip, name);
3096 void Server::unsetIpBanned(const std::string &ip_or_name)
3098 m_banmanager->remove(ip_or_name);
3101 std::string Server::getBanDescription(const std::string &ip_or_name)
3103 return m_banmanager->getBanDescription(ip_or_name);
3106 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3108 // m_env will be NULL if the server is initializing
3112 if (m_admin_nick == name && !m_admin_nick.empty()) {
3113 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3116 RemotePlayer *player = m_env->getPlayer(name);
3121 if (player->peer_id == PEER_ID_INEXISTENT)
3124 SendChatMessage(player->peer_id, msg);
3127 bool Server::showFormspec(const char *playername, const std::string &formspec,
3128 const std::string &formname)
3130 // m_env will be NULL if the server is initializing
3134 RemotePlayer *player = m_env->getPlayer(playername);
3138 SendShowFormspecMessage(player->peer_id, formspec, formname);
3142 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3147 u32 id = player->addHud(form);
3149 SendHUDAdd(player->peer_id, id, form);
3154 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3158 HudElement* todel = player->removeHud(id);
3165 SendHUDRemove(player->peer_id, id);
3169 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3174 SendHUDChange(player->peer_id, id, stat, data);
3178 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3183 SendHUDSetFlags(player->peer_id, flags, mask);
3184 player->hud_flags &= ~mask;
3185 player->hud_flags |= flags;
3187 PlayerSAO* playersao = player->getPlayerSAO();
3189 if (playersao == NULL)
3192 m_script->player_event(playersao, "hud_changed");
3196 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3201 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3204 player->setHotbarItemcount(hotbar_itemcount);
3205 std::ostringstream os(std::ios::binary);
3206 writeS32(os, hotbar_itemcount);
3207 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3211 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3216 player->setHotbarImage(name);
3217 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3220 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3224 return player->getHotbarImage();
3227 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3232 player->setHotbarSelectedImage(name);
3233 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3236 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3237 v2s32 animation_frames[4], f32 frame_speed)
3242 player->setLocalAnimations(animation_frames, frame_speed);
3243 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3247 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3252 player->eye_offset_first = first;
3253 player->eye_offset_third = third;
3254 SendEyeOffset(player->peer_id, first, third);
3258 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3259 const std::string &type, const std::vector<std::string> ¶ms,
3265 player->setSky(bgcolor, type, params, clouds);
3266 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3270 bool Server::setClouds(RemotePlayer *player, float density,
3271 const video::SColor &color_bright,
3272 const video::SColor &color_ambient,
3280 SendCloudParams(player->peer_id, density,
3281 color_bright, color_ambient, height,
3286 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3292 player->overrideDayNightRatio(do_override, ratio);
3293 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3297 void Server::notifyPlayers(const std::wstring &msg)
3299 SendChatMessage(PEER_ID_INEXISTENT,msg);
3302 void Server::spawnParticle(const std::string &playername, v3f pos,
3303 v3f velocity, v3f acceleration,
3304 float expirationtime, float size, bool
3305 collisiondetection, bool collision_removal,
3306 bool vertical, const std::string &texture,
3307 const struct TileAnimationParams &animation, u8 glow)
3309 // m_env will be NULL if the server is initializing
3313 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3314 if (playername != "") {
3315 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3318 peer_id = player->peer_id;
3319 proto_ver = player->protocol_version;
3322 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3323 expirationtime, size, collisiondetection,
3324 collision_removal, vertical, texture, animation, glow);
3327 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3328 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3329 float minexptime, float maxexptime, float minsize, float maxsize,
3330 bool collisiondetection, bool collision_removal,
3331 ServerActiveObject *attached, bool vertical, const std::string &texture,
3332 const std::string &playername, const struct TileAnimationParams &animation,
3335 // m_env will be NULL if the server is initializing
3339 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3340 if (playername != "") {
3341 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3344 peer_id = player->peer_id;
3345 proto_ver = player->protocol_version;
3348 u16 attached_id = attached ? attached->getId() : 0;
3351 if (attached_id == 0)
3352 id = m_env->addParticleSpawner(spawntime);
3354 id = m_env->addParticleSpawner(spawntime, attached_id);
3356 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3357 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3358 minexptime, maxexptime, minsize, maxsize,
3359 collisiondetection, collision_removal, attached_id, vertical,
3360 texture, id, animation, glow);
3365 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3367 // m_env will be NULL if the server is initializing
3369 throw ServerError("Can't delete particle spawners during initialisation!");
3371 u16 peer_id = PEER_ID_INEXISTENT;
3372 if (playername != "") {
3373 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3376 peer_id = player->peer_id;
3379 m_env->deleteParticleSpawner(id);
3380 SendDeleteParticleSpawner(peer_id, id);
3383 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3385 if(m_detached_inventories.count(name) > 0){
3386 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3387 delete m_detached_inventories[name];
3389 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3391 Inventory *inv = new Inventory(m_itemdef);
3393 m_detached_inventories[name] = inv;
3394 m_detached_inventories_player[name] = player;
3395 //TODO find a better way to do this
3396 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3400 // actions: time-reversed list
3401 // Return value: success/failure
3402 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3403 std::list<std::string> *log)
3405 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3406 ServerMap *map = (ServerMap*)(&m_env->getMap());
3408 // Fail if no actions to handle
3409 if(actions.empty()){
3410 log->push_back("Nothing to do.");
3417 for(std::list<RollbackAction>::const_iterator
3418 i = actions.begin();
3419 i != actions.end(); ++i)
3421 const RollbackAction &action = *i;
3423 bool success = action.applyRevert(map, this, this);
3426 std::ostringstream os;
3427 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3428 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3430 log->push_back(os.str());
3432 std::ostringstream os;
3433 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3434 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3436 log->push_back(os.str());
3440 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3441 <<" failed"<<std::endl;
3443 // Call it done if less than half failed
3444 return num_failed <= num_tried/2;
3447 // IGameDef interface
3449 IItemDefManager *Server::getItemDefManager()
3454 INodeDefManager *Server::getNodeDefManager()
3459 ICraftDefManager *Server::getCraftDefManager()
3464 u16 Server::allocateUnknownNodeId(const std::string &name)
3466 return m_nodedef->allocateDummy(name);
3469 MtEventManager *Server::getEventManager()
3474 IWritableItemDefManager *Server::getWritableItemDefManager()
3479 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3484 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3489 const ModSpec *Server::getModSpec(const std::string &modname) const
3491 std::vector<ModSpec>::const_iterator it;
3492 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3493 const ModSpec &mod = *it;
3494 if (mod.name == modname)
3500 void Server::getModNames(std::vector<std::string> &modlist)
3502 std::vector<ModSpec>::iterator it;
3503 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3504 modlist.push_back(it->name);
3507 std::string Server::getBuiltinLuaPath()
3509 return porting::path_share + DIR_DELIM + "builtin";
3512 std::string Server::getModStoragePath() const
3514 return m_path_world + DIR_DELIM + "mod_storage";
3517 v3f Server::findSpawnPos()
3519 ServerMap &map = m_env->getServerMap();
3521 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3522 return nodeposf * BS;
3525 bool is_good = false;
3527 // Try to find a good place a few times
3528 for(s32 i = 0; i < 4000 && !is_good; i++) {
3530 // We're going to try to throw the player to this position
3531 v2s16 nodepos2d = v2s16(
3532 -range + (myrand() % (range * 2)),
3533 -range + (myrand() % (range * 2)));
3535 // Get spawn level at point
3536 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3537 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3538 // the mapgen to signify an unsuitable spawn position
3539 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3542 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3545 for (s32 i = 0; i < 10; i++) {
3546 v3s16 blockpos = getNodeBlockPos(nodepos);
3547 map.emergeBlock(blockpos, true);
3548 content_t c = map.getNodeNoEx(nodepos).getContent();
3549 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3551 if (air_count >= 2) {
3552 nodeposf = intToFloat(nodepos, BS);
3553 // Don't spawn the player outside map boundaries
3554 if (objectpos_over_limit(nodeposf))
3567 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3569 m_shutdown_timer = delay;
3570 m_shutdown_msg = msg;
3571 m_shutdown_ask_reconnect = reconnect;
3573 if (delay == 0.0f) {
3574 // No delay, shutdown immediately
3575 m_shutdown_requested = true;
3576 // only print to the infostream, a chat message saying
3577 // "Server Shutting Down" is sent when the server destructs.
3578 infostream << "*** Immediate Server shutdown requested." << std::endl;
3579 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3580 // Negative delay, cancel shutdown if requested
3581 m_shutdown_timer = 0.0f;
3582 m_shutdown_msg = "";
3583 m_shutdown_ask_reconnect = false;
3584 m_shutdown_requested = false;
3585 std::wstringstream ws;
3587 ws << L"*** Server shutdown canceled.";
3589 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3590 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3591 } else if (delay > 0.0f) {
3592 // Positive delay, tell the clients when the server will shut down
3593 std::wstringstream ws;
3595 ws << L"*** Server shutting down in "
3596 << duration_to_string(myround(m_shutdown_timer)).c_str()
3599 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3600 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3604 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3607 Try to get an existing player
3609 RemotePlayer *player = m_env->getPlayer(name);
3611 // If player is already connected, cancel
3612 if (player != NULL && player->peer_id != 0) {
3613 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3618 If player with the wanted peer_id already exists, cancel.
3620 if (m_env->getPlayer(peer_id) != NULL) {
3621 infostream<<"emergePlayer(): Player with wrong name but same"
3622 " peer_id already exists"<<std::endl;
3627 player = new RemotePlayer(name, idef());
3630 bool newplayer = false;
3633 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3635 // Complete init with server parts
3636 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3637 player->protocol_version = proto_version;
3641 m_script->on_newplayer(playersao);
3647 bool Server::registerModStorage(ModMetadata *storage)
3649 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3650 errorstream << "Unable to register same mod storage twice. Storage name: "
3651 << storage->getModName() << std::endl;
3655 m_mod_storages[storage->getModName()] = storage;
3659 void Server::unregisterModStorage(const std::string &name)
3661 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3662 if (it != m_mod_storages.end()) {
3663 // Save unconditionaly on unregistration
3664 it->second->save(getModStoragePath());
3665 m_mod_storages.erase(name);
3669 void dedicated_server_loop(Server &server, bool &kill)
3671 DSTACK(FUNCTION_NAME);
3673 verbosestream<<"dedicated_server_loop()"<<std::endl;
3675 IntervalLimiter m_profiler_interval;
3677 static const float steplen = g_settings->getFloat("dedicated_server_step");
3678 static const float profiler_print_interval =
3679 g_settings->getFloat("profiler_print_interval");
3682 // This is kind of a hack but can be done like this
3683 // because server.step() is very light
3685 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3686 sleep_ms((int)(steplen*1000.0));
3688 server.step(steplen);
3690 if (server.getShutdownRequested() || kill)
3696 if (profiler_print_interval != 0) {
3697 if(m_profiler_interval.step(steplen, profiler_print_interval))
3699 infostream<<"Profiler:"<<std::endl;
3700 g_profiler->print(infostream);
3701 g_profiler->clear();
3706 infostream << "Dedicated server quitting" << std::endl;
3708 if (g_settings->getBool("server_announce"))
3709 ServerList::sendAnnounce(ServerList::AA_DELETE,
3710 server.m_bind_addr.getPort());