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_nodemeta.h"
49 #include "content_abm.h"
50 #include "content_sao.h"
52 #include "event_manager.h"
53 #include "serverlist.h"
54 #include "util/string.h"
56 #include "util/serialize.h"
57 #include "util/thread.h"
58 #include "defaultsettings.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
64 class ClientNotFoundException : public BaseException
67 ClientNotFoundException(const char *s):
72 class ServerThread : public Thread
76 ServerThread(Server *server):
87 void *ServerThread::run()
89 DSTACK(FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
92 m_server->AsyncRunStep(true);
94 while (!stopRequested()) {
96 //TimeTaker timer("AsyncRunStep() + Receive()");
98 m_server->AsyncRunStep();
102 } catch (con::NoIncomingDataException &e) {
103 } catch (con::PeerNotFoundException &e) {
104 infostream<<"Server: PeerNotFoundException"<<std::endl;
105 } catch (ClientNotFoundException &e) {
106 } catch (con::ConnectionBindFailed &e) {
107 m_server->setAsyncFatalError(e.what());
108 } catch (LuaError &e) {
109 m_server->setAsyncFatalError(
110 "ServerThread::run Lua: " + std::string(e.what()));
114 END_DEBUG_EXCEPTION_HANDLER
119 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
121 if(pos_exists) *pos_exists = false;
126 if(pos_exists) *pos_exists = true;
131 ServerActiveObject *sao = env->getActiveObject(object);
134 if(pos_exists) *pos_exists = true;
135 return sao->getBasePosition(); }
147 const std::string &path_world,
148 const SubgameSpec &gamespec,
149 bool simple_singleplayer_mode,
154 m_path_world(path_world),
155 m_gamespec(gamespec),
156 m_simple_singleplayer_mode(simple_singleplayer_mode),
157 m_dedicated(dedicated),
158 m_async_fatal_error(""),
167 m_enable_rollback_recording(false),
170 m_itemdef(createItemDefManager()),
171 m_nodedef(createNodeDefManager()),
172 m_craftdef(createCraftDefManager()),
173 m_event(new EventManager()),
175 m_time_of_day_send_timer(0),
178 m_shutdown_requested(false),
179 m_shutdown_ask_reconnect(false),
180 m_shutdown_timer(0.0f),
182 m_ignore_map_edit_events(false),
183 m_ignore_map_edit_events_peer_id(0),
185 m_mod_storage_save_timer(10.0f)
187 m_liquid_transform_timer = 0.0;
188 m_liquid_transform_every = 1.0;
189 m_masterserver_timer = 0.0;
190 m_emergethread_trigger_timer = 0.0;
191 m_savemap_timer = 0.0;
194 m_lag = g_settings->getFloat("dedicated_server_step");
197 throw ServerError("Supplied empty world path");
199 if(!gamespec.isValid())
200 throw ServerError("Supplied invalid gamespec");
202 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
203 if(m_simple_singleplayer_mode)
204 infostream<<" in simple singleplayer mode"<<std::endl;
206 infostream<<std::endl;
207 infostream<<"- world: "<<m_path_world<<std::endl;
208 infostream<<"- game: "<<m_gamespec.path<<std::endl;
210 // Create world if it doesn't exist
211 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
212 throw ServerError("Failed to initialize world");
214 // Create server thread
215 m_thread = new ServerThread(this);
217 // Create emerge manager
218 m_emerge = new EmergeManager(this);
220 // Create ban manager
221 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
222 m_banmanager = new BanManager(ban_path);
224 ServerModConfiguration modconf(m_path_world);
225 m_mods = modconf.getMods();
226 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
227 // complain about mods with unsatisfied dependencies
228 if (!modconf.isConsistent()) {
229 modconf.printUnsatisfiedModsError();
233 MutexAutoLock envlock(m_env_mutex);
235 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
236 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
238 // Initialize scripting
239 infostream<<"Server: Initializing Lua"<<std::endl;
241 m_script = new ServerScripting(this);
243 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
246 infostream << "Server: Loading mods: ";
247 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
248 i != m_mods.end(); ++i) {
249 infostream << (*i).name << " ";
251 infostream << std::endl;
252 // Load and run "mod" scripts
253 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
254 it != m_mods.end(); ++it) {
255 const ModSpec &mod = *it;
256 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
257 throw ModError("Error loading mod \"" + mod.name +
258 "\": Mod name does not follow naming conventions: "
259 "Only characters [a-z0-9_] are allowed.");
261 std::string script_path = mod.path + DIR_DELIM + "init.lua";
262 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
263 << script_path << "\"]" << std::endl;
264 m_script->loadMod(script_path, mod.name);
267 // Read Textures and calculate sha1 sums
270 // Apply item aliases in the node definition manager
271 m_nodedef->updateAliases(m_itemdef);
273 // Apply texture overrides from texturepack/override.txt
274 std::string texture_path = g_settings->get("texture_path");
275 if (texture_path != "" && fs::IsDir(texture_path))
276 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
278 m_nodedef->setNodeRegistrationStatus(true);
280 // Perform pending node name resolutions
281 m_nodedef->runNodeResolveCallbacks();
283 // unmap node names for connected nodeboxes
284 m_nodedef->mapNodeboxConnections();
286 // init the recipe hashes to speed up crafting
287 m_craftdef->initHashes(this);
289 // Initialize Environment
290 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
292 m_clients.setEnv(m_env);
294 if (!servermap->settings_mgr.makeMapgenParams())
295 FATAL_ERROR("Couldn't create any mapgen type");
297 // Initialize mapgens
298 m_emerge->initMapgens(servermap->getMapgenParams());
300 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
301 if (m_enable_rollback_recording) {
302 // Create rollback manager
303 m_rollback = new RollbackManager(m_path_world, this);
306 // Give environment reference to scripting api
307 m_script->initializeEnvironment(m_env);
309 // Register us to receive map edit events
310 servermap->addEventReceiver(this);
312 // If file exists, load environment metadata
313 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
314 infostream << "Server: Loading environment metadata" << std::endl;
317 m_env->loadDefaultMeta();
320 // Add some test ActiveBlockModifiers to environment
321 add_legacy_abms(m_env, m_nodedef);
323 m_liquid_transform_every = g_settings->getFloat("liquid_update");
324 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
329 infostream<<"Server destructing"<<std::endl;
331 // Send shutdown message
332 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
335 MutexAutoLock envlock(m_env_mutex);
337 // Execute script shutdown hooks
338 m_script->on_shutdown();
340 infostream << "Server: Saving players" << std::endl;
341 m_env->saveLoadedPlayers();
343 infostream << "Server: Kicking players" << std::endl;
344 std::string kick_msg;
345 bool reconnect = false;
346 if (getShutdownRequested()) {
347 reconnect = m_shutdown_ask_reconnect;
348 kick_msg = m_shutdown_msg;
350 if (kick_msg == "") {
351 kick_msg = g_settings->get("kick_msg_shutdown");
353 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
354 kick_msg, reconnect);
356 infostream << "Server: Saving environment metadata" << std::endl;
364 // stop all emerge threads before deleting players that may have
365 // requested blocks to be emerged
366 m_emerge->stopThreads();
368 // Delete things in the reverse order of creation
378 // Deinitialize scripting
379 infostream<<"Server: Deinitializing scripting"<<std::endl;
382 // Delete detached inventories
383 for (std::map<std::string, Inventory*>::iterator
384 i = m_detached_inventories.begin();
385 i != m_detached_inventories.end(); ++i) {
390 void Server::start(Address bind_addr)
392 DSTACK(FUNCTION_NAME);
394 m_bind_addr = bind_addr;
396 infostream<<"Starting server on "
397 << bind_addr.serializeString() <<"..."<<std::endl;
399 // Stop thread if already running
402 // Initialize connection
403 m_con.SetTimeoutMs(30);
404 m_con.Serve(bind_addr);
409 // ASCII art for the win!
411 <<" .__ __ __ "<<std::endl
412 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
413 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
414 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
415 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
416 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
417 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
418 actionstream<<"Server for gameid=\""<<m_gamespec.id
419 <<"\" listening on "<<bind_addr.serializeString()<<":"
420 <<bind_addr.getPort() << "."<<std::endl;
425 DSTACK(FUNCTION_NAME);
427 infostream<<"Server: Stopping and waiting threads"<<std::endl;
429 // Stop threads (set run=false first so both start stopping)
431 //m_emergethread.setRun(false);
433 //m_emergethread.stop();
435 infostream<<"Server: Threads stopped"<<std::endl;
438 void Server::step(float dtime)
440 DSTACK(FUNCTION_NAME);
445 MutexAutoLock lock(m_step_dtime_mutex);
446 m_step_dtime += dtime;
448 // Throw if fatal error occurred in thread
449 std::string async_err = m_async_fatal_error.get();
450 if (!async_err.empty()) {
451 if (!m_simple_singleplayer_mode) {
452 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
453 g_settings->get("kick_msg_crash"),
454 g_settings->getBool("ask_reconnect_on_crash"));
456 throw ServerError("AsyncErr: " + async_err);
460 void Server::AsyncRunStep(bool initial_step)
462 DSTACK(FUNCTION_NAME);
464 g_profiler->add("Server::AsyncRunStep (num)", 1);
468 MutexAutoLock lock1(m_step_dtime_mutex);
469 dtime = m_step_dtime;
473 // Send blocks to clients
477 if((dtime < 0.001) && (initial_step == false))
480 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
482 //infostream<<"Server steps "<<dtime<<std::endl;
483 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
486 MutexAutoLock lock1(m_step_dtime_mutex);
487 m_step_dtime -= dtime;
494 m_uptime.set(m_uptime.get() + dtime);
500 Update time of day and overall game time
502 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
505 Send to clients at constant intervals
508 m_time_of_day_send_timer -= dtime;
509 if(m_time_of_day_send_timer < 0.0) {
510 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
511 u16 time = m_env->getTimeOfDay();
512 float time_speed = g_settings->getFloat("time_speed");
513 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
517 MutexAutoLock lock(m_env_mutex);
518 // Figure out and report maximum lag to environment
519 float max_lag = m_env->getMaxLagEstimate();
520 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
522 if(dtime > 0.1 && dtime > max_lag * 2.0)
523 infostream<<"Server: Maximum lag peaked to "<<dtime
527 m_env->reportMaxLagEstimate(max_lag);
529 ScopeProfiler sp(g_profiler, "SEnv step");
530 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
534 static const float map_timer_and_unload_dtime = 2.92;
535 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
537 MutexAutoLock lock(m_env_mutex);
538 // Run Map's timers and unload unused data
539 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
540 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
541 g_settings->getFloat("server_unload_unused_data_timeout"),
546 Listen to the admin chat, if available
549 if (!m_admin_chat->command_queue.empty()) {
550 MutexAutoLock lock(m_env_mutex);
551 while (!m_admin_chat->command_queue.empty()) {
552 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
553 handleChatInterfaceEvent(evt);
557 m_admin_chat->outgoing_queue.push_back(
558 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
565 /* Transform liquids */
566 m_liquid_transform_timer += dtime;
567 if(m_liquid_transform_timer >= m_liquid_transform_every)
569 m_liquid_transform_timer -= m_liquid_transform_every;
571 MutexAutoLock lock(m_env_mutex);
573 ScopeProfiler sp(g_profiler, "Server: liquid transform");
575 std::map<v3s16, MapBlock*> modified_blocks;
576 m_env->getMap().transformLiquids(modified_blocks, m_env);
581 core::map<v3s16, MapBlock*> lighting_modified_blocks;
582 ServerMap &map = ((ServerMap&)m_env->getMap());
583 map.updateLighting(modified_blocks, lighting_modified_blocks);
585 // Add blocks modified by lighting to modified_blocks
586 for(core::map<v3s16, MapBlock*>::Iterator
587 i = lighting_modified_blocks.getIterator();
588 i.atEnd() == false; i++)
590 MapBlock *block = i.getNode()->getValue();
591 modified_blocks.insert(block->getPos(), block);
595 Set the modified blocks unsent for all the clients
597 if(!modified_blocks.empty())
599 SetBlocksNotSent(modified_blocks);
602 m_clients.step(dtime);
604 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
606 // send masterserver announce
608 float &counter = m_masterserver_timer;
609 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
610 g_settings->getBool("server_announce")) {
611 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
612 ServerList::AA_START,
613 m_bind_addr.getPort(),
614 m_clients.getPlayerNames(),
616 m_env->getGameTime(),
619 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
629 Check added and deleted active objects
632 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
633 MutexAutoLock envlock(m_env_mutex);
636 RemoteClientMap clients = m_clients.getClientList();
637 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
639 // Radius inside which objects are active
640 static const s16 radius =
641 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
643 // Radius inside which players are active
644 static const bool is_transfer_limited =
645 g_settings->exists("unlimited_player_transfer_distance") &&
646 !g_settings->getBool("unlimited_player_transfer_distance");
647 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
648 s16 player_radius = player_transfer_dist;
649 if (player_radius == 0 && is_transfer_limited)
650 player_radius = radius;
652 for (RemoteClientMap::iterator i = clients.begin();
653 i != clients.end(); ++i) {
654 RemoteClient *client = i->second;
656 // If definitions and textures have not been sent, don't
657 // send objects either
658 if (client->getState() < CS_DefinitionsSent)
661 RemotePlayer *player = m_env->getPlayer(client->peer_id);
662 if (player == NULL) {
663 // This can happen if the client timeouts somehow
664 /*warningstream<<FUNCTION_NAME<<": Client "
666 <<" has no associated player"<<std::endl;*/
670 PlayerSAO *playersao = player->getPlayerSAO();
671 if (playersao == NULL)
674 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
675 if (my_radius <= 0) my_radius = radius;
676 //infostream << "Server: Active Radius " << my_radius << std::endl;
678 std::queue<u16> removed_objects;
679 std::queue<u16> added_objects;
680 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
681 client->m_known_objects, removed_objects);
682 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
683 client->m_known_objects, added_objects);
685 // Ignore if nothing happened
686 if (removed_objects.empty() && added_objects.empty()) {
690 std::string data_buffer;
694 // Handle removed objects
695 writeU16((u8*)buf, removed_objects.size());
696 data_buffer.append(buf, 2);
697 while (!removed_objects.empty()) {
699 u16 id = removed_objects.front();
700 ServerActiveObject* obj = m_env->getActiveObject(id);
702 // Add to data buffer for sending
703 writeU16((u8*)buf, id);
704 data_buffer.append(buf, 2);
706 // Remove from known objects
707 client->m_known_objects.erase(id);
709 if(obj && obj->m_known_by_count > 0)
710 obj->m_known_by_count--;
711 removed_objects.pop();
714 // Handle added objects
715 writeU16((u8*)buf, added_objects.size());
716 data_buffer.append(buf, 2);
717 while (!added_objects.empty()) {
719 u16 id = added_objects.front();
720 ServerActiveObject* obj = m_env->getActiveObject(id);
723 u8 type = ACTIVEOBJECT_TYPE_INVALID;
725 warningstream<<FUNCTION_NAME
726 <<": NULL object"<<std::endl;
728 type = obj->getSendType();
730 // Add to data buffer for sending
731 writeU16((u8*)buf, id);
732 data_buffer.append(buf, 2);
733 writeU8((u8*)buf, type);
734 data_buffer.append(buf, 1);
737 data_buffer.append(serializeLongString(
738 obj->getClientInitializationData(client->net_proto_version)));
740 data_buffer.append(serializeLongString(""));
742 // Add to known objects
743 client->m_known_objects.insert(id);
746 obj->m_known_by_count++;
751 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
752 verbosestream << "Server: Sent object remove/add: "
753 << removed_objects.size() << " removed, "
754 << added_objects.size() << " added, "
755 << "packet size is " << pktSize << std::endl;
759 m_mod_storage_save_timer -= dtime;
760 if (m_mod_storage_save_timer <= 0.0f) {
761 infostream << "Saving registered mod storages." << std::endl;
762 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
763 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
764 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
765 if (it->second->isModified()) {
766 it->second->save(getModStoragePath());
776 MutexAutoLock envlock(m_env_mutex);
777 ScopeProfiler sp(g_profiler, "Server: sending object messages");
780 // Value = data sent by object
781 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
783 // Get active object messages from environment
785 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
789 std::vector<ActiveObjectMessage>* message_list = NULL;
790 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
791 n = buffered_messages.find(aom.id);
792 if (n == buffered_messages.end()) {
793 message_list = new std::vector<ActiveObjectMessage>;
794 buffered_messages[aom.id] = message_list;
797 message_list = n->second;
799 message_list->push_back(aom);
803 RemoteClientMap clients = m_clients.getClientList();
804 // Route data to every client
805 for (std::unordered_map<u16, RemoteClient*>::iterator i = clients.begin();
806 i != clients.end(); ++i) {
807 RemoteClient *client = i->second;
808 std::string reliable_data;
809 std::string unreliable_data;
810 // Go through all objects in message buffer
811 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
812 j = buffered_messages.begin();
813 j != buffered_messages.end(); ++j) {
814 // If object is not known by client, skip it
816 if (client->m_known_objects.find(id) == client->m_known_objects.end())
819 // Get message list of object
820 std::vector<ActiveObjectMessage>* list = j->second;
821 // Go through every message
822 for (std::vector<ActiveObjectMessage>::iterator
823 k = list->begin(); k != list->end(); ++k) {
824 // Compose the full new data with header
825 ActiveObjectMessage aom = *k;
826 std::string new_data;
829 writeU16((u8*)&buf[0], aom.id);
830 new_data.append(buf, 2);
832 new_data += serializeString(aom.datastring);
833 // Add data to buffer
835 reliable_data += new_data;
837 unreliable_data += new_data;
841 reliable_data and unreliable_data are now ready.
844 if(reliable_data.size() > 0) {
845 SendActiveObjectMessages(client->peer_id, reliable_data);
848 if(unreliable_data.size() > 0) {
849 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
854 // Clear buffered_messages
855 for (std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator
856 i = buffered_messages.begin();
857 i != buffered_messages.end(); ++i) {
863 Send queued-for-sending map edit events.
866 // We will be accessing the environment
867 MutexAutoLock lock(m_env_mutex);
869 // Don't send too many at a time
872 // Single change sending is disabled if queue size is not small
873 bool disable_single_change_sending = false;
874 if(m_unsent_map_edit_queue.size() >= 4)
875 disable_single_change_sending = true;
877 int event_count = m_unsent_map_edit_queue.size();
879 // We'll log the amount of each
882 while(m_unsent_map_edit_queue.size() != 0)
884 MapEditEvent* event = m_unsent_map_edit_queue.front();
885 m_unsent_map_edit_queue.pop();
887 // Players far away from the change are stored here.
888 // Instead of sending the changes, MapBlocks are set not sent
890 std::vector<u16> far_players;
892 switch (event->type) {
895 prof.add("MEET_ADDNODE", 1);
896 sendAddNode(event->p, event->n, event->already_known_by_peer,
897 &far_players, disable_single_change_sending ? 5 : 30,
898 event->type == MEET_ADDNODE);
900 case MEET_REMOVENODE:
901 prof.add("MEET_REMOVENODE", 1);
902 sendRemoveNode(event->p, event->already_known_by_peer,
903 &far_players, disable_single_change_sending ? 5 : 30);
905 case MEET_BLOCK_NODE_METADATA_CHANGED:
906 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
907 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
908 setBlockNotSent(event->p);
911 infostream << "Server: MEET_OTHER" << std::endl;
912 prof.add("MEET_OTHER", 1);
913 for(std::set<v3s16>::iterator
914 i = event->modified_blocks.begin();
915 i != event->modified_blocks.end(); ++i) {
920 prof.add("unknown", 1);
921 warningstream << "Server: Unknown MapEditEvent "
922 << ((u32)event->type) << std::endl;
927 Set blocks not sent to far players
929 if(!far_players.empty()) {
930 // Convert list format to that wanted by SetBlocksNotSent
931 std::map<v3s16, MapBlock*> modified_blocks2;
932 for(std::set<v3s16>::iterator
933 i = event->modified_blocks.begin();
934 i != event->modified_blocks.end(); ++i) {
935 modified_blocks2[*i] =
936 m_env->getMap().getBlockNoCreateNoEx(*i);
939 // Set blocks not sent
940 for(std::vector<u16>::iterator
941 i = far_players.begin();
942 i != far_players.end(); ++i) {
943 if(RemoteClient *client = getClient(*i))
944 client->SetBlocksNotSent(modified_blocks2);
950 /*// Don't send too many at a time
952 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
956 if(event_count >= 5){
957 infostream<<"Server: MapEditEvents:"<<std::endl;
958 prof.print(infostream);
959 } else if(event_count != 0){
960 verbosestream<<"Server: MapEditEvents:"<<std::endl;
961 prof.print(verbosestream);
967 Trigger emergethread (it somehow gets to a non-triggered but
968 bysy state sometimes)
971 float &counter = m_emergethread_trigger_timer;
973 if (counter >= 2.0) {
976 m_emerge->startThreads();
980 // Save map, players and auth stuff
982 float &counter = m_savemap_timer;
984 static const float save_interval =
985 g_settings->getFloat("server_map_save_interval");
986 if (counter >= save_interval) {
988 MutexAutoLock lock(m_env_mutex);
990 ScopeProfiler sp(g_profiler, "Server: saving stuff");
993 if (m_banmanager->isModified()) {
994 m_banmanager->save();
997 // Save changed parts of map
998 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1001 m_env->saveLoadedPlayers();
1003 // Save environment metadata
1009 static const float shutdown_msg_times[] =
1011 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
1014 if (m_shutdown_timer > 0.0f) {
1015 // Automated messages
1016 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
1017 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
1018 // If shutdown timer matches an automessage, shot it
1019 if (m_shutdown_timer > shutdown_msg_times[i] &&
1020 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1021 std::wstringstream ws;
1023 ws << L"*** Server shutting down in "
1024 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1027 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1028 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1034 m_shutdown_timer -= dtime;
1035 if (m_shutdown_timer < 0.0f) {
1036 m_shutdown_timer = 0.0f;
1037 m_shutdown_requested = true;
1042 void Server::Receive()
1044 DSTACK(FUNCTION_NAME);
1045 SharedBuffer<u8> data;
1049 m_con.Receive(&pkt);
1050 peer_id = pkt.getPeerId();
1053 catch(con::InvalidIncomingDataException &e) {
1054 infostream<<"Server::Receive(): "
1055 "InvalidIncomingDataException: what()="
1056 <<e.what()<<std::endl;
1058 catch(SerializationError &e) {
1059 infostream<<"Server::Receive(): "
1060 "SerializationError: what()="
1061 <<e.what()<<std::endl;
1063 catch(ClientStateError &e) {
1064 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1065 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1066 L"Try reconnecting or updating your client");
1068 catch(con::PeerNotFoundException &e) {
1073 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1075 std::string playername = "";
1076 PlayerSAO *playersao = NULL;
1079 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1080 if (client != NULL) {
1081 playername = client->getName();
1082 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1084 } catch (std::exception &e) {
1090 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1092 // If failed, cancel
1093 if ((playersao == NULL) || (player == NULL)) {
1094 if (player && player->peer_id != 0) {
1095 actionstream << "Server: Failed to emerge player \"" << playername
1096 << "\" (player allocated to an another client)" << std::endl;
1097 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1098 L"name. If your client closed unexpectedly, try again in "
1101 errorstream << "Server: " << playername << ": Failed to emerge player"
1103 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1109 Send complete position information
1111 SendMovePlayer(peer_id);
1114 SendPlayerPrivileges(peer_id);
1116 // Send inventory formspec
1117 SendPlayerInventoryFormspec(peer_id);
1120 SendInventory(playersao);
1122 // Send HP or death screen
1123 if (playersao->isDead())
1124 SendDeathscreen(peer_id, false, v3f(0,0,0));
1126 SendPlayerHPOrDie(playersao);
1129 SendPlayerBreath(playersao);
1131 // Note things in chat if not in simple singleplayer mode
1132 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1133 // Send information about server to player in chat
1134 SendChatMessage(peer_id, getStatusString());
1136 Address addr = getPeerAddress(player->peer_id);
1137 std::string ip_str = addr.serializeString();
1138 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1143 const std::vector<std::string> &names = m_clients.getPlayerNames();
1145 actionstream << player->getName() << " joins game. List of players: ";
1147 for (std::vector<std::string>::const_iterator i = names.begin();
1148 i != names.end(); ++i) {
1149 actionstream << *i << " ";
1152 actionstream << player->getName() <<std::endl;
1157 inline void Server::handleCommand(NetworkPacket* pkt)
1159 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1160 (this->*opHandle.handler)(pkt);
1163 void Server::ProcessData(NetworkPacket *pkt)
1165 DSTACK(FUNCTION_NAME);
1166 // Environment is locked first.
1167 MutexAutoLock envlock(m_env_mutex);
1169 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1170 u32 peer_id = pkt->getPeerId();
1173 Address address = getPeerAddress(peer_id);
1174 std::string addr_s = address.serializeString();
1176 if(m_banmanager->isIpBanned(addr_s)) {
1177 std::string ban_name = m_banmanager->getBanName(addr_s);
1178 infostream << "Server: A banned client tried to connect from "
1179 << addr_s << "; banned name was "
1180 << ban_name << std::endl;
1181 // This actually doesn't seem to transfer to the client
1182 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1183 + utf8_to_wide(ban_name));
1187 catch(con::PeerNotFoundException &e) {
1189 * no peer for this packet found
1190 * most common reason is peer timeout, e.g. peer didn't
1191 * respond for some time, your server was overloaded or
1194 infostream << "Server::ProcessData(): Canceling: peer "
1195 << peer_id << " not found" << std::endl;
1200 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1202 // Command must be handled into ToServerCommandHandler
1203 if (command >= TOSERVER_NUM_MSG_TYPES) {
1204 infostream << "Server: Ignoring unknown command "
1205 << command << std::endl;
1209 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1214 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1216 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1217 errorstream << "Server::ProcessData(): Cancelling: Peer"
1218 " serialization format invalid or not initialized."
1219 " Skipping incoming command=" << command << std::endl;
1223 /* Handle commands related to client startup */
1224 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1229 if (m_clients.getClientState(peer_id) < CS_Active) {
1230 if (command == TOSERVER_PLAYERPOS) return;
1232 errorstream << "Got packet command: " << command << " for peer id "
1233 << peer_id << " but client isn't active yet. Dropping packet "
1239 } catch (SendFailedException &e) {
1240 errorstream << "Server::ProcessData(): SendFailedException: "
1241 << "what=" << e.what()
1243 } catch (PacketError &e) {
1244 actionstream << "Server::ProcessData(): PacketError: "
1245 << "what=" << e.what()
1250 void Server::setTimeOfDay(u32 time)
1252 m_env->setTimeOfDay(time);
1253 m_time_of_day_send_timer = 0;
1256 void Server::onMapEditEvent(MapEditEvent *event)
1258 if(m_ignore_map_edit_events)
1260 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1262 MapEditEvent *e = event->clone();
1263 m_unsent_map_edit_queue.push(e);
1266 Inventory* Server::getInventory(const InventoryLocation &loc)
1269 case InventoryLocation::UNDEFINED:
1270 case InventoryLocation::CURRENT_PLAYER:
1272 case InventoryLocation::PLAYER:
1274 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1277 PlayerSAO *playersao = player->getPlayerSAO();
1280 return playersao->getInventory();
1283 case InventoryLocation::NODEMETA:
1285 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1288 return meta->getInventory();
1291 case InventoryLocation::DETACHED:
1293 if(m_detached_inventories.count(loc.name) == 0)
1295 return m_detached_inventories[loc.name];
1299 sanity_check(false); // abort
1304 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1307 case InventoryLocation::UNDEFINED:
1309 case InventoryLocation::PLAYER:
1314 RemotePlayer *player =
1315 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1320 PlayerSAO *playersao = player->getPlayerSAO();
1324 SendInventory(playersao);
1327 case InventoryLocation::NODEMETA:
1329 v3s16 blockpos = getNodeBlockPos(loc.p);
1331 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1333 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1335 setBlockNotSent(blockpos);
1338 case InventoryLocation::DETACHED:
1340 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1344 sanity_check(false); // abort
1349 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1351 std::vector<u16> clients = m_clients.getClientIDs();
1353 // Set the modified blocks unsent for all the clients
1354 for (std::vector<u16>::iterator i = clients.begin();
1355 i != clients.end(); ++i) {
1356 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1357 client->SetBlocksNotSent(block);
1362 void Server::peerAdded(con::Peer *peer)
1364 DSTACK(FUNCTION_NAME);
1365 verbosestream<<"Server::peerAdded(): peer->id="
1366 <<peer->id<<std::endl;
1369 c.type = con::PEER_ADDED;
1370 c.peer_id = peer->id;
1372 m_peer_change_queue.push(c);
1375 void Server::deletingPeer(con::Peer *peer, bool timeout)
1377 DSTACK(FUNCTION_NAME);
1378 verbosestream<<"Server::deletingPeer(): peer->id="
1379 <<peer->id<<", timeout="<<timeout<<std::endl;
1381 m_clients.event(peer->id, CSE_Disconnect);
1383 c.type = con::PEER_REMOVED;
1384 c.peer_id = peer->id;
1385 c.timeout = timeout;
1386 m_peer_change_queue.push(c);
1389 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1391 *retval = m_con.getPeerStat(peer_id,type);
1392 if (*retval == -1) return false;
1396 bool Server::getClientInfo(
1405 std::string* vers_string
1408 *state = m_clients.getClientState(peer_id);
1410 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1412 if (client == NULL) {
1417 *uptime = client->uptime();
1418 *ser_vers = client->serialization_version;
1419 *prot_vers = client->net_proto_version;
1421 *major = client->getMajor();
1422 *minor = client->getMinor();
1423 *patch = client->getPatch();
1424 *vers_string = client->getPatch();
1431 void Server::handlePeerChanges()
1433 while(m_peer_change_queue.size() > 0)
1435 con::PeerChange c = m_peer_change_queue.front();
1436 m_peer_change_queue.pop();
1438 verbosestream<<"Server: Handling peer change: "
1439 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1444 case con::PEER_ADDED:
1445 m_clients.CreateClient(c.peer_id);
1448 case con::PEER_REMOVED:
1449 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1453 FATAL_ERROR("Invalid peer change event received!");
1459 void Server::printToConsoleOnly(const std::string &text)
1462 m_admin_chat->outgoing_queue.push_back(
1463 new ChatEventChat("", utf8_to_wide(text)));
1465 std::cout << text << std::endl;
1469 void Server::Send(NetworkPacket* pkt)
1471 m_clients.send(pkt->getPeerId(),
1472 clientCommandFactoryTable[pkt->getCommand()].channel,
1474 clientCommandFactoryTable[pkt->getCommand()].reliable);
1477 void Server::SendMovement(u16 peer_id)
1479 DSTACK(FUNCTION_NAME);
1480 std::ostringstream os(std::ios_base::binary);
1482 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1484 pkt << g_settings->getFloat("movement_acceleration_default");
1485 pkt << g_settings->getFloat("movement_acceleration_air");
1486 pkt << g_settings->getFloat("movement_acceleration_fast");
1487 pkt << g_settings->getFloat("movement_speed_walk");
1488 pkt << g_settings->getFloat("movement_speed_crouch");
1489 pkt << g_settings->getFloat("movement_speed_fast");
1490 pkt << g_settings->getFloat("movement_speed_climb");
1491 pkt << g_settings->getFloat("movement_speed_jump");
1492 pkt << g_settings->getFloat("movement_liquid_fluidity");
1493 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1494 pkt << g_settings->getFloat("movement_liquid_sink");
1495 pkt << g_settings->getFloat("movement_gravity");
1500 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1502 if (!g_settings->getBool("enable_damage"))
1505 u16 peer_id = playersao->getPeerID();
1506 bool is_alive = playersao->getHP() > 0;
1509 SendPlayerHP(peer_id);
1514 void Server::SendHP(u16 peer_id, u8 hp)
1516 DSTACK(FUNCTION_NAME);
1518 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1523 void Server::SendBreath(u16 peer_id, u16 breath)
1525 DSTACK(FUNCTION_NAME);
1527 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1528 pkt << (u16) breath;
1532 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1533 const std::string &custom_reason, bool reconnect)
1535 assert(reason < SERVER_ACCESSDENIED_MAX);
1537 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1539 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1540 pkt << custom_reason;
1541 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1542 reason == SERVER_ACCESSDENIED_CRASH)
1543 pkt << custom_reason << (u8)reconnect;
1547 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1549 DSTACK(FUNCTION_NAME);
1551 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1556 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1557 v3f camera_point_target)
1559 DSTACK(FUNCTION_NAME);
1561 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1562 pkt << set_camera_point_target << camera_point_target;
1566 void Server::SendItemDef(u16 peer_id,
1567 IItemDefManager *itemdef, u16 protocol_version)
1569 DSTACK(FUNCTION_NAME);
1571 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1575 u32 length of the next item
1576 zlib-compressed serialized ItemDefManager
1578 std::ostringstream tmp_os(std::ios::binary);
1579 itemdef->serialize(tmp_os, protocol_version);
1580 std::ostringstream tmp_os2(std::ios::binary);
1581 compressZlib(tmp_os.str(), tmp_os2);
1582 pkt.putLongString(tmp_os2.str());
1585 verbosestream << "Server: Sending item definitions to id(" << peer_id
1586 << "): size=" << pkt.getSize() << std::endl;
1591 void Server::SendNodeDef(u16 peer_id,
1592 INodeDefManager *nodedef, u16 protocol_version)
1594 DSTACK(FUNCTION_NAME);
1596 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1600 u32 length of the next item
1601 zlib-compressed serialized NodeDefManager
1603 std::ostringstream tmp_os(std::ios::binary);
1604 nodedef->serialize(tmp_os, protocol_version);
1605 std::ostringstream tmp_os2(std::ios::binary);
1606 compressZlib(tmp_os.str(), tmp_os2);
1608 pkt.putLongString(tmp_os2.str());
1611 verbosestream << "Server: Sending node definitions to id(" << peer_id
1612 << "): size=" << pkt.getSize() << std::endl;
1618 Non-static send methods
1621 void Server::SendInventory(PlayerSAO* playerSAO)
1623 DSTACK(FUNCTION_NAME);
1625 UpdateCrafting(playerSAO->getPlayer());
1631 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1633 std::ostringstream os;
1634 playerSAO->getInventory()->serialize(os);
1636 std::string s = os.str();
1638 pkt.putRawString(s.c_str(), s.size());
1642 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1644 DSTACK(FUNCTION_NAME);
1646 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1649 if (peer_id != PEER_ID_INEXISTENT) {
1653 m_clients.sendToAll(&pkt);
1657 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1658 const std::string &formname)
1660 DSTACK(FUNCTION_NAME);
1662 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1663 if (formspec == "" ){
1664 //the client should close the formspec
1665 pkt.putLongString("");
1667 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1674 // Spawns a particle on peer with peer_id
1675 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1676 v3f pos, v3f velocity, v3f acceleration,
1677 float expirationtime, float size, bool collisiondetection,
1678 bool collision_removal,
1679 bool vertical, const std::string &texture,
1680 const struct TileAnimationParams &animation, u8 glow)
1682 DSTACK(FUNCTION_NAME);
1683 static const float radius =
1684 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1686 if (peer_id == PEER_ID_INEXISTENT) {
1687 std::vector<u16> clients = m_clients.getClientIDs();
1689 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1690 RemotePlayer *player = m_env->getPlayer(*i);
1694 PlayerSAO *sao = player->getPlayerSAO();
1698 // Do not send to distant clients
1699 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1702 SendSpawnParticle(*i, player->protocol_version,
1703 pos, velocity, acceleration,
1704 expirationtime, size, collisiondetection,
1705 collision_removal, vertical, texture, animation, glow);
1710 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1712 pkt << pos << velocity << acceleration << expirationtime
1713 << size << collisiondetection;
1714 pkt.putLongString(texture);
1716 pkt << collision_removal;
1717 // This is horrible but required (why are there two ways to serialize pkts?)
1718 std::ostringstream os(std::ios_base::binary);
1719 animation.serialize(os, protocol_version);
1720 pkt.putRawString(os.str());
1726 // Adds a ParticleSpawner on peer with peer_id
1727 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1728 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1729 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1730 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1731 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1732 const struct TileAnimationParams &animation, u8 glow)
1734 DSTACK(FUNCTION_NAME);
1735 if (peer_id == PEER_ID_INEXISTENT) {
1736 // This sucks and should be replaced:
1737 std::vector<u16> clients = m_clients.getClientIDs();
1738 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1739 RemotePlayer *player = m_env->getPlayer(*i);
1742 SendAddParticleSpawner(*i, player->protocol_version,
1743 amount, spawntime, minpos, maxpos,
1744 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1745 minsize, maxsize, collisiondetection, collision_removal,
1746 attached_id, vertical, texture, id, animation, glow);
1751 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1753 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1754 << minacc << maxacc << minexptime << maxexptime << minsize
1755 << maxsize << collisiondetection;
1757 pkt.putLongString(texture);
1759 pkt << id << vertical;
1760 pkt << collision_removal;
1762 // This is horrible but required
1763 std::ostringstream os(std::ios_base::binary);
1764 animation.serialize(os, protocol_version);
1765 pkt.putRawString(os.str());
1771 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1773 DSTACK(FUNCTION_NAME);
1775 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1777 // Ugly error in this packet
1780 if (peer_id != PEER_ID_INEXISTENT) {
1784 m_clients.sendToAll(&pkt);
1789 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1791 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1793 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1794 << form->text << form->number << form->item << form->dir
1795 << form->align << form->offset << form->world_pos << form->size;
1800 void Server::SendHUDRemove(u16 peer_id, u32 id)
1802 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1807 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1809 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1810 pkt << id << (u8) stat;
1814 case HUD_STAT_SCALE:
1815 case HUD_STAT_ALIGN:
1816 case HUD_STAT_OFFSET:
1817 pkt << *(v2f *) value;
1821 pkt << *(std::string *) value;
1823 case HUD_STAT_WORLD_POS:
1824 pkt << *(v3f *) value;
1827 pkt << *(v2s32 *) value;
1829 case HUD_STAT_NUMBER:
1833 pkt << *(u32 *) value;
1840 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1842 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1844 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1846 pkt << flags << mask;
1851 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1853 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1854 pkt << param << value;
1858 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1859 const std::string &type, const std::vector<std::string> ¶ms,
1862 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1863 pkt << bgcolor << type << (u16) params.size();
1865 for(size_t i=0; i<params.size(); i++)
1873 void Server::SendCloudParams(u16 peer_id, float density,
1874 const video::SColor &color_bright,
1875 const video::SColor &color_ambient,
1880 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1881 pkt << density << color_bright << color_ambient
1882 << height << thickness << speed;
1887 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1890 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1893 pkt << do_override << (u16) (ratio * 65535);
1898 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1900 DSTACK(FUNCTION_NAME);
1902 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1903 pkt << time << time_speed;
1905 if (peer_id == PEER_ID_INEXISTENT) {
1906 m_clients.sendToAll(&pkt);
1913 void Server::SendPlayerHP(u16 peer_id)
1915 DSTACK(FUNCTION_NAME);
1916 PlayerSAO *playersao = getPlayerSAO(peer_id);
1917 // In some rare case if the player is disconnected
1918 // while Lua call l_punch, for example, this can be NULL
1922 SendHP(peer_id, playersao->getHP());
1923 m_script->player_event(playersao,"health_changed");
1925 // Send to other clients
1926 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1927 ActiveObjectMessage aom(playersao->getId(), true, str);
1928 playersao->m_messages_out.push(aom);
1931 void Server::SendPlayerBreath(PlayerSAO *sao)
1933 DSTACK(FUNCTION_NAME);
1936 m_script->player_event(sao, "breath_changed");
1937 SendBreath(sao->getPeerID(), sao->getBreath());
1940 void Server::SendMovePlayer(u16 peer_id)
1942 DSTACK(FUNCTION_NAME);
1943 RemotePlayer *player = m_env->getPlayer(peer_id);
1945 PlayerSAO *sao = player->getPlayerSAO();
1948 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1949 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1952 v3f pos = sao->getBasePosition();
1953 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1954 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1955 << " pitch=" << sao->getPitch()
1956 << " yaw=" << sao->getYaw()
1963 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1965 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1968 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1969 << animation_frames[3] << animation_speed;
1974 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1976 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1977 pkt << first << third;
1980 void Server::SendPlayerPrivileges(u16 peer_id)
1982 RemotePlayer *player = m_env->getPlayer(peer_id);
1984 if(player->peer_id == PEER_ID_INEXISTENT)
1987 std::set<std::string> privs;
1988 m_script->getAuth(player->getName(), NULL, &privs);
1990 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1991 pkt << (u16) privs.size();
1993 for(std::set<std::string>::const_iterator i = privs.begin();
1994 i != privs.end(); ++i) {
2001 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2003 RemotePlayer *player = m_env->getPlayer(peer_id);
2005 if(player->peer_id == PEER_ID_INEXISTENT)
2008 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2009 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2013 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2015 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2016 pkt.putRawString(datas.c_str(), datas.size());
2018 return pkt.getSize();
2021 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2023 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2024 datas.size(), peer_id);
2026 pkt.putRawString(datas.c_str(), datas.size());
2028 m_clients.send(pkt.getPeerId(),
2029 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2034 s32 Server::playSound(const SimpleSoundSpec &spec,
2035 const ServerSoundParams ¶ms)
2037 // Find out initial position of sound
2038 bool pos_exists = false;
2039 v3f pos = params.getPos(m_env, &pos_exists);
2040 // If position is not found while it should be, cancel sound
2041 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2044 // Filter destination clients
2045 std::vector<u16> dst_clients;
2046 if(params.to_player != "")
2048 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2050 infostream<<"Server::playSound: Player \""<<params.to_player
2051 <<"\" not found"<<std::endl;
2054 if(player->peer_id == PEER_ID_INEXISTENT){
2055 infostream<<"Server::playSound: Player \""<<params.to_player
2056 <<"\" not connected"<<std::endl;
2059 dst_clients.push_back(player->peer_id);
2062 std::vector<u16> clients = m_clients.getClientIDs();
2064 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2065 RemotePlayer *player = m_env->getPlayer(*i);
2069 PlayerSAO *sao = player->getPlayerSAO();
2074 if(sao->getBasePosition().getDistanceFrom(pos) >
2075 params.max_hear_distance)
2078 dst_clients.push_back(*i);
2082 if(dst_clients.empty())
2086 s32 id = m_next_sound_id++;
2087 // The sound will exist as a reference in m_playing_sounds
2088 m_playing_sounds[id] = ServerPlayingSound();
2089 ServerPlayingSound &psound = m_playing_sounds[id];
2090 psound.params = params;
2093 float gain = params.gain * spec.gain;
2094 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2095 pkt << id << spec.name << gain
2096 << (u8) params.type << pos << params.object
2097 << params.loop << params.fade;
2099 // Backwards compability
2100 bool play_sound = gain > 0;
2102 for (std::vector<u16>::iterator i = dst_clients.begin();
2103 i != dst_clients.end(); ++i) {
2104 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2105 psound.clients.insert(*i);
2106 m_clients.send(*i, 0, &pkt, true);
2111 void Server::stopSound(s32 handle)
2113 // Get sound reference
2114 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2115 m_playing_sounds.find(handle);
2116 if (i == m_playing_sounds.end())
2118 ServerPlayingSound &psound = i->second;
2120 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2123 for (std::unordered_set<u16>::const_iterator si = psound.clients.begin();
2124 si != psound.clients.end(); ++si) {
2126 m_clients.send(*si, 0, &pkt, true);
2128 // Remove sound reference
2129 m_playing_sounds.erase(i);
2132 void Server::fadeSound(s32 handle, float step, float gain)
2134 // Get sound reference
2135 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2136 m_playing_sounds.find(handle);
2137 if (i == m_playing_sounds.end())
2140 ServerPlayingSound &psound = i->second;
2141 psound.params.gain = gain;
2143 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2144 pkt << handle << step << gain;
2146 // Backwards compability
2147 bool play_sound = gain > 0;
2148 ServerPlayingSound compat_psound = psound;
2149 compat_psound.clients.clear();
2151 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2152 compat_pkt << handle;
2154 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2155 it != psound.clients.end();) {
2156 if (m_clients.getProtocolVersion(*it) >= 32) {
2158 m_clients.send(*it, 0, &pkt, true);
2161 compat_psound.clients.insert(*it);
2163 m_clients.send(*it, 0, &compat_pkt, true);
2164 psound.clients.erase(it++);
2168 // Remove sound reference
2169 if (!play_sound || psound.clients.size() == 0)
2170 m_playing_sounds.erase(i);
2172 if (play_sound && compat_psound.clients.size() > 0) {
2173 // Play new sound volume on older clients
2174 playSound(compat_psound.spec, compat_psound.params);
2178 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2179 std::vector<u16> *far_players, float far_d_nodes)
2181 float maxd = far_d_nodes*BS;
2182 v3f p_f = intToFloat(p, BS);
2184 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2187 std::vector<u16> clients = m_clients.getClientIDs();
2188 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2191 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2192 PlayerSAO *sao = player->getPlayerSAO();
2196 // If player is far away, only set modified blocks not sent
2197 v3f player_pos = sao->getBasePosition();
2198 if (player_pos.getDistanceFrom(p_f) > maxd) {
2199 far_players->push_back(*i);
2206 m_clients.send(*i, 0, &pkt, true);
2210 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2211 std::vector<u16> *far_players, float far_d_nodes,
2212 bool remove_metadata)
2214 float maxd = far_d_nodes*BS;
2215 v3f p_f = intToFloat(p, BS);
2217 std::vector<u16> clients = m_clients.getClientIDs();
2218 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2221 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2222 PlayerSAO *sao = player->getPlayerSAO();
2226 // If player is far away, only set modified blocks not sent
2227 v3f player_pos = sao->getBasePosition();
2228 if(player_pos.getDistanceFrom(p_f) > maxd) {
2229 far_players->push_back(*i);
2235 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2237 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2239 pkt << p << n.param0 << n.param1 << n.param2
2240 << (u8) (remove_metadata ? 0 : 1);
2245 if (pkt.getSize() > 0)
2246 m_clients.send(*i, 0, &pkt, true);
2250 void Server::setBlockNotSent(v3s16 p)
2252 std::vector<u16> clients = m_clients.getClientIDs();
2254 for(std::vector<u16>::iterator i = clients.begin();
2255 i != clients.end(); ++i) {
2256 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2257 client->SetBlockNotSent(p);
2262 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2264 DSTACK(FUNCTION_NAME);
2266 v3s16 p = block->getPos();
2269 Create a packet with the block in the right format
2272 std::ostringstream os(std::ios_base::binary);
2273 block->serialize(os, ver, false);
2274 block->serializeNetworkSpecific(os);
2275 std::string s = os.str();
2277 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2280 pkt.putRawString(s.c_str(), s.size());
2284 void Server::SendBlocks(float dtime)
2286 DSTACK(FUNCTION_NAME);
2288 MutexAutoLock envlock(m_env_mutex);
2289 //TODO check if one big lock could be faster then multiple small ones
2291 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2293 std::vector<PrioritySortedBlockTransfer> queue;
2295 s32 total_sending = 0;
2298 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2300 std::vector<u16> clients = m_clients.getClientIDs();
2303 for(std::vector<u16>::iterator i = clients.begin();
2304 i != clients.end(); ++i) {
2305 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2310 total_sending += client->SendingCount();
2311 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2317 // Lowest priority number comes first.
2318 // Lowest is most important.
2319 std::sort(queue.begin(), queue.end());
2322 for(u32 i=0; i<queue.size(); i++)
2324 //TODO: Calculate limit dynamically
2325 if(total_sending >= g_settings->getS32
2326 ("max_simultaneous_block_sends_server_total"))
2329 PrioritySortedBlockTransfer q = queue[i];
2331 MapBlock *block = NULL;
2334 block = m_env->getMap().getBlockNoCreate(q.pos);
2336 catch(InvalidPositionException &e)
2341 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2346 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2348 client->SentBlock(q.pos);
2354 void Server::fillMediaCache()
2356 DSTACK(FUNCTION_NAME);
2358 infostream<<"Server: Calculating media file checksums"<<std::endl;
2360 // Collect all media file paths
2361 std::vector<std::string> paths;
2362 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2363 i != m_mods.end(); ++i) {
2364 const ModSpec &mod = *i;
2365 paths.push_back(mod.path + DIR_DELIM + "textures");
2366 paths.push_back(mod.path + DIR_DELIM + "sounds");
2367 paths.push_back(mod.path + DIR_DELIM + "media");
2368 paths.push_back(mod.path + DIR_DELIM + "models");
2370 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2372 // Collect media file information from paths into cache
2373 for(std::vector<std::string>::iterator i = paths.begin();
2374 i != paths.end(); ++i) {
2375 std::string mediapath = *i;
2376 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2377 for (u32 j = 0; j < dirlist.size(); j++) {
2378 if (dirlist[j].dir) // Ignode dirs
2380 std::string filename = dirlist[j].name;
2381 // If name contains illegal characters, ignore the file
2382 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2383 infostream<<"Server: ignoring illegal file name: \""
2384 << filename << "\"" << std::endl;
2387 // If name is not in a supported format, ignore it
2388 const char *supported_ext[] = {
2389 ".png", ".jpg", ".bmp", ".tga",
2390 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2392 ".x", ".b3d", ".md2", ".obj",
2395 if (removeStringEnd(filename, supported_ext) == ""){
2396 infostream << "Server: ignoring unsupported file extension: \""
2397 << filename << "\"" << std::endl;
2400 // Ok, attempt to load the file and add to cache
2401 std::string filepath = mediapath + DIR_DELIM + filename;
2403 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2405 errorstream << "Server::fillMediaCache(): Could not open \""
2406 << filename << "\" for reading" << std::endl;
2409 std::ostringstream tmp_os(std::ios_base::binary);
2413 fis.read(buf, 1024);
2414 std::streamsize len = fis.gcount();
2415 tmp_os.write(buf, len);
2424 errorstream<<"Server::fillMediaCache(): Failed to read \""
2425 << filename << "\"" << std::endl;
2428 if(tmp_os.str().length() == 0) {
2429 errorstream << "Server::fillMediaCache(): Empty file \""
2430 << filepath << "\"" << std::endl;
2435 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2437 unsigned char *digest = sha1.getDigest();
2438 std::string sha1_base64 = base64_encode(digest, 20);
2439 std::string sha1_hex = hex_encode((char*)digest, 20);
2443 m_media[filename] = MediaInfo(filepath, sha1_base64);
2444 verbosestream << "Server: " << sha1_hex << " is " << filename
2450 void Server::sendMediaAnnouncement(u16 peer_id)
2452 DSTACK(FUNCTION_NAME);
2454 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2458 std::ostringstream os(std::ios_base::binary);
2460 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2461 pkt << (u16) m_media.size();
2463 for (std::unordered_map<std::string, MediaInfo>::iterator i = m_media.begin();
2464 i != m_media.end(); ++i) {
2465 pkt << i->first << i->second.sha1_digest;
2468 pkt << g_settings->get("remote_media");
2472 struct SendableMedia
2478 SendableMedia(const std::string &name_="", const std::string &path_="",
2479 const std::string &data_=""):
2486 void Server::sendRequestedMedia(u16 peer_id,
2487 const std::vector<std::string> &tosend)
2489 DSTACK(FUNCTION_NAME);
2491 verbosestream<<"Server::sendRequestedMedia(): "
2492 <<"Sending files to client"<<std::endl;
2496 // Put 5kB in one bunch (this is not accurate)
2497 u32 bytes_per_bunch = 5000;
2499 std::vector< std::vector<SendableMedia> > file_bunches;
2500 file_bunches.push_back(std::vector<SendableMedia>());
2502 u32 file_size_bunch_total = 0;
2504 for(std::vector<std::string>::const_iterator i = tosend.begin();
2505 i != tosend.end(); ++i) {
2506 const std::string &name = *i;
2508 if (m_media.find(name) == m_media.end()) {
2509 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2510 <<"unknown file \""<<(name)<<"\""<<std::endl;
2514 //TODO get path + name
2515 std::string tpath = m_media[name].path;
2518 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2519 if(fis.good() == false){
2520 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2521 <<tpath<<"\" for reading"<<std::endl;
2524 std::ostringstream tmp_os(std::ios_base::binary);
2528 fis.read(buf, 1024);
2529 std::streamsize len = fis.gcount();
2530 tmp_os.write(buf, len);
2531 file_size_bunch_total += len;
2540 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2541 <<name<<"\""<<std::endl;
2544 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2545 <<tname<<"\""<<std::endl;*/
2547 file_bunches[file_bunches.size()-1].push_back(
2548 SendableMedia(name, tpath, tmp_os.str()));
2550 // Start next bunch if got enough data
2551 if(file_size_bunch_total >= bytes_per_bunch) {
2552 file_bunches.push_back(std::vector<SendableMedia>());
2553 file_size_bunch_total = 0;
2558 /* Create and send packets */
2560 u16 num_bunches = file_bunches.size();
2561 for(u16 i = 0; i < num_bunches; i++) {
2564 u16 total number of texture bunches
2565 u16 index of this bunch
2566 u32 number of files in this bunch
2575 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2576 pkt << num_bunches << i << (u32) file_bunches[i].size();
2578 for(std::vector<SendableMedia>::iterator
2579 j = file_bunches[i].begin();
2580 j != file_bunches[i].end(); ++j) {
2582 pkt.putLongString(j->data);
2585 verbosestream << "Server::sendRequestedMedia(): bunch "
2586 << i << "/" << num_bunches
2587 << " files=" << file_bunches[i].size()
2588 << " size=" << pkt.getSize() << std::endl;
2593 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2595 if(m_detached_inventories.count(name) == 0) {
2596 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2599 Inventory *inv = m_detached_inventories[name];
2600 std::ostringstream os(std::ios_base::binary);
2602 os << serializeString(name);
2606 std::string s = os.str();
2608 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2609 pkt.putRawString(s.c_str(), s.size());
2611 const std::string &check = m_detached_inventories_player[name];
2612 if (peer_id == PEER_ID_INEXISTENT) {
2614 return m_clients.sendToAll(&pkt);
2615 RemotePlayer *p = m_env->getPlayer(check.c_str());
2617 m_clients.send(p->peer_id, 0, &pkt, true);
2619 if (check == "" || getPlayerName(peer_id) == check)
2624 void Server::sendDetachedInventories(u16 peer_id)
2626 DSTACK(FUNCTION_NAME);
2628 for(std::map<std::string, Inventory*>::iterator
2629 i = m_detached_inventories.begin();
2630 i != m_detached_inventories.end(); ++i) {
2631 const std::string &name = i->first;
2632 //Inventory *inv = i->second;
2633 sendDetachedInventory(name, peer_id);
2641 void Server::DiePlayer(u16 peer_id)
2643 DSTACK(FUNCTION_NAME);
2644 PlayerSAO *playersao = getPlayerSAO(peer_id);
2645 // In some rare cases this can be NULL -- if the player is disconnected
2646 // when a Lua function modifies l_punch, for example
2650 infostream << "Server::DiePlayer(): Player "
2651 << playersao->getPlayer()->getName()
2652 << " dies" << std::endl;
2654 playersao->setHP(0);
2656 // Trigger scripted stuff
2657 m_script->on_dieplayer(playersao);
2659 SendPlayerHP(peer_id);
2660 SendDeathscreen(peer_id, false, v3f(0,0,0));
2663 void Server::RespawnPlayer(u16 peer_id)
2665 DSTACK(FUNCTION_NAME);
2667 PlayerSAO *playersao = getPlayerSAO(peer_id);
2670 infostream << "Server::RespawnPlayer(): Player "
2671 << playersao->getPlayer()->getName()
2672 << " respawns" << std::endl;
2674 playersao->setHP(PLAYER_MAX_HP);
2675 playersao->setBreath(PLAYER_MAX_BREATH);
2677 bool repositioned = m_script->on_respawnplayer(playersao);
2678 if (!repositioned) {
2679 // setPos will send the new position to client
2680 playersao->setPos(findSpawnPos());
2683 SendPlayerHP(peer_id);
2687 void Server::DenySudoAccess(u16 peer_id)
2689 DSTACK(FUNCTION_NAME);
2691 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2696 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2697 const std::string &str_reason, bool reconnect)
2699 if (proto_ver >= 25) {
2700 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2702 std::wstring wreason = utf8_to_wide(
2703 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2704 accessDeniedStrings[(u8)reason]);
2705 SendAccessDenied_Legacy(peer_id, wreason);
2708 m_clients.event(peer_id, CSE_SetDenied);
2709 m_con.DisconnectPeer(peer_id);
2713 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2715 DSTACK(FUNCTION_NAME);
2717 SendAccessDenied(peer_id, reason, custom_reason);
2718 m_clients.event(peer_id, CSE_SetDenied);
2719 m_con.DisconnectPeer(peer_id);
2722 // 13/03/15: remove this function when protocol version 25 will become
2723 // the minimum version for MT users, maybe in 1 year
2724 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2726 DSTACK(FUNCTION_NAME);
2728 SendAccessDenied_Legacy(peer_id, reason);
2729 m_clients.event(peer_id, CSE_SetDenied);
2730 m_con.DisconnectPeer(peer_id);
2733 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2735 DSTACK(FUNCTION_NAME);
2738 RemoteClient* client = getClient(peer_id, CS_Invalid);
2740 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2742 // Right now, the auth mechs don't change between login and sudo mode.
2743 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2744 client->allowed_sudo_mechs = sudo_auth_mechs;
2746 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2747 << g_settings->getFloat("dedicated_server_step")
2751 m_clients.event(peer_id, CSE_AuthAccept);
2753 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2755 // We only support SRP right now
2756 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2758 resp_pkt << sudo_auth_mechs;
2760 m_clients.event(peer_id, CSE_SudoSuccess);
2764 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2766 DSTACK(FUNCTION_NAME);
2767 std::wstring message;
2770 Clear references to playing sounds
2772 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2773 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2774 ServerPlayingSound &psound = i->second;
2775 psound.clients.erase(peer_id);
2776 if (psound.clients.empty())
2777 m_playing_sounds.erase(i++);
2782 RemotePlayer *player = m_env->getPlayer(peer_id);
2784 /* Run scripts and remove from environment */
2785 if (player != NULL) {
2786 PlayerSAO *playersao = player->getPlayerSAO();
2789 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2791 playersao->disconnected();
2798 if(player != NULL && reason != CDR_DENY) {
2799 std::ostringstream os(std::ios_base::binary);
2800 std::vector<u16> clients = m_clients.getClientIDs();
2802 for(std::vector<u16>::iterator i = clients.begin();
2803 i != clients.end(); ++i) {
2805 RemotePlayer *player = m_env->getPlayer(*i);
2809 // Get name of player
2810 os << player->getName() << " ";
2813 std::string name = player->getName();
2814 actionstream << name << " "
2815 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2816 << " List of players: " << os.str() << std::endl;
2818 m_admin_chat->outgoing_queue.push_back(
2819 new ChatEventNick(CET_NICK_REMOVE, name));
2823 MutexAutoLock env_lock(m_env_mutex);
2824 m_clients.DeleteClient(peer_id);
2828 // Send leave chat message to all remaining clients
2829 if(message.length() != 0)
2830 SendChatMessage(PEER_ID_INEXISTENT,message);
2833 void Server::UpdateCrafting(RemotePlayer *player)
2835 DSTACK(FUNCTION_NAME);
2837 // Get a preview for crafting
2839 InventoryLocation loc;
2840 loc.setPlayer(player->getName());
2841 std::vector<ItemStack> output_replacements;
2842 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2843 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2844 (&player->inventory)->getList("craft"), loc);
2846 // Put the new preview in
2847 InventoryList *plist = player->inventory.getList("craftpreview");
2848 sanity_check(plist);
2849 sanity_check(plist->getSize() >= 1);
2850 plist->changeItem(0, preview);
2853 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2855 if (evt->type == CET_NICK_ADD) {
2856 // The terminal informed us of its nick choice
2857 m_admin_nick = ((ChatEventNick *)evt)->nick;
2858 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2859 errorstream << "You haven't set up an account." << std::endl
2860 << "Please log in using the client as '"
2861 << m_admin_nick << "' with a secure password." << std::endl
2862 << "Until then, you can't execute admin tasks via the console," << std::endl
2863 << "and everybody can claim the user account instead of you," << std::endl
2864 << "giving them full control over this server." << std::endl;
2867 assert(evt->type == CET_CHAT);
2868 handleAdminChat((ChatEventChat *)evt);
2872 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2873 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2875 // If something goes wrong, this player is to blame
2876 RollbackScopeActor rollback_scope(m_rollback,
2877 std::string("player:") + name);
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(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, 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, 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,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;
3514 // Try to find a good place a few times
3515 for(s32 i = 0; i < 4000 && !is_good; i++) {
3517 // We're going to try to throw the player to this position
3518 v2s16 nodepos2d = v2s16(
3519 -range + (myrand() % (range * 2)),
3520 -range + (myrand() % (range * 2)));
3522 // Get spawn level at point
3523 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3524 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3525 // the mapgen to signify an unsuitable spawn position
3526 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3529 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3532 for (s32 i = 0; i < 10; i++) {
3533 v3s16 blockpos = getNodeBlockPos(nodepos);
3534 map.emergeBlock(blockpos, true);
3535 content_t c = map.getNodeNoEx(nodepos).getContent();
3536 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3538 if (air_count >= 2) {
3539 nodeposf = intToFloat(nodepos, BS);
3540 // Don't spawn the player outside map boundaries
3541 if (objectpos_over_limit(nodeposf))
3554 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3556 m_shutdown_timer = delay;
3557 m_shutdown_msg = msg;
3558 m_shutdown_ask_reconnect = reconnect;
3560 if (delay == 0.0f) {
3561 // No delay, shutdown immediately
3562 m_shutdown_requested = true;
3563 // only print to the infostream, a chat message saying
3564 // "Server Shutting Down" is sent when the server destructs.
3565 infostream << "*** Immediate Server shutdown requested." << std::endl;
3566 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3567 // Negative delay, cancel shutdown if requested
3568 m_shutdown_timer = 0.0f;
3569 m_shutdown_msg = "";
3570 m_shutdown_ask_reconnect = false;
3571 m_shutdown_requested = false;
3572 std::wstringstream ws;
3574 ws << L"*** Server shutdown canceled.";
3576 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3577 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3578 } else if (delay > 0.0f) {
3579 // Positive delay, tell the clients when the server will shut down
3580 std::wstringstream ws;
3582 ws << L"*** Server shutting down in "
3583 << duration_to_string(myround(m_shutdown_timer)).c_str()
3586 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3587 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3591 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3594 Try to get an existing player
3596 RemotePlayer *player = m_env->getPlayer(name);
3598 // If player is already connected, cancel
3599 if (player != NULL && player->peer_id != 0) {
3600 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3605 If player with the wanted peer_id already exists, cancel.
3607 if (m_env->getPlayer(peer_id) != NULL) {
3608 infostream<<"emergePlayer(): Player with wrong name but same"
3609 " peer_id already exists"<<std::endl;
3614 player = new RemotePlayer(name, idef());
3617 bool newplayer = false;
3620 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3622 // Complete init with server parts
3623 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3624 player->protocol_version = proto_version;
3628 m_script->on_newplayer(playersao);
3634 bool Server::registerModStorage(ModMetadata *storage)
3636 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3637 errorstream << "Unable to register same mod storage twice. Storage name: "
3638 << storage->getModName() << std::endl;
3642 m_mod_storages[storage->getModName()] = storage;
3646 void Server::unregisterModStorage(const std::string &name)
3648 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3649 if (it != m_mod_storages.end()) {
3650 // Save unconditionaly on unregistration
3651 it->second->save(getModStoragePath());
3652 m_mod_storages.erase(name);
3656 void dedicated_server_loop(Server &server, bool &kill)
3658 DSTACK(FUNCTION_NAME);
3660 verbosestream<<"dedicated_server_loop()"<<std::endl;
3662 IntervalLimiter m_profiler_interval;
3664 static const float steplen = g_settings->getFloat("dedicated_server_step");
3665 static const float profiler_print_interval =
3666 g_settings->getFloat("profiler_print_interval");
3669 // This is kind of a hack but can be done like this
3670 // because server.step() is very light
3672 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3673 sleep_ms((int)(steplen*1000.0));
3675 server.step(steplen);
3677 if (server.getShutdownRequested() || kill)
3683 if (profiler_print_interval != 0) {
3684 if(m_profiler_interval.step(steplen, profiler_print_interval))
3686 infostream<<"Profiler:"<<std::endl;
3687 g_profiler->print(infostream);
3688 g_profiler->clear();
3693 infostream << "Dedicated server quitting" << std::endl;
3695 if (g_settings->getBool("server_announce"))
3696 ServerList::sendAnnounce(ServerList::AA_DELETE,
3697 server.m_bind_addr.getPort());