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();
233 Settings worldmt_settings;
234 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
235 worldmt_settings.readConfigFile(worldmt.c_str());
236 std::vector<std::string> names = worldmt_settings.getNames();
237 std::set<std::string> load_mod_names;
238 for(std::vector<std::string>::iterator it = names.begin();
239 it != names.end(); ++it) {
240 std::string name = *it;
241 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
242 load_mod_names.insert(name.substr(9));
244 // complain about mods declared to be loaded, but not found
245 for(std::vector<ModSpec>::iterator it = m_mods.begin();
246 it != m_mods.end(); ++it)
247 load_mod_names.erase((*it).name);
248 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
249 it != unsatisfied_mods.end(); ++it)
250 load_mod_names.erase((*it).name);
251 if(!load_mod_names.empty()) {
252 errorstream << "The following mods could not be found:";
253 for(std::set<std::string>::iterator it = load_mod_names.begin();
254 it != load_mod_names.end(); ++it)
255 errorstream << " \"" << (*it) << "\"";
256 errorstream << std::endl;
260 MutexAutoLock envlock(m_env_mutex);
262 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
263 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
265 // Initialize scripting
266 infostream<<"Server: Initializing Lua"<<std::endl;
268 m_script = new ServerScripting(this);
270 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
273 infostream << "Server: Loading mods: ";
274 for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
275 i != m_mods.end(); ++i) {
276 infostream << (*i).name << " ";
278 infostream << std::endl;
279 // Load and run "mod" scripts
280 for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
281 it != m_mods.end(); ++it) {
282 const ModSpec &mod = *it;
283 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
284 throw ModError("Error loading mod \"" + mod.name +
285 "\": Mod name does not follow naming conventions: "
286 "Only chararacters [a-z0-9_] are allowed.");
288 std::string script_path = mod.path + DIR_DELIM + "init.lua";
289 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
290 << script_path << "\"]" << std::endl;
291 m_script->loadMod(script_path, mod.name);
294 // Read Textures and calculate sha1 sums
297 // Apply item aliases in the node definition manager
298 m_nodedef->updateAliases(m_itemdef);
300 // Apply texture overrides from texturepack/override.txt
301 std::string texture_path = g_settings->get("texture_path");
302 if (texture_path != "" && fs::IsDir(texture_path))
303 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
305 m_nodedef->setNodeRegistrationStatus(true);
307 // Perform pending node name resolutions
308 m_nodedef->runNodeResolveCallbacks();
310 // unmap node names for connected nodeboxes
311 m_nodedef->mapNodeboxConnections();
313 // init the recipe hashes to speed up crafting
314 m_craftdef->initHashes(this);
316 // Initialize Environment
317 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
319 m_clients.setEnv(m_env);
321 if (!servermap->settings_mgr.makeMapgenParams())
322 FATAL_ERROR("Couldn't create any mapgen type");
324 // Initialize mapgens
325 m_emerge->initMapgens(servermap->getMapgenParams());
327 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
328 if (m_enable_rollback_recording) {
329 // Create rollback manager
330 m_rollback = new RollbackManager(m_path_world, this);
333 // Give environment reference to scripting api
334 m_script->initializeEnvironment(m_env);
336 // Register us to receive map edit events
337 servermap->addEventReceiver(this);
339 // If file exists, load environment metadata
340 if (fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
341 infostream << "Server: Loading environment metadata" << std::endl;
344 m_env->loadDefaultMeta();
347 // Add some test ActiveBlockModifiers to environment
348 add_legacy_abms(m_env, m_nodedef);
350 m_liquid_transform_every = g_settings->getFloat("liquid_update");
351 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
356 infostream<<"Server destructing"<<std::endl;
358 // Send shutdown message
359 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
362 MutexAutoLock envlock(m_env_mutex);
364 // Execute script shutdown hooks
365 m_script->on_shutdown();
367 infostream << "Server: Saving players" << std::endl;
368 m_env->saveLoadedPlayers();
370 infostream << "Server: Kicking players" << std::endl;
371 std::string kick_msg;
372 bool reconnect = false;
373 if (getShutdownRequested()) {
374 reconnect = m_shutdown_ask_reconnect;
375 kick_msg = m_shutdown_msg;
377 if (kick_msg == "") {
378 kick_msg = g_settings->get("kick_msg_shutdown");
380 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
381 kick_msg, reconnect);
383 infostream << "Server: Saving environment metadata" << std::endl;
391 // stop all emerge threads before deleting players that may have
392 // requested blocks to be emerged
393 m_emerge->stopThreads();
395 // Delete things in the reverse order of creation
405 // Deinitialize scripting
406 infostream<<"Server: Deinitializing scripting"<<std::endl;
409 // Delete detached inventories
410 for (std::map<std::string, Inventory*>::iterator
411 i = m_detached_inventories.begin();
412 i != m_detached_inventories.end(); ++i) {
417 void Server::start(Address bind_addr)
419 DSTACK(FUNCTION_NAME);
421 m_bind_addr = bind_addr;
423 infostream<<"Starting server on "
424 << bind_addr.serializeString() <<"..."<<std::endl;
426 // Stop thread if already running
429 // Initialize connection
430 m_con.SetTimeoutMs(30);
431 m_con.Serve(bind_addr);
436 // ASCII art for the win!
438 <<" .__ __ __ "<<std::endl
439 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
440 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
441 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
442 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
443 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
444 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
445 actionstream<<"Server for gameid=\""<<m_gamespec.id
446 <<"\" listening on "<<bind_addr.serializeString()<<":"
447 <<bind_addr.getPort() << "."<<std::endl;
452 DSTACK(FUNCTION_NAME);
454 infostream<<"Server: Stopping and waiting threads"<<std::endl;
456 // Stop threads (set run=false first so both start stopping)
458 //m_emergethread.setRun(false);
460 //m_emergethread.stop();
462 infostream<<"Server: Threads stopped"<<std::endl;
465 void Server::step(float dtime)
467 DSTACK(FUNCTION_NAME);
472 MutexAutoLock lock(m_step_dtime_mutex);
473 m_step_dtime += dtime;
475 // Throw if fatal error occurred in thread
476 std::string async_err = m_async_fatal_error.get();
477 if (!async_err.empty()) {
478 if (!m_simple_singleplayer_mode) {
479 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
480 g_settings->get("kick_msg_crash"),
481 g_settings->getBool("ask_reconnect_on_crash"));
483 throw ServerError("AsyncErr: " + async_err);
487 void Server::AsyncRunStep(bool initial_step)
489 DSTACK(FUNCTION_NAME);
491 g_profiler->add("Server::AsyncRunStep (num)", 1);
495 MutexAutoLock lock1(m_step_dtime_mutex);
496 dtime = m_step_dtime;
500 // Send blocks to clients
504 if((dtime < 0.001) && (initial_step == false))
507 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
509 //infostream<<"Server steps "<<dtime<<std::endl;
510 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
513 MutexAutoLock lock1(m_step_dtime_mutex);
514 m_step_dtime -= dtime;
521 m_uptime.set(m_uptime.get() + dtime);
527 Update time of day and overall game time
529 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
532 Send to clients at constant intervals
535 m_time_of_day_send_timer -= dtime;
536 if(m_time_of_day_send_timer < 0.0) {
537 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
538 u16 time = m_env->getTimeOfDay();
539 float time_speed = g_settings->getFloat("time_speed");
540 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
544 MutexAutoLock lock(m_env_mutex);
545 // Figure out and report maximum lag to environment
546 float max_lag = m_env->getMaxLagEstimate();
547 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
549 if(dtime > 0.1 && dtime > max_lag * 2.0)
550 infostream<<"Server: Maximum lag peaked to "<<dtime
554 m_env->reportMaxLagEstimate(max_lag);
556 ScopeProfiler sp(g_profiler, "SEnv step");
557 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
561 static const float map_timer_and_unload_dtime = 2.92;
562 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
564 MutexAutoLock lock(m_env_mutex);
565 // Run Map's timers and unload unused data
566 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
567 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
568 g_settings->getFloat("server_unload_unused_data_timeout"),
573 Listen to the admin chat, if available
576 if (!m_admin_chat->command_queue.empty()) {
577 MutexAutoLock lock(m_env_mutex);
578 while (!m_admin_chat->command_queue.empty()) {
579 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
580 handleChatInterfaceEvent(evt);
584 m_admin_chat->outgoing_queue.push_back(
585 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
592 /* Transform liquids */
593 m_liquid_transform_timer += dtime;
594 if(m_liquid_transform_timer >= m_liquid_transform_every)
596 m_liquid_transform_timer -= m_liquid_transform_every;
598 MutexAutoLock lock(m_env_mutex);
600 ScopeProfiler sp(g_profiler, "Server: liquid transform");
602 std::map<v3s16, MapBlock*> modified_blocks;
603 m_env->getMap().transformLiquids(modified_blocks, m_env);
608 core::map<v3s16, MapBlock*> lighting_modified_blocks;
609 ServerMap &map = ((ServerMap&)m_env->getMap());
610 map.updateLighting(modified_blocks, lighting_modified_blocks);
612 // Add blocks modified by lighting to modified_blocks
613 for(core::map<v3s16, MapBlock*>::Iterator
614 i = lighting_modified_blocks.getIterator();
615 i.atEnd() == false; i++)
617 MapBlock *block = i.getNode()->getValue();
618 modified_blocks.insert(block->getPos(), block);
622 Set the modified blocks unsent for all the clients
624 if(!modified_blocks.empty())
626 SetBlocksNotSent(modified_blocks);
629 m_clients.step(dtime);
631 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
633 // send masterserver announce
635 float &counter = m_masterserver_timer;
636 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
637 g_settings->getBool("server_announce")) {
638 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
639 ServerList::AA_START,
640 m_bind_addr.getPort(),
641 m_clients.getPlayerNames(),
643 m_env->getGameTime(),
646 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
656 Check added and deleted active objects
659 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
660 MutexAutoLock envlock(m_env_mutex);
663 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
664 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
666 // Radius inside which objects are active
667 static const s16 radius =
668 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
670 // Radius inside which players are active
671 static const bool is_transfer_limited =
672 g_settings->exists("unlimited_player_transfer_distance") &&
673 !g_settings->getBool("unlimited_player_transfer_distance");
674 static const s16 player_transfer_dist = g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
675 s16 player_radius = player_transfer_dist;
676 if (player_radius == 0 && is_transfer_limited)
677 player_radius = radius;
679 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
680 i != clients.end(); ++i) {
681 RemoteClient *client = i->second;
683 // If definitions and textures have not been sent, don't
684 // send objects either
685 if (client->getState() < CS_DefinitionsSent)
688 RemotePlayer *player = m_env->getPlayer(client->peer_id);
689 if (player == NULL) {
690 // This can happen if the client timeouts somehow
691 /*warningstream<<FUNCTION_NAME<<": Client "
693 <<" has no associated player"<<std::endl;*/
697 PlayerSAO *playersao = player->getPlayerSAO();
698 if (playersao == NULL)
701 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
702 if (my_radius <= 0) my_radius = radius;
703 //infostream << "Server: Active Radius " << my_radius << std::endl;
705 std::queue<u16> removed_objects;
706 std::queue<u16> added_objects;
707 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
708 client->m_known_objects, removed_objects);
709 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
710 client->m_known_objects, added_objects);
712 // Ignore if nothing happened
713 if (removed_objects.empty() && added_objects.empty()) {
717 std::string data_buffer;
721 // Handle removed objects
722 writeU16((u8*)buf, removed_objects.size());
723 data_buffer.append(buf, 2);
724 while (!removed_objects.empty()) {
726 u16 id = removed_objects.front();
727 ServerActiveObject* obj = m_env->getActiveObject(id);
729 // Add to data buffer for sending
730 writeU16((u8*)buf, id);
731 data_buffer.append(buf, 2);
733 // Remove from known objects
734 client->m_known_objects.erase(id);
736 if(obj && obj->m_known_by_count > 0)
737 obj->m_known_by_count--;
738 removed_objects.pop();
741 // Handle added objects
742 writeU16((u8*)buf, added_objects.size());
743 data_buffer.append(buf, 2);
744 while (!added_objects.empty()) {
746 u16 id = added_objects.front();
747 ServerActiveObject* obj = m_env->getActiveObject(id);
750 u8 type = ACTIVEOBJECT_TYPE_INVALID;
752 warningstream<<FUNCTION_NAME
753 <<": NULL object"<<std::endl;
755 type = obj->getSendType();
757 // Add to data buffer for sending
758 writeU16((u8*)buf, id);
759 data_buffer.append(buf, 2);
760 writeU8((u8*)buf, type);
761 data_buffer.append(buf, 1);
764 data_buffer.append(serializeLongString(
765 obj->getClientInitializationData(client->net_proto_version)));
767 data_buffer.append(serializeLongString(""));
769 // Add to known objects
770 client->m_known_objects.insert(id);
773 obj->m_known_by_count++;
778 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
779 verbosestream << "Server: Sent object remove/add: "
780 << removed_objects.size() << " removed, "
781 << added_objects.size() << " added, "
782 << "packet size is " << pktSize << std::endl;
786 m_mod_storage_save_timer -= dtime;
787 if (m_mod_storage_save_timer <= 0.0f) {
788 infostream << "Saving registered mod storages." << std::endl;
789 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
790 for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
791 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
792 if (it->second->isModified()) {
793 it->second->save(getModStoragePath());
803 MutexAutoLock envlock(m_env_mutex);
804 ScopeProfiler sp(g_profiler, "Server: sending object messages");
807 // Value = data sent by object
808 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
810 // Get active object messages from environment
812 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
816 std::vector<ActiveObjectMessage>* message_list = NULL;
817 UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator n;
818 n = buffered_messages.find(aom.id);
819 if (n == buffered_messages.end()) {
820 message_list = new std::vector<ActiveObjectMessage>;
821 buffered_messages[aom.id] = message_list;
824 message_list = n->second;
826 message_list->push_back(aom);
830 UNORDERED_MAP<u16, RemoteClient*> clients = m_clients.getClientList();
831 // Route data to every client
832 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = clients.begin();
833 i != clients.end(); ++i) {
834 RemoteClient *client = i->second;
835 std::string reliable_data;
836 std::string unreliable_data;
837 // Go through all objects in message buffer
838 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
839 j = buffered_messages.begin();
840 j != buffered_messages.end(); ++j) {
841 // If object is not known by client, skip it
843 if (client->m_known_objects.find(id) == client->m_known_objects.end())
846 // Get message list of object
847 std::vector<ActiveObjectMessage>* list = j->second;
848 // Go through every message
849 for (std::vector<ActiveObjectMessage>::iterator
850 k = list->begin(); k != list->end(); ++k) {
851 // Compose the full new data with header
852 ActiveObjectMessage aom = *k;
853 std::string new_data;
856 writeU16((u8*)&buf[0], aom.id);
857 new_data.append(buf, 2);
859 new_data += serializeString(aom.datastring);
860 // Add data to buffer
862 reliable_data += new_data;
864 unreliable_data += new_data;
868 reliable_data and unreliable_data are now ready.
871 if(reliable_data.size() > 0) {
872 SendActiveObjectMessages(client->peer_id, reliable_data);
875 if(unreliable_data.size() > 0) {
876 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
881 // Clear buffered_messages
882 for (UNORDERED_MAP<u16, std::vector<ActiveObjectMessage>* >::iterator
883 i = buffered_messages.begin();
884 i != buffered_messages.end(); ++i) {
890 Send queued-for-sending map edit events.
893 // We will be accessing the environment
894 MutexAutoLock lock(m_env_mutex);
896 // Don't send too many at a time
899 // Single change sending is disabled if queue size is not small
900 bool disable_single_change_sending = false;
901 if(m_unsent_map_edit_queue.size() >= 4)
902 disable_single_change_sending = true;
904 int event_count = m_unsent_map_edit_queue.size();
906 // We'll log the amount of each
909 while(m_unsent_map_edit_queue.size() != 0)
911 MapEditEvent* event = m_unsent_map_edit_queue.front();
912 m_unsent_map_edit_queue.pop();
914 // Players far away from the change are stored here.
915 // Instead of sending the changes, MapBlocks are set not sent
917 std::vector<u16> far_players;
919 switch (event->type) {
922 prof.add("MEET_ADDNODE", 1);
923 sendAddNode(event->p, event->n, event->already_known_by_peer,
924 &far_players, disable_single_change_sending ? 5 : 30,
925 event->type == MEET_ADDNODE);
927 case MEET_REMOVENODE:
928 prof.add("MEET_REMOVENODE", 1);
929 sendRemoveNode(event->p, event->already_known_by_peer,
930 &far_players, disable_single_change_sending ? 5 : 30);
932 case MEET_BLOCK_NODE_METADATA_CHANGED:
933 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
934 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
935 setBlockNotSent(event->p);
938 infostream << "Server: MEET_OTHER" << std::endl;
939 prof.add("MEET_OTHER", 1);
940 for(std::set<v3s16>::iterator
941 i = event->modified_blocks.begin();
942 i != event->modified_blocks.end(); ++i) {
947 prof.add("unknown", 1);
948 warningstream << "Server: Unknown MapEditEvent "
949 << ((u32)event->type) << std::endl;
954 Set blocks not sent to far players
956 if(!far_players.empty()) {
957 // Convert list format to that wanted by SetBlocksNotSent
958 std::map<v3s16, MapBlock*> modified_blocks2;
959 for(std::set<v3s16>::iterator
960 i = event->modified_blocks.begin();
961 i != event->modified_blocks.end(); ++i) {
962 modified_blocks2[*i] =
963 m_env->getMap().getBlockNoCreateNoEx(*i);
966 // Set blocks not sent
967 for(std::vector<u16>::iterator
968 i = far_players.begin();
969 i != far_players.end(); ++i) {
970 if(RemoteClient *client = getClient(*i))
971 client->SetBlocksNotSent(modified_blocks2);
977 /*// Don't send too many at a time
979 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
983 if(event_count >= 5){
984 infostream<<"Server: MapEditEvents:"<<std::endl;
985 prof.print(infostream);
986 } else if(event_count != 0){
987 verbosestream<<"Server: MapEditEvents:"<<std::endl;
988 prof.print(verbosestream);
994 Trigger emergethread (it somehow gets to a non-triggered but
995 bysy state sometimes)
998 float &counter = m_emergethread_trigger_timer;
1000 if (counter >= 2.0) {
1003 m_emerge->startThreads();
1007 // Save map, players and auth stuff
1009 float &counter = m_savemap_timer;
1011 static const float save_interval =
1012 g_settings->getFloat("server_map_save_interval");
1013 if (counter >= save_interval) {
1015 MutexAutoLock lock(m_env_mutex);
1017 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1020 if (m_banmanager->isModified()) {
1021 m_banmanager->save();
1024 // Save changed parts of map
1025 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1028 m_env->saveLoadedPlayers();
1030 // Save environment metadata
1036 static const float shutdown_msg_times[] =
1038 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
1041 if (m_shutdown_timer > 0.0f) {
1042 // Automated messages
1043 if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
1044 for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
1045 // If shutdown timer matches an automessage, shot it
1046 if (m_shutdown_timer > shutdown_msg_times[i] &&
1047 m_shutdown_timer - dtime < shutdown_msg_times[i]) {
1048 std::wstringstream ws;
1050 ws << L"*** Server shutting down in "
1051 << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
1054 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
1055 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
1061 m_shutdown_timer -= dtime;
1062 if (m_shutdown_timer < 0.0f) {
1063 m_shutdown_timer = 0.0f;
1064 m_shutdown_requested = true;
1069 void Server::Receive()
1071 DSTACK(FUNCTION_NAME);
1072 SharedBuffer<u8> data;
1076 m_con.Receive(&pkt);
1077 peer_id = pkt.getPeerId();
1080 catch(con::InvalidIncomingDataException &e) {
1081 infostream<<"Server::Receive(): "
1082 "InvalidIncomingDataException: what()="
1083 <<e.what()<<std::endl;
1085 catch(SerializationError &e) {
1086 infostream<<"Server::Receive(): "
1087 "SerializationError: what()="
1088 <<e.what()<<std::endl;
1090 catch(ClientStateError &e) {
1091 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1092 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1093 L"Try reconnecting or updating your client");
1095 catch(con::PeerNotFoundException &e) {
1100 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1102 std::string playername = "";
1103 PlayerSAO *playersao = NULL;
1106 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1107 if (client != NULL) {
1108 playername = client->getName();
1109 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1111 } catch (std::exception &e) {
1117 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1119 // If failed, cancel
1120 if ((playersao == NULL) || (player == NULL)) {
1121 if (player && player->peer_id != 0) {
1122 actionstream << "Server: Failed to emerge player \"" << playername
1123 << "\" (player allocated to an another client)" << std::endl;
1124 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1125 L"name. If your client closed unexpectedly, try again in "
1128 errorstream << "Server: " << playername << ": Failed to emerge player"
1130 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1136 Send complete position information
1138 SendMovePlayer(peer_id);
1141 SendPlayerPrivileges(peer_id);
1143 // Send inventory formspec
1144 SendPlayerInventoryFormspec(peer_id);
1147 SendInventory(playersao);
1149 // Send HP or death screen
1150 if (playersao->isDead())
1151 SendDeathscreen(peer_id, false, v3f(0,0,0));
1153 SendPlayerHPOrDie(playersao);
1156 SendPlayerBreath(playersao);
1158 // Note things in chat if not in simple singleplayer mode
1159 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1160 // Send information about server to player in chat
1161 SendChatMessage(peer_id, getStatusString());
1163 Address addr = getPeerAddress(player->peer_id);
1164 std::string ip_str = addr.serializeString();
1165 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1170 const std::vector<std::string> &names = m_clients.getPlayerNames();
1172 actionstream << player->getName() << " joins game. List of players: ";
1174 for (std::vector<std::string>::const_iterator i = names.begin();
1175 i != names.end(); ++i) {
1176 actionstream << *i << " ";
1179 actionstream << player->getName() <<std::endl;
1184 inline void Server::handleCommand(NetworkPacket* pkt)
1186 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1187 (this->*opHandle.handler)(pkt);
1190 void Server::ProcessData(NetworkPacket *pkt)
1192 DSTACK(FUNCTION_NAME);
1193 // Environment is locked first.
1194 MutexAutoLock envlock(m_env_mutex);
1196 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1197 u32 peer_id = pkt->getPeerId();
1200 Address address = getPeerAddress(peer_id);
1201 std::string addr_s = address.serializeString();
1203 if(m_banmanager->isIpBanned(addr_s)) {
1204 std::string ban_name = m_banmanager->getBanName(addr_s);
1205 infostream << "Server: A banned client tried to connect from "
1206 << addr_s << "; banned name was "
1207 << ban_name << std::endl;
1208 // This actually doesn't seem to transfer to the client
1209 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1210 + utf8_to_wide(ban_name));
1214 catch(con::PeerNotFoundException &e) {
1216 * no peer for this packet found
1217 * most common reason is peer timeout, e.g. peer didn't
1218 * respond for some time, your server was overloaded or
1221 infostream << "Server::ProcessData(): Canceling: peer "
1222 << peer_id << " not found" << std::endl;
1227 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1229 // Command must be handled into ToServerCommandHandler
1230 if (command >= TOSERVER_NUM_MSG_TYPES) {
1231 infostream << "Server: Ignoring unknown command "
1232 << command << std::endl;
1236 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1241 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1243 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1244 errorstream << "Server::ProcessData(): Cancelling: Peer"
1245 " serialization format invalid or not initialized."
1246 " Skipping incoming command=" << command << std::endl;
1250 /* Handle commands related to client startup */
1251 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1256 if (m_clients.getClientState(peer_id) < CS_Active) {
1257 if (command == TOSERVER_PLAYERPOS) return;
1259 errorstream << "Got packet command: " << command << " for peer id "
1260 << peer_id << " but client isn't active yet. Dropping packet "
1266 } catch (SendFailedException &e) {
1267 errorstream << "Server::ProcessData(): SendFailedException: "
1268 << "what=" << e.what()
1270 } catch (PacketError &e) {
1271 actionstream << "Server::ProcessData(): PacketError: "
1272 << "what=" << e.what()
1277 void Server::setTimeOfDay(u32 time)
1279 m_env->setTimeOfDay(time);
1280 m_time_of_day_send_timer = 0;
1283 void Server::onMapEditEvent(MapEditEvent *event)
1285 if(m_ignore_map_edit_events)
1287 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1289 MapEditEvent *e = event->clone();
1290 m_unsent_map_edit_queue.push(e);
1293 Inventory* Server::getInventory(const InventoryLocation &loc)
1296 case InventoryLocation::UNDEFINED:
1297 case InventoryLocation::CURRENT_PLAYER:
1299 case InventoryLocation::PLAYER:
1301 RemotePlayer *player = dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1304 PlayerSAO *playersao = player->getPlayerSAO();
1307 return playersao->getInventory();
1310 case InventoryLocation::NODEMETA:
1312 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1315 return meta->getInventory();
1318 case InventoryLocation::DETACHED:
1320 if(m_detached_inventories.count(loc.name) == 0)
1322 return m_detached_inventories[loc.name];
1326 sanity_check(false); // abort
1331 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1334 case InventoryLocation::UNDEFINED:
1336 case InventoryLocation::PLAYER:
1341 RemotePlayer *player =
1342 dynamic_cast<RemotePlayer *>(m_env->getPlayer(loc.name.c_str()));
1347 PlayerSAO *playersao = player->getPlayerSAO();
1351 SendInventory(playersao);
1354 case InventoryLocation::NODEMETA:
1356 v3s16 blockpos = getNodeBlockPos(loc.p);
1358 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1360 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1362 setBlockNotSent(blockpos);
1365 case InventoryLocation::DETACHED:
1367 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1371 sanity_check(false); // abort
1376 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1378 std::vector<u16> clients = m_clients.getClientIDs();
1380 // Set the modified blocks unsent for all the clients
1381 for (std::vector<u16>::iterator i = clients.begin();
1382 i != clients.end(); ++i) {
1383 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1384 client->SetBlocksNotSent(block);
1389 void Server::peerAdded(con::Peer *peer)
1391 DSTACK(FUNCTION_NAME);
1392 verbosestream<<"Server::peerAdded(): peer->id="
1393 <<peer->id<<std::endl;
1396 c.type = con::PEER_ADDED;
1397 c.peer_id = peer->id;
1399 m_peer_change_queue.push(c);
1402 void Server::deletingPeer(con::Peer *peer, bool timeout)
1404 DSTACK(FUNCTION_NAME);
1405 verbosestream<<"Server::deletingPeer(): peer->id="
1406 <<peer->id<<", timeout="<<timeout<<std::endl;
1408 m_clients.event(peer->id, CSE_Disconnect);
1410 c.type = con::PEER_REMOVED;
1411 c.peer_id = peer->id;
1412 c.timeout = timeout;
1413 m_peer_change_queue.push(c);
1416 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1418 *retval = m_con.getPeerStat(peer_id,type);
1419 if (*retval == -1) return false;
1423 bool Server::getClientInfo(
1432 std::string* vers_string
1435 *state = m_clients.getClientState(peer_id);
1437 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1439 if (client == NULL) {
1444 *uptime = client->uptime();
1445 *ser_vers = client->serialization_version;
1446 *prot_vers = client->net_proto_version;
1448 *major = client->getMajor();
1449 *minor = client->getMinor();
1450 *patch = client->getPatch();
1451 *vers_string = client->getPatch();
1458 void Server::handlePeerChanges()
1460 while(m_peer_change_queue.size() > 0)
1462 con::PeerChange c = m_peer_change_queue.front();
1463 m_peer_change_queue.pop();
1465 verbosestream<<"Server: Handling peer change: "
1466 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1471 case con::PEER_ADDED:
1472 m_clients.CreateClient(c.peer_id);
1475 case con::PEER_REMOVED:
1476 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1480 FATAL_ERROR("Invalid peer change event received!");
1486 void Server::printToConsoleOnly(const std::string &text)
1489 m_admin_chat->outgoing_queue.push_back(
1490 new ChatEventChat("", utf8_to_wide(text)));
1492 std::cout << text << std::endl;
1496 void Server::Send(NetworkPacket* pkt)
1498 m_clients.send(pkt->getPeerId(),
1499 clientCommandFactoryTable[pkt->getCommand()].channel,
1501 clientCommandFactoryTable[pkt->getCommand()].reliable);
1504 void Server::SendMovement(u16 peer_id)
1506 DSTACK(FUNCTION_NAME);
1507 std::ostringstream os(std::ios_base::binary);
1509 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1511 pkt << g_settings->getFloat("movement_acceleration_default");
1512 pkt << g_settings->getFloat("movement_acceleration_air");
1513 pkt << g_settings->getFloat("movement_acceleration_fast");
1514 pkt << g_settings->getFloat("movement_speed_walk");
1515 pkt << g_settings->getFloat("movement_speed_crouch");
1516 pkt << g_settings->getFloat("movement_speed_fast");
1517 pkt << g_settings->getFloat("movement_speed_climb");
1518 pkt << g_settings->getFloat("movement_speed_jump");
1519 pkt << g_settings->getFloat("movement_liquid_fluidity");
1520 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1521 pkt << g_settings->getFloat("movement_liquid_sink");
1522 pkt << g_settings->getFloat("movement_gravity");
1527 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1529 if (!g_settings->getBool("enable_damage"))
1532 u16 peer_id = playersao->getPeerID();
1533 bool is_alive = playersao->getHP() > 0;
1536 SendPlayerHP(peer_id);
1541 void Server::SendHP(u16 peer_id, u8 hp)
1543 DSTACK(FUNCTION_NAME);
1545 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1550 void Server::SendBreath(u16 peer_id, u16 breath)
1552 DSTACK(FUNCTION_NAME);
1554 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1555 pkt << (u16) breath;
1559 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1560 const std::string &custom_reason, bool reconnect)
1562 assert(reason < SERVER_ACCESSDENIED_MAX);
1564 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1566 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1567 pkt << custom_reason;
1568 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1569 reason == SERVER_ACCESSDENIED_CRASH)
1570 pkt << custom_reason << (u8)reconnect;
1574 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1576 DSTACK(FUNCTION_NAME);
1578 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1583 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1584 v3f camera_point_target)
1586 DSTACK(FUNCTION_NAME);
1588 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1589 pkt << set_camera_point_target << camera_point_target;
1593 void Server::SendItemDef(u16 peer_id,
1594 IItemDefManager *itemdef, u16 protocol_version)
1596 DSTACK(FUNCTION_NAME);
1598 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1602 u32 length of the next item
1603 zlib-compressed serialized ItemDefManager
1605 std::ostringstream tmp_os(std::ios::binary);
1606 itemdef->serialize(tmp_os, protocol_version);
1607 std::ostringstream tmp_os2(std::ios::binary);
1608 compressZlib(tmp_os.str(), tmp_os2);
1609 pkt.putLongString(tmp_os2.str());
1612 verbosestream << "Server: Sending item definitions to id(" << peer_id
1613 << "): size=" << pkt.getSize() << std::endl;
1618 void Server::SendNodeDef(u16 peer_id,
1619 INodeDefManager *nodedef, u16 protocol_version)
1621 DSTACK(FUNCTION_NAME);
1623 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1627 u32 length of the next item
1628 zlib-compressed serialized NodeDefManager
1630 std::ostringstream tmp_os(std::ios::binary);
1631 nodedef->serialize(tmp_os, protocol_version);
1632 std::ostringstream tmp_os2(std::ios::binary);
1633 compressZlib(tmp_os.str(), tmp_os2);
1635 pkt.putLongString(tmp_os2.str());
1638 verbosestream << "Server: Sending node definitions to id(" << peer_id
1639 << "): size=" << pkt.getSize() << std::endl;
1645 Non-static send methods
1648 void Server::SendInventory(PlayerSAO* playerSAO)
1650 DSTACK(FUNCTION_NAME);
1652 UpdateCrafting(playerSAO->getPlayer());
1658 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1660 std::ostringstream os;
1661 playerSAO->getInventory()->serialize(os);
1663 std::string s = os.str();
1665 pkt.putRawString(s.c_str(), s.size());
1669 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1671 DSTACK(FUNCTION_NAME);
1673 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1676 if (peer_id != PEER_ID_INEXISTENT) {
1680 m_clients.sendToAll(&pkt);
1684 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1685 const std::string &formname)
1687 DSTACK(FUNCTION_NAME);
1689 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1690 if (formspec == "" ){
1691 //the client should close the formspec
1692 pkt.putLongString("");
1694 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1701 // Spawns a particle on peer with peer_id
1702 void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
1703 v3f pos, v3f velocity, v3f acceleration,
1704 float expirationtime, float size, bool collisiondetection,
1705 bool collision_removal,
1706 bool vertical, const std::string &texture,
1707 const struct TileAnimationParams &animation, u8 glow)
1709 DSTACK(FUNCTION_NAME);
1710 if (peer_id == PEER_ID_INEXISTENT) {
1711 // This sucks and should be replaced by a better solution in a refactor:
1712 std::vector<u16> clients = m_clients.getClientIDs();
1713 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1714 RemotePlayer *player = m_env->getPlayer(*i);
1717 SendSpawnParticle(*i, player->protocol_version,
1718 pos, velocity, acceleration,
1719 expirationtime, size, collisiondetection,
1720 collision_removal, vertical, texture, animation, glow);
1725 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1727 pkt << pos << velocity << acceleration << expirationtime
1728 << size << collisiondetection;
1729 pkt.putLongString(texture);
1731 pkt << collision_removal;
1732 // This is horrible but required (why are there two ways to serialize pkts?)
1733 std::ostringstream os(std::ios_base::binary);
1734 animation.serialize(os, protocol_version);
1735 pkt.putRawString(os.str());
1741 // Adds a ParticleSpawner on peer with peer_id
1742 void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
1743 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1744 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1745 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1746 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1747 const struct TileAnimationParams &animation, u8 glow)
1749 DSTACK(FUNCTION_NAME);
1750 if (peer_id == PEER_ID_INEXISTENT) {
1751 // This sucks and should be replaced:
1752 std::vector<u16> clients = m_clients.getClientIDs();
1753 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
1754 RemotePlayer *player = m_env->getPlayer(*i);
1757 SendAddParticleSpawner(*i, player->protocol_version,
1758 amount, spawntime, minpos, maxpos,
1759 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1760 minsize, maxsize, collisiondetection, collision_removal,
1761 attached_id, vertical, texture, id, animation, glow);
1766 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1768 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1769 << minacc << maxacc << minexptime << maxexptime << minsize
1770 << maxsize << collisiondetection;
1772 pkt.putLongString(texture);
1774 pkt << id << vertical;
1775 pkt << collision_removal;
1777 // This is horrible but required
1778 std::ostringstream os(std::ios_base::binary);
1779 animation.serialize(os, protocol_version);
1780 pkt.putRawString(os.str());
1786 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1788 DSTACK(FUNCTION_NAME);
1790 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1792 // Ugly error in this packet
1795 if (peer_id != PEER_ID_INEXISTENT) {
1799 m_clients.sendToAll(&pkt);
1804 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1806 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1808 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1809 << form->text << form->number << form->item << form->dir
1810 << form->align << form->offset << form->world_pos << form->size;
1815 void Server::SendHUDRemove(u16 peer_id, u32 id)
1817 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1822 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1824 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1825 pkt << id << (u8) stat;
1829 case HUD_STAT_SCALE:
1830 case HUD_STAT_ALIGN:
1831 case HUD_STAT_OFFSET:
1832 pkt << *(v2f *) value;
1836 pkt << *(std::string *) value;
1838 case HUD_STAT_WORLD_POS:
1839 pkt << *(v3f *) value;
1842 pkt << *(v2s32 *) value;
1844 case HUD_STAT_NUMBER:
1848 pkt << *(u32 *) value;
1855 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1857 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1859 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1861 pkt << flags << mask;
1866 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1868 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1869 pkt << param << value;
1873 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1874 const std::string &type, const std::vector<std::string> ¶ms,
1877 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1878 pkt << bgcolor << type << (u16) params.size();
1880 for(size_t i=0; i<params.size(); i++)
1888 void Server::SendCloudParams(u16 peer_id, float density,
1889 const video::SColor &color_bright,
1890 const video::SColor &color_ambient,
1895 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1896 pkt << density << color_bright << color_ambient
1897 << height << thickness << speed;
1902 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1905 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1908 pkt << do_override << (u16) (ratio * 65535);
1913 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1915 DSTACK(FUNCTION_NAME);
1917 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1918 pkt << time << time_speed;
1920 if (peer_id == PEER_ID_INEXISTENT) {
1921 m_clients.sendToAll(&pkt);
1928 void Server::SendPlayerHP(u16 peer_id)
1930 DSTACK(FUNCTION_NAME);
1931 PlayerSAO *playersao = getPlayerSAO(peer_id);
1932 // In some rare case if the player is disconnected
1933 // while Lua call l_punch, for example, this can be NULL
1937 SendHP(peer_id, playersao->getHP());
1938 m_script->player_event(playersao,"health_changed");
1940 // Send to other clients
1941 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1942 ActiveObjectMessage aom(playersao->getId(), true, str);
1943 playersao->m_messages_out.push(aom);
1946 void Server::SendPlayerBreath(PlayerSAO *sao)
1948 DSTACK(FUNCTION_NAME);
1951 m_script->player_event(sao, "breath_changed");
1952 SendBreath(sao->getPeerID(), sao->getBreath());
1955 void Server::SendMovePlayer(u16 peer_id)
1957 DSTACK(FUNCTION_NAME);
1958 RemotePlayer *player = m_env->getPlayer(peer_id);
1960 PlayerSAO *sao = player->getPlayerSAO();
1963 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1964 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1967 v3f pos = sao->getBasePosition();
1968 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1969 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1970 << " pitch=" << sao->getPitch()
1971 << " yaw=" << sao->getYaw()
1978 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1980 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1983 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1984 << animation_frames[3] << animation_speed;
1989 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1991 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1992 pkt << first << third;
1995 void Server::SendPlayerPrivileges(u16 peer_id)
1997 RemotePlayer *player = m_env->getPlayer(peer_id);
1999 if(player->peer_id == PEER_ID_INEXISTENT)
2002 std::set<std::string> privs;
2003 m_script->getAuth(player->getName(), NULL, &privs);
2005 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
2006 pkt << (u16) privs.size();
2008 for(std::set<std::string>::const_iterator i = privs.begin();
2009 i != privs.end(); ++i) {
2016 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2018 RemotePlayer *player = m_env->getPlayer(peer_id);
2020 if(player->peer_id == PEER_ID_INEXISTENT)
2023 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2024 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2028 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2030 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2031 pkt.putRawString(datas.c_str(), datas.size());
2033 return pkt.getSize();
2036 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2038 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2039 datas.size(), peer_id);
2041 pkt.putRawString(datas.c_str(), datas.size());
2043 m_clients.send(pkt.getPeerId(),
2044 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2049 s32 Server::playSound(const SimpleSoundSpec &spec,
2050 const ServerSoundParams ¶ms)
2052 // Find out initial position of sound
2053 bool pos_exists = false;
2054 v3f pos = params.getPos(m_env, &pos_exists);
2055 // If position is not found while it should be, cancel sound
2056 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2059 // Filter destination clients
2060 std::vector<u16> dst_clients;
2061 if(params.to_player != "")
2063 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2065 infostream<<"Server::playSound: Player \""<<params.to_player
2066 <<"\" not found"<<std::endl;
2069 if(player->peer_id == PEER_ID_INEXISTENT){
2070 infostream<<"Server::playSound: Player \""<<params.to_player
2071 <<"\" not connected"<<std::endl;
2074 dst_clients.push_back(player->peer_id);
2077 std::vector<u16> clients = m_clients.getClientIDs();
2079 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2080 RemotePlayer *player = m_env->getPlayer(*i);
2084 PlayerSAO *sao = player->getPlayerSAO();
2089 if(sao->getBasePosition().getDistanceFrom(pos) >
2090 params.max_hear_distance)
2093 dst_clients.push_back(*i);
2097 if(dst_clients.empty())
2101 s32 id = m_next_sound_id++;
2102 // The sound will exist as a reference in m_playing_sounds
2103 m_playing_sounds[id] = ServerPlayingSound();
2104 ServerPlayingSound &psound = m_playing_sounds[id];
2105 psound.params = params;
2108 float gain = params.gain * spec.gain;
2109 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2110 pkt << id << spec.name << gain
2111 << (u8) params.type << pos << params.object
2112 << params.loop << params.fade;
2114 // Backwards compability
2115 bool play_sound = gain > 0;
2117 for (std::vector<u16>::iterator i = dst_clients.begin();
2118 i != dst_clients.end(); ++i) {
2119 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2120 psound.clients.insert(*i);
2121 m_clients.send(*i, 0, &pkt, true);
2126 void Server::stopSound(s32 handle)
2128 // Get sound reference
2129 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2130 if (i == m_playing_sounds.end())
2132 ServerPlayingSound &psound = i->second;
2134 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2137 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2138 i != psound.clients.end(); ++i) {
2140 m_clients.send(*i, 0, &pkt, true);
2142 // Remove sound reference
2143 m_playing_sounds.erase(i);
2146 void Server::fadeSound(s32 handle, float step, float gain)
2148 // Get sound reference
2149 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i =
2150 m_playing_sounds.find(handle);
2151 if (i == m_playing_sounds.end())
2154 ServerPlayingSound &psound = i->second;
2155 psound.params.gain = gain;
2157 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2158 pkt << handle << step << gain;
2160 // Backwards compability
2161 bool play_sound = gain > 0;
2162 ServerPlayingSound compat_psound = psound;
2163 compat_psound.clients.clear();
2165 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2166 compat_pkt << handle;
2168 for (UNORDERED_SET<u16>::iterator it = psound.clients.begin();
2169 it != psound.clients.end();) {
2170 if (m_clients.getProtocolVersion(*it) >= 32) {
2172 m_clients.send(*it, 0, &pkt, true);
2175 compat_psound.clients.insert(*it);
2177 m_clients.send(*it, 0, &compat_pkt, true);
2178 psound.clients.erase(it++);
2182 // Remove sound reference
2183 if (!play_sound || psound.clients.size() == 0)
2184 m_playing_sounds.erase(i);
2186 if (play_sound && compat_psound.clients.size() > 0) {
2187 // Play new sound volume on older clients
2188 playSound(compat_psound.spec, compat_psound.params);
2192 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2193 std::vector<u16> *far_players, float far_d_nodes)
2195 float maxd = far_d_nodes*BS;
2196 v3f p_f = intToFloat(p, BS);
2198 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2201 std::vector<u16> clients = m_clients.getClientIDs();
2202 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2205 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2206 PlayerSAO *sao = player->getPlayerSAO();
2210 // If player is far away, only set modified blocks not sent
2211 v3f player_pos = sao->getBasePosition();
2212 if (player_pos.getDistanceFrom(p_f) > maxd) {
2213 far_players->push_back(*i);
2220 m_clients.send(*i, 0, &pkt, true);
2224 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2225 std::vector<u16> *far_players, float far_d_nodes,
2226 bool remove_metadata)
2228 float maxd = far_d_nodes*BS;
2229 v3f p_f = intToFloat(p, BS);
2231 std::vector<u16> clients = m_clients.getClientIDs();
2232 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2235 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2236 PlayerSAO *sao = player->getPlayerSAO();
2240 // If player is far away, only set modified blocks not sent
2241 v3f player_pos = sao->getBasePosition();
2242 if(player_pos.getDistanceFrom(p_f) > maxd) {
2243 far_players->push_back(*i);
2249 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2251 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2253 pkt << p << n.param0 << n.param1 << n.param2
2254 << (u8) (remove_metadata ? 0 : 1);
2259 if (pkt.getSize() > 0)
2260 m_clients.send(*i, 0, &pkt, true);
2264 void Server::setBlockNotSent(v3s16 p)
2266 std::vector<u16> clients = m_clients.getClientIDs();
2268 for(std::vector<u16>::iterator i = clients.begin();
2269 i != clients.end(); ++i) {
2270 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2271 client->SetBlockNotSent(p);
2276 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2278 DSTACK(FUNCTION_NAME);
2280 v3s16 p = block->getPos();
2283 Create a packet with the block in the right format
2286 std::ostringstream os(std::ios_base::binary);
2287 block->serialize(os, ver, false);
2288 block->serializeNetworkSpecific(os);
2289 std::string s = os.str();
2291 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2294 pkt.putRawString(s.c_str(), s.size());
2298 void Server::SendBlocks(float dtime)
2300 DSTACK(FUNCTION_NAME);
2302 MutexAutoLock envlock(m_env_mutex);
2303 //TODO check if one big lock could be faster then multiple small ones
2305 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2307 std::vector<PrioritySortedBlockTransfer> queue;
2309 s32 total_sending = 0;
2312 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2314 std::vector<u16> clients = m_clients.getClientIDs();
2317 for(std::vector<u16>::iterator i = clients.begin();
2318 i != clients.end(); ++i) {
2319 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2324 total_sending += client->SendingCount();
2325 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2331 // Lowest priority number comes first.
2332 // Lowest is most important.
2333 std::sort(queue.begin(), queue.end());
2336 for(u32 i=0; i<queue.size(); i++)
2338 //TODO: Calculate limit dynamically
2339 if(total_sending >= g_settings->getS32
2340 ("max_simultaneous_block_sends_server_total"))
2343 PrioritySortedBlockTransfer q = queue[i];
2345 MapBlock *block = NULL;
2348 block = m_env->getMap().getBlockNoCreate(q.pos);
2350 catch(InvalidPositionException &e)
2355 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2360 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2362 client->SentBlock(q.pos);
2368 void Server::fillMediaCache()
2370 DSTACK(FUNCTION_NAME);
2372 infostream<<"Server: Calculating media file checksums"<<std::endl;
2374 // Collect all media file paths
2375 std::vector<std::string> paths;
2376 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2377 i != m_mods.end(); ++i) {
2378 const ModSpec &mod = *i;
2379 paths.push_back(mod.path + DIR_DELIM + "textures");
2380 paths.push_back(mod.path + DIR_DELIM + "sounds");
2381 paths.push_back(mod.path + DIR_DELIM + "media");
2382 paths.push_back(mod.path + DIR_DELIM + "models");
2384 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2386 // Collect media file information from paths into cache
2387 for(std::vector<std::string>::iterator i = paths.begin();
2388 i != paths.end(); ++i) {
2389 std::string mediapath = *i;
2390 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2391 for (u32 j = 0; j < dirlist.size(); j++) {
2392 if (dirlist[j].dir) // Ignode dirs
2394 std::string filename = dirlist[j].name;
2395 // If name contains illegal characters, ignore the file
2396 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2397 infostream<<"Server: ignoring illegal file name: \""
2398 << filename << "\"" << std::endl;
2401 // If name is not in a supported format, ignore it
2402 const char *supported_ext[] = {
2403 ".png", ".jpg", ".bmp", ".tga",
2404 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2406 ".x", ".b3d", ".md2", ".obj",
2409 if (removeStringEnd(filename, supported_ext) == ""){
2410 infostream << "Server: ignoring unsupported file extension: \""
2411 << filename << "\"" << std::endl;
2414 // Ok, attempt to load the file and add to cache
2415 std::string filepath = mediapath + DIR_DELIM + filename;
2417 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2419 errorstream << "Server::fillMediaCache(): Could not open \""
2420 << filename << "\" for reading" << std::endl;
2423 std::ostringstream tmp_os(std::ios_base::binary);
2427 fis.read(buf, 1024);
2428 std::streamsize len = fis.gcount();
2429 tmp_os.write(buf, len);
2438 errorstream<<"Server::fillMediaCache(): Failed to read \""
2439 << filename << "\"" << std::endl;
2442 if(tmp_os.str().length() == 0) {
2443 errorstream << "Server::fillMediaCache(): Empty file \""
2444 << filepath << "\"" << std::endl;
2449 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2451 unsigned char *digest = sha1.getDigest();
2452 std::string sha1_base64 = base64_encode(digest, 20);
2453 std::string sha1_hex = hex_encode((char*)digest, 20);
2457 m_media[filename] = MediaInfo(filepath, sha1_base64);
2458 verbosestream << "Server: " << sha1_hex << " is " << filename
2464 void Server::sendMediaAnnouncement(u16 peer_id)
2466 DSTACK(FUNCTION_NAME);
2468 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2472 std::ostringstream os(std::ios_base::binary);
2474 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2475 pkt << (u16) m_media.size();
2477 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2478 i != m_media.end(); ++i) {
2479 pkt << i->first << i->second.sha1_digest;
2482 pkt << g_settings->get("remote_media");
2486 struct SendableMedia
2492 SendableMedia(const std::string &name_="", const std::string &path_="",
2493 const std::string &data_=""):
2500 void Server::sendRequestedMedia(u16 peer_id,
2501 const std::vector<std::string> &tosend)
2503 DSTACK(FUNCTION_NAME);
2505 verbosestream<<"Server::sendRequestedMedia(): "
2506 <<"Sending files to client"<<std::endl;
2510 // Put 5kB in one bunch (this is not accurate)
2511 u32 bytes_per_bunch = 5000;
2513 std::vector< std::vector<SendableMedia> > file_bunches;
2514 file_bunches.push_back(std::vector<SendableMedia>());
2516 u32 file_size_bunch_total = 0;
2518 for(std::vector<std::string>::const_iterator i = tosend.begin();
2519 i != tosend.end(); ++i) {
2520 const std::string &name = *i;
2522 if (m_media.find(name) == m_media.end()) {
2523 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2524 <<"unknown file \""<<(name)<<"\""<<std::endl;
2528 //TODO get path + name
2529 std::string tpath = m_media[name].path;
2532 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2533 if(fis.good() == false){
2534 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2535 <<tpath<<"\" for reading"<<std::endl;
2538 std::ostringstream tmp_os(std::ios_base::binary);
2542 fis.read(buf, 1024);
2543 std::streamsize len = fis.gcount();
2544 tmp_os.write(buf, len);
2545 file_size_bunch_total += len;
2554 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2555 <<name<<"\""<<std::endl;
2558 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2559 <<tname<<"\""<<std::endl;*/
2561 file_bunches[file_bunches.size()-1].push_back(
2562 SendableMedia(name, tpath, tmp_os.str()));
2564 // Start next bunch if got enough data
2565 if(file_size_bunch_total >= bytes_per_bunch) {
2566 file_bunches.push_back(std::vector<SendableMedia>());
2567 file_size_bunch_total = 0;
2572 /* Create and send packets */
2574 u16 num_bunches = file_bunches.size();
2575 for(u16 i = 0; i < num_bunches; i++) {
2578 u16 total number of texture bunches
2579 u16 index of this bunch
2580 u32 number of files in this bunch
2589 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2590 pkt << num_bunches << i << (u32) file_bunches[i].size();
2592 for(std::vector<SendableMedia>::iterator
2593 j = file_bunches[i].begin();
2594 j != file_bunches[i].end(); ++j) {
2596 pkt.putLongString(j->data);
2599 verbosestream << "Server::sendRequestedMedia(): bunch "
2600 << i << "/" << num_bunches
2601 << " files=" << file_bunches[i].size()
2602 << " size=" << pkt.getSize() << std::endl;
2607 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2609 if(m_detached_inventories.count(name) == 0) {
2610 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2613 Inventory *inv = m_detached_inventories[name];
2614 std::ostringstream os(std::ios_base::binary);
2616 os << serializeString(name);
2620 std::string s = os.str();
2622 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2623 pkt.putRawString(s.c_str(), s.size());
2625 const std::string &check = m_detached_inventories_player[name];
2626 if (peer_id == PEER_ID_INEXISTENT) {
2628 return m_clients.sendToAll(&pkt);
2629 RemotePlayer *p = m_env->getPlayer(check.c_str());
2631 m_clients.send(p->peer_id, 0, &pkt, true);
2633 if (check == "" || getPlayerName(peer_id) == check)
2638 void Server::sendDetachedInventories(u16 peer_id)
2640 DSTACK(FUNCTION_NAME);
2642 for(std::map<std::string, Inventory*>::iterator
2643 i = m_detached_inventories.begin();
2644 i != m_detached_inventories.end(); ++i) {
2645 const std::string &name = i->first;
2646 //Inventory *inv = i->second;
2647 sendDetachedInventory(name, peer_id);
2655 void Server::DiePlayer(u16 peer_id)
2657 DSTACK(FUNCTION_NAME);
2658 PlayerSAO *playersao = getPlayerSAO(peer_id);
2659 // In some rare cases this can be NULL -- if the player is disconnected
2660 // when a Lua function modifies l_punch, for example
2664 infostream << "Server::DiePlayer(): Player "
2665 << playersao->getPlayer()->getName()
2666 << " dies" << std::endl;
2668 playersao->setHP(0);
2670 // Trigger scripted stuff
2671 m_script->on_dieplayer(playersao);
2673 SendPlayerHP(peer_id);
2674 SendDeathscreen(peer_id, false, v3f(0,0,0));
2677 void Server::RespawnPlayer(u16 peer_id)
2679 DSTACK(FUNCTION_NAME);
2681 PlayerSAO *playersao = getPlayerSAO(peer_id);
2684 infostream << "Server::RespawnPlayer(): Player "
2685 << playersao->getPlayer()->getName()
2686 << " respawns" << std::endl;
2688 playersao->setHP(PLAYER_MAX_HP);
2689 playersao->setBreath(PLAYER_MAX_BREATH);
2691 bool repositioned = m_script->on_respawnplayer(playersao);
2692 if (!repositioned) {
2693 // setPos will send the new position to client
2694 playersao->setPos(findSpawnPos());
2697 SendPlayerHP(peer_id);
2701 void Server::DenySudoAccess(u16 peer_id)
2703 DSTACK(FUNCTION_NAME);
2705 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2710 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2711 const std::string &str_reason, bool reconnect)
2713 if (proto_ver >= 25) {
2714 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2716 std::wstring wreason = utf8_to_wide(
2717 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2718 accessDeniedStrings[(u8)reason]);
2719 SendAccessDenied_Legacy(peer_id, wreason);
2722 m_clients.event(peer_id, CSE_SetDenied);
2723 m_con.DisconnectPeer(peer_id);
2727 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2729 DSTACK(FUNCTION_NAME);
2731 SendAccessDenied(peer_id, reason, custom_reason);
2732 m_clients.event(peer_id, CSE_SetDenied);
2733 m_con.DisconnectPeer(peer_id);
2736 // 13/03/15: remove this function when protocol version 25 will become
2737 // the minimum version for MT users, maybe in 1 year
2738 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2740 DSTACK(FUNCTION_NAME);
2742 SendAccessDenied_Legacy(peer_id, reason);
2743 m_clients.event(peer_id, CSE_SetDenied);
2744 m_con.DisconnectPeer(peer_id);
2747 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2749 DSTACK(FUNCTION_NAME);
2752 RemoteClient* client = getClient(peer_id, CS_Invalid);
2754 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2756 // Right now, the auth mechs don't change between login and sudo mode.
2757 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2758 client->allowed_sudo_mechs = sudo_auth_mechs;
2760 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2761 << g_settings->getFloat("dedicated_server_step")
2765 m_clients.event(peer_id, CSE_AuthAccept);
2767 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2769 // We only support SRP right now
2770 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2772 resp_pkt << sudo_auth_mechs;
2774 m_clients.event(peer_id, CSE_SudoSuccess);
2778 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2780 DSTACK(FUNCTION_NAME);
2781 std::wstring message;
2784 Clear references to playing sounds
2786 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2787 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2788 ServerPlayingSound &psound = i->second;
2789 psound.clients.erase(peer_id);
2790 if (psound.clients.empty())
2791 m_playing_sounds.erase(i++);
2796 RemotePlayer *player = m_env->getPlayer(peer_id);
2798 /* Run scripts and remove from environment */
2799 if (player != NULL) {
2800 PlayerSAO *playersao = player->getPlayerSAO();
2803 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2805 playersao->disconnected();
2812 if(player != NULL && reason != CDR_DENY) {
2813 std::ostringstream os(std::ios_base::binary);
2814 std::vector<u16> clients = m_clients.getClientIDs();
2816 for(std::vector<u16>::iterator i = clients.begin();
2817 i != clients.end(); ++i) {
2819 RemotePlayer *player = m_env->getPlayer(*i);
2823 // Get name of player
2824 os << player->getName() << " ";
2827 std::string name = player->getName();
2828 actionstream << name << " "
2829 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2830 << " List of players: " << os.str() << std::endl;
2832 m_admin_chat->outgoing_queue.push_back(
2833 new ChatEventNick(CET_NICK_REMOVE, name));
2837 MutexAutoLock env_lock(m_env_mutex);
2838 m_clients.DeleteClient(peer_id);
2842 // Send leave chat message to all remaining clients
2843 if(message.length() != 0)
2844 SendChatMessage(PEER_ID_INEXISTENT,message);
2847 void Server::UpdateCrafting(RemotePlayer *player)
2849 DSTACK(FUNCTION_NAME);
2851 // Get a preview for crafting
2853 InventoryLocation loc;
2854 loc.setPlayer(player->getName());
2855 std::vector<ItemStack> output_replacements;
2856 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2857 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2858 (&player->inventory)->getList("craft"), loc);
2860 // Put the new preview in
2861 InventoryList *plist = player->inventory.getList("craftpreview");
2862 sanity_check(plist);
2863 sanity_check(plist->getSize() >= 1);
2864 plist->changeItem(0, preview);
2867 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2869 if (evt->type == CET_NICK_ADD) {
2870 // The terminal informed us of its nick choice
2871 m_admin_nick = ((ChatEventNick *)evt)->nick;
2872 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2873 errorstream << "You haven't set up an account." << std::endl
2874 << "Please log in using the client as '"
2875 << m_admin_nick << "' with a secure password." << std::endl
2876 << "Until then, you can't execute admin tasks via the console," << std::endl
2877 << "and everybody can claim the user account instead of you," << std::endl
2878 << "giving them full control over this server." << std::endl;
2881 assert(evt->type == CET_CHAT);
2882 handleAdminChat((ChatEventChat *)evt);
2886 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2887 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2889 // If something goes wrong, this player is to blame
2890 RollbackScopeActor rollback_scope(m_rollback,
2891 std::string("player:") + name);
2894 switch (player->canSendChatMessage()) {
2895 case RPLAYER_CHATRESULT_FLOODING: {
2896 std::wstringstream ws;
2897 ws << L"You cannot send more messages. You are limited to "
2898 << g_settings->getFloat("chat_message_limit_per_10sec")
2899 << L" messages per 10 seconds.";
2902 case RPLAYER_CHATRESULT_KICK:
2903 DenyAccess_Legacy(player->peer_id,
2904 L"You have been kicked due to message flooding.");
2906 case RPLAYER_CHATRESULT_OK:
2909 FATAL_ERROR("Unhandled chat filtering result found.");
2913 if (m_max_chatmessage_length > 0
2914 && wmessage.length() > m_max_chatmessage_length) {
2915 return L"Your message exceed the maximum chat message limit set on the server. "
2916 L"It was refused. Send a shorter message";
2919 // Run script hook, exit if script ate the chat message
2920 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2925 // Whether to send line to the player that sent the message, or to all players
2926 bool broadcast_line = true;
2928 if (check_shout_priv && !checkPriv(name, "shout")) {
2929 line += L"-!- You don't have permission to shout.";
2930 broadcast_line = false;
2939 Tell calling method to send the message to sender
2941 if (!broadcast_line) {
2945 Send the message to others
2947 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2949 std::vector<u16> clients = m_clients.getClientIDs();
2952 Send the message back to the inital sender
2953 if they are using protocol version >= 29
2956 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2957 if (player && player->protocol_version >= 29)
2958 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2960 for (u16 i = 0; i < clients.size(); i++) {
2961 u16 cid = clients[i];
2962 if (cid != peer_id_to_avoid_sending)
2963 SendChatMessage(cid, line);
2969 void Server::handleAdminChat(const ChatEventChat *evt)
2971 std::string name = evt->nick;
2972 std::wstring wname = utf8_to_wide(name);
2973 std::wstring wmessage = evt->evt_msg;
2975 std::wstring answer = handleChat(name, wname, wmessage);
2977 // If asked to send answer to sender
2978 if (!answer.empty()) {
2979 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2983 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2985 RemoteClient *client = getClientNoEx(peer_id,state_min);
2987 throw ClientNotFoundException("Client not found");
2991 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2993 return m_clients.getClientNoEx(peer_id, state_min);
2996 std::string Server::getPlayerName(u16 peer_id)
2998 RemotePlayer *player = m_env->getPlayer(peer_id);
3000 return "[id="+itos(peer_id)+"]";
3001 return player->getName();
3004 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3006 RemotePlayer *player = m_env->getPlayer(peer_id);
3009 return player->getPlayerSAO();
3012 std::wstring Server::getStatusString()
3014 std::wostringstream os(std::ios_base::binary);
3017 os<<L"version="<<narrow_to_wide(g_version_string);
3019 os<<L", uptime="<<m_uptime.get();
3021 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3022 // Information about clients
3025 std::vector<u16> clients = m_clients.getClientIDs();
3026 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3028 RemotePlayer *player = m_env->getPlayer(*i);
3029 // Get name of player
3030 std::wstring name = L"unknown";
3032 name = narrow_to_wide(player->getName());
3033 // Add name to information string
3041 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3042 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3043 if(g_settings->get("motd") != "")
3044 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3048 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3050 std::set<std::string> privs;
3051 m_script->getAuth(name, NULL, &privs);
3055 bool Server::checkPriv(const std::string &name, const std::string &priv)
3057 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3058 return (privs.count(priv) != 0);
3061 void Server::reportPrivsModified(const std::string &name)
3064 std::vector<u16> clients = m_clients.getClientIDs();
3065 for(std::vector<u16>::iterator i = clients.begin();
3066 i != clients.end(); ++i) {
3067 RemotePlayer *player = m_env->getPlayer(*i);
3068 reportPrivsModified(player->getName());
3071 RemotePlayer *player = m_env->getPlayer(name.c_str());
3074 SendPlayerPrivileges(player->peer_id);
3075 PlayerSAO *sao = player->getPlayerSAO();
3078 sao->updatePrivileges(
3079 getPlayerEffectivePrivs(name),
3084 void Server::reportInventoryFormspecModified(const std::string &name)
3086 RemotePlayer *player = m_env->getPlayer(name.c_str());
3089 SendPlayerInventoryFormspec(player->peer_id);
3092 void Server::setIpBanned(const std::string &ip, const std::string &name)
3094 m_banmanager->add(ip, name);
3097 void Server::unsetIpBanned(const std::string &ip_or_name)
3099 m_banmanager->remove(ip_or_name);
3102 std::string Server::getBanDescription(const std::string &ip_or_name)
3104 return m_banmanager->getBanDescription(ip_or_name);
3107 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3109 // m_env will be NULL if the server is initializing
3113 if (m_admin_nick == name && !m_admin_nick.empty()) {
3114 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3117 RemotePlayer *player = m_env->getPlayer(name);
3122 if (player->peer_id == PEER_ID_INEXISTENT)
3125 SendChatMessage(player->peer_id, msg);
3128 bool Server::showFormspec(const char *playername, const std::string &formspec,
3129 const std::string &formname)
3131 // m_env will be NULL if the server is initializing
3135 RemotePlayer *player = m_env->getPlayer(playername);
3139 SendShowFormspecMessage(player->peer_id, formspec, formname);
3143 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3148 u32 id = player->addHud(form);
3150 SendHUDAdd(player->peer_id, id, form);
3155 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3159 HudElement* todel = player->removeHud(id);
3166 SendHUDRemove(player->peer_id, id);
3170 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3175 SendHUDChange(player->peer_id, id, stat, data);
3179 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3184 SendHUDSetFlags(player->peer_id, flags, mask);
3185 player->hud_flags &= ~mask;
3186 player->hud_flags |= flags;
3188 PlayerSAO* playersao = player->getPlayerSAO();
3190 if (playersao == NULL)
3193 m_script->player_event(playersao, "hud_changed");
3197 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3202 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3205 player->setHotbarItemcount(hotbar_itemcount);
3206 std::ostringstream os(std::ios::binary);
3207 writeS32(os, hotbar_itemcount);
3208 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3212 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3217 player->setHotbarImage(name);
3218 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3221 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3225 return player->getHotbarImage();
3228 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3233 player->setHotbarSelectedImage(name);
3234 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3237 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3238 v2s32 animation_frames[4], f32 frame_speed)
3243 player->setLocalAnimations(animation_frames, frame_speed);
3244 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3248 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3253 player->eye_offset_first = first;
3254 player->eye_offset_third = third;
3255 SendEyeOffset(player->peer_id, first, third);
3259 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3260 const std::string &type, const std::vector<std::string> ¶ms,
3266 player->setSky(bgcolor, type, params, clouds);
3267 SendSetSky(player->peer_id, bgcolor, type, params, clouds);
3271 bool Server::setClouds(RemotePlayer *player, float density,
3272 const video::SColor &color_bright,
3273 const video::SColor &color_ambient,
3281 SendCloudParams(player->peer_id, density,
3282 color_bright, color_ambient, height,
3287 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3293 player->overrideDayNightRatio(do_override, ratio);
3294 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3298 void Server::notifyPlayers(const std::wstring &msg)
3300 SendChatMessage(PEER_ID_INEXISTENT,msg);
3303 void Server::spawnParticle(const std::string &playername, v3f pos,
3304 v3f velocity, v3f acceleration,
3305 float expirationtime, float size, bool
3306 collisiondetection, bool collision_removal,
3307 bool vertical, const std::string &texture,
3308 const struct TileAnimationParams &animation, u8 glow)
3310 // m_env will be NULL if the server is initializing
3314 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3315 if (playername != "") {
3316 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3319 peer_id = player->peer_id;
3320 proto_ver = player->protocol_version;
3323 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3324 expirationtime, size, collisiondetection,
3325 collision_removal, vertical, texture, animation, glow);
3328 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3329 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3330 float minexptime, float maxexptime, float minsize, float maxsize,
3331 bool collisiondetection, bool collision_removal,
3332 ServerActiveObject *attached, bool vertical, const std::string &texture,
3333 const std::string &playername, const struct TileAnimationParams &animation,
3336 // m_env will be NULL if the server is initializing
3340 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3341 if (playername != "") {
3342 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3345 peer_id = player->peer_id;
3346 proto_ver = player->protocol_version;
3349 u16 attached_id = attached ? attached->getId() : 0;
3352 if (attached_id == 0)
3353 id = m_env->addParticleSpawner(spawntime);
3355 id = m_env->addParticleSpawner(spawntime, attached_id);
3357 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3358 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3359 minexptime, maxexptime, minsize, maxsize,
3360 collisiondetection, collision_removal, attached_id, vertical,
3361 texture, id, animation, glow);
3366 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3368 // m_env will be NULL if the server is initializing
3370 throw ServerError("Can't delete particle spawners during initialisation!");
3372 u16 peer_id = PEER_ID_INEXISTENT;
3373 if (playername != "") {
3374 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3377 peer_id = player->peer_id;
3380 m_env->deleteParticleSpawner(id);
3381 SendDeleteParticleSpawner(peer_id, id);
3384 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3386 if(m_detached_inventories.count(name) > 0){
3387 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3388 delete m_detached_inventories[name];
3390 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3392 Inventory *inv = new Inventory(m_itemdef);
3394 m_detached_inventories[name] = inv;
3395 m_detached_inventories_player[name] = player;
3396 //TODO find a better way to do this
3397 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3401 // actions: time-reversed list
3402 // Return value: success/failure
3403 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3404 std::list<std::string> *log)
3406 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3407 ServerMap *map = (ServerMap*)(&m_env->getMap());
3409 // Fail if no actions to handle
3410 if(actions.empty()){
3411 log->push_back("Nothing to do.");
3418 for(std::list<RollbackAction>::const_iterator
3419 i = actions.begin();
3420 i != actions.end(); ++i)
3422 const RollbackAction &action = *i;
3424 bool success = action.applyRevert(map, this, this);
3427 std::ostringstream os;
3428 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3429 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3431 log->push_back(os.str());
3433 std::ostringstream os;
3434 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3435 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3437 log->push_back(os.str());
3441 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3442 <<" failed"<<std::endl;
3444 // Call it done if less than half failed
3445 return num_failed <= num_tried/2;
3448 // IGameDef interface
3450 IItemDefManager *Server::getItemDefManager()
3455 INodeDefManager *Server::getNodeDefManager()
3460 ICraftDefManager *Server::getCraftDefManager()
3465 u16 Server::allocateUnknownNodeId(const std::string &name)
3467 return m_nodedef->allocateDummy(name);
3470 MtEventManager *Server::getEventManager()
3475 IWritableItemDefManager *Server::getWritableItemDefManager()
3480 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3485 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3490 const ModSpec *Server::getModSpec(const std::string &modname) const
3492 std::vector<ModSpec>::const_iterator it;
3493 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3494 const ModSpec &mod = *it;
3495 if (mod.name == modname)
3501 void Server::getModNames(std::vector<std::string> &modlist)
3503 std::vector<ModSpec>::iterator it;
3504 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3505 modlist.push_back(it->name);
3508 std::string Server::getBuiltinLuaPath()
3510 return porting::path_share + DIR_DELIM + "builtin";
3513 std::string Server::getModStoragePath() const
3515 return m_path_world + DIR_DELIM + "mod_storage";
3518 v3f Server::findSpawnPos()
3520 ServerMap &map = m_env->getServerMap();
3522 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3523 return nodeposf * BS;
3526 bool is_good = false;
3528 // Try to find a good place a few times
3529 for(s32 i = 0; i < 4000 && !is_good; i++) {
3531 // We're going to try to throw the player to this position
3532 v2s16 nodepos2d = v2s16(
3533 -range + (myrand() % (range * 2)),
3534 -range + (myrand() % (range * 2)));
3536 // Get spawn level at point
3537 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3538 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3539 // the mapgen to signify an unsuitable spawn position
3540 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3543 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3546 for (s32 i = 0; i < 10; i++) {
3547 v3s16 blockpos = getNodeBlockPos(nodepos);
3548 map.emergeBlock(blockpos, true);
3549 content_t c = map.getNodeNoEx(nodepos).getContent();
3550 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3552 if (air_count >= 2) {
3553 nodeposf = intToFloat(nodepos, BS);
3554 // Don't spawn the player outside map boundaries
3555 if (objectpos_over_limit(nodeposf))
3568 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3570 m_shutdown_timer = delay;
3571 m_shutdown_msg = msg;
3572 m_shutdown_ask_reconnect = reconnect;
3574 if (delay == 0.0f) {
3575 // No delay, shutdown immediately
3576 m_shutdown_requested = true;
3577 // only print to the infostream, a chat message saying
3578 // "Server Shutting Down" is sent when the server destructs.
3579 infostream << "*** Immediate Server shutdown requested." << std::endl;
3580 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3581 // Negative delay, cancel shutdown if requested
3582 m_shutdown_timer = 0.0f;
3583 m_shutdown_msg = "";
3584 m_shutdown_ask_reconnect = false;
3585 m_shutdown_requested = false;
3586 std::wstringstream ws;
3588 ws << L"*** Server shutdown canceled.";
3590 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3591 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3592 } else if (delay > 0.0f) {
3593 // Positive delay, tell the clients when the server will shut down
3594 std::wstringstream ws;
3596 ws << L"*** Server shutting down in "
3597 << duration_to_string(myround(m_shutdown_timer)).c_str()
3600 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3601 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3605 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3608 Try to get an existing player
3610 RemotePlayer *player = m_env->getPlayer(name);
3612 // If player is already connected, cancel
3613 if (player != NULL && player->peer_id != 0) {
3614 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3619 If player with the wanted peer_id already exists, cancel.
3621 if (m_env->getPlayer(peer_id) != NULL) {
3622 infostream<<"emergePlayer(): Player with wrong name but same"
3623 " peer_id already exists"<<std::endl;
3628 player = new RemotePlayer(name, idef());
3631 bool newplayer = false;
3634 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3636 // Complete init with server parts
3637 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3638 player->protocol_version = proto_version;
3642 m_script->on_newplayer(playersao);
3648 bool Server::registerModStorage(ModMetadata *storage)
3650 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3651 errorstream << "Unable to register same mod storage twice. Storage name: "
3652 << storage->getModName() << std::endl;
3656 m_mod_storages[storage->getModName()] = storage;
3660 void Server::unregisterModStorage(const std::string &name)
3662 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3663 if (it != m_mod_storages.end()) {
3664 // Save unconditionaly on unregistration
3665 it->second->save(getModStoragePath());
3666 m_mod_storages.erase(name);
3670 void dedicated_server_loop(Server &server, bool &kill)
3672 DSTACK(FUNCTION_NAME);
3674 verbosestream<<"dedicated_server_loop()"<<std::endl;
3676 IntervalLimiter m_profiler_interval;
3678 static const float steplen = g_settings->getFloat("dedicated_server_step");
3679 static const float profiler_print_interval =
3680 g_settings->getFloat("profiler_print_interval");
3683 // This is kind of a hack but can be done like this
3684 // because server.step() is very light
3686 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3687 sleep_ms((int)(steplen*1000.0));
3689 server.step(steplen);
3691 if (server.getShutdownRequested() || kill)
3697 if (profiler_print_interval != 0) {
3698 if(m_profiler_interval.step(steplen, profiler_print_interval))
3700 infostream<<"Profiler:"<<std::endl;
3701 g_profiler->print(infostream);
3702 g_profiler->clear();
3707 infostream << "Dedicated server quitting" << std::endl;
3709 if (g_settings->getBool("server_announce"))
3710 ServerList::sendAnnounce(ServerList::AA_DELETE,
3711 server.m_bind_addr.getPort());