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)
1876 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1877 pkt << bgcolor << type << (u16) params.size();
1879 for(size_t i=0; i<params.size(); i++)
1885 void Server::SendCloudParams(u16 peer_id, float density,
1886 const video::SColor &color_bright,
1887 const video::SColor &color_ambient,
1892 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1893 pkt << density << color_bright << color_ambient
1894 << height << thickness << speed;
1899 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1902 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1905 pkt << do_override << (u16) (ratio * 65535);
1910 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1912 DSTACK(FUNCTION_NAME);
1914 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1915 pkt << time << time_speed;
1917 if (peer_id == PEER_ID_INEXISTENT) {
1918 m_clients.sendToAll(&pkt);
1925 void Server::SendPlayerHP(u16 peer_id)
1927 DSTACK(FUNCTION_NAME);
1928 PlayerSAO *playersao = getPlayerSAO(peer_id);
1929 // In some rare case if the player is disconnected
1930 // while Lua call l_punch, for example, this can be NULL
1934 SendHP(peer_id, playersao->getHP());
1935 m_script->player_event(playersao,"health_changed");
1937 // Send to other clients
1938 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1939 ActiveObjectMessage aom(playersao->getId(), true, str);
1940 playersao->m_messages_out.push(aom);
1943 void Server::SendPlayerBreath(PlayerSAO *sao)
1945 DSTACK(FUNCTION_NAME);
1948 m_script->player_event(sao, "breath_changed");
1949 SendBreath(sao->getPeerID(), sao->getBreath());
1952 void Server::SendMovePlayer(u16 peer_id)
1954 DSTACK(FUNCTION_NAME);
1955 RemotePlayer *player = m_env->getPlayer(peer_id);
1957 PlayerSAO *sao = player->getPlayerSAO();
1960 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1961 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1964 v3f pos = sao->getBasePosition();
1965 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1966 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1967 << " pitch=" << sao->getPitch()
1968 << " yaw=" << sao->getYaw()
1975 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1977 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1980 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1981 << animation_frames[3] << animation_speed;
1986 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1988 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1989 pkt << first << third;
1992 void Server::SendPlayerPrivileges(u16 peer_id)
1994 RemotePlayer *player = m_env->getPlayer(peer_id);
1996 if(player->peer_id == PEER_ID_INEXISTENT)
1999 std::set<std::string> privs;
2000 m_script->getAuth(player->getName(), NULL, &privs);
2002 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
2003 pkt << (u16) privs.size();
2005 for(std::set<std::string>::const_iterator i = privs.begin();
2006 i != privs.end(); ++i) {
2013 void Server::SendPlayerInventoryFormspec(u16 peer_id)
2015 RemotePlayer *player = m_env->getPlayer(peer_id);
2017 if(player->peer_id == PEER_ID_INEXISTENT)
2020 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
2021 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
2025 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
2027 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
2028 pkt.putRawString(datas.c_str(), datas.size());
2030 return pkt.getSize();
2033 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
2035 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2036 datas.size(), peer_id);
2038 pkt.putRawString(datas.c_str(), datas.size());
2040 m_clients.send(pkt.getPeerId(),
2041 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2046 s32 Server::playSound(const SimpleSoundSpec &spec,
2047 const ServerSoundParams ¶ms)
2049 // Find out initial position of sound
2050 bool pos_exists = false;
2051 v3f pos = params.getPos(m_env, &pos_exists);
2052 // If position is not found while it should be, cancel sound
2053 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2056 // Filter destination clients
2057 std::vector<u16> dst_clients;
2058 if(params.to_player != "")
2060 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2062 infostream<<"Server::playSound: Player \""<<params.to_player
2063 <<"\" not found"<<std::endl;
2066 if(player->peer_id == PEER_ID_INEXISTENT){
2067 infostream<<"Server::playSound: Player \""<<params.to_player
2068 <<"\" not connected"<<std::endl;
2071 dst_clients.push_back(player->peer_id);
2074 std::vector<u16> clients = m_clients.getClientIDs();
2076 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2077 RemotePlayer *player = m_env->getPlayer(*i);
2081 PlayerSAO *sao = player->getPlayerSAO();
2086 if(sao->getBasePosition().getDistanceFrom(pos) >
2087 params.max_hear_distance)
2090 dst_clients.push_back(*i);
2094 if(dst_clients.empty())
2098 s32 id = m_next_sound_id++;
2099 // The sound will exist as a reference in m_playing_sounds
2100 m_playing_sounds[id] = ServerPlayingSound();
2101 ServerPlayingSound &psound = m_playing_sounds[id];
2102 psound.params = params;
2105 float gain = params.gain * spec.gain;
2106 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2107 pkt << id << spec.name << gain
2108 << (u8) params.type << pos << params.object
2109 << params.loop << params.fade;
2111 // Backwards compability
2112 bool play_sound = gain > 0;
2114 for (std::vector<u16>::iterator i = dst_clients.begin();
2115 i != dst_clients.end(); ++i) {
2116 if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2117 psound.clients.insert(*i);
2118 m_clients.send(*i, 0, &pkt, true);
2123 void Server::stopSound(s32 handle)
2125 // Get sound reference
2126 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(handle);
2127 if (i == m_playing_sounds.end())
2129 ServerPlayingSound &psound = i->second;
2131 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2134 for (UNORDERED_SET<u16>::iterator i = psound.clients.begin();
2135 i != psound.clients.end(); ++i) {
2137 m_clients.send(*i, 0, &pkt, true);
2139 // Remove sound reference
2140 m_playing_sounds.erase(i);
2143 void Server::fadeSound(s32 handle, float step, float gain)
2145 // Get sound reference
2146 UNORDERED_MAP<s32, ServerPlayingSound>::iterator i =
2147 m_playing_sounds.find(handle);
2148 if (i == m_playing_sounds.end())
2151 ServerPlayingSound &psound = i->second;
2152 psound.params.gain = gain;
2154 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2155 pkt << handle << step << gain;
2157 // Backwards compability
2158 bool play_sound = gain > 0;
2159 ServerPlayingSound compat_psound = psound;
2160 compat_psound.clients.clear();
2162 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2163 compat_pkt << handle;
2165 for (UNORDERED_SET<u16>::iterator it = psound.clients.begin();
2166 it != psound.clients.end();) {
2167 if (m_clients.getProtocolVersion(*it) >= 32) {
2169 m_clients.send(*it, 0, &pkt, true);
2172 compat_psound.clients.insert(*it);
2174 m_clients.send(*it, 0, &compat_pkt, true);
2175 psound.clients.erase(it++);
2179 // Remove sound reference
2180 if (!play_sound || psound.clients.size() == 0)
2181 m_playing_sounds.erase(i);
2183 if (play_sound && compat_psound.clients.size() > 0) {
2184 // Play new sound volume on older clients
2185 playSound(compat_psound.spec, compat_psound.params);
2189 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2190 std::vector<u16> *far_players, float far_d_nodes)
2192 float maxd = far_d_nodes*BS;
2193 v3f p_f = intToFloat(p, BS);
2195 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2198 std::vector<u16> clients = m_clients.getClientIDs();
2199 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2202 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2203 PlayerSAO *sao = player->getPlayerSAO();
2207 // If player is far away, only set modified blocks not sent
2208 v3f player_pos = sao->getBasePosition();
2209 if (player_pos.getDistanceFrom(p_f) > maxd) {
2210 far_players->push_back(*i);
2217 m_clients.send(*i, 0, &pkt, true);
2221 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2222 std::vector<u16> *far_players, float far_d_nodes,
2223 bool remove_metadata)
2225 float maxd = far_d_nodes*BS;
2226 v3f p_f = intToFloat(p, BS);
2228 std::vector<u16> clients = m_clients.getClientIDs();
2229 for(std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
2232 if (RemotePlayer *player = m_env->getPlayer(*i)) {
2233 PlayerSAO *sao = player->getPlayerSAO();
2237 // If player is far away, only set modified blocks not sent
2238 v3f player_pos = sao->getBasePosition();
2239 if(player_pos.getDistanceFrom(p_f) > maxd) {
2240 far_players->push_back(*i);
2246 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2248 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2250 pkt << p << n.param0 << n.param1 << n.param2
2251 << (u8) (remove_metadata ? 0 : 1);
2256 if (pkt.getSize() > 0)
2257 m_clients.send(*i, 0, &pkt, true);
2261 void Server::setBlockNotSent(v3s16 p)
2263 std::vector<u16> clients = m_clients.getClientIDs();
2265 for(std::vector<u16>::iterator i = clients.begin();
2266 i != clients.end(); ++i) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2268 client->SetBlockNotSent(p);
2273 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2275 DSTACK(FUNCTION_NAME);
2277 v3s16 p = block->getPos();
2280 Create a packet with the block in the right format
2283 std::ostringstream os(std::ios_base::binary);
2284 block->serialize(os, ver, false);
2285 block->serializeNetworkSpecific(os);
2286 std::string s = os.str();
2288 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2291 pkt.putRawString(s.c_str(), s.size());
2295 void Server::SendBlocks(float dtime)
2297 DSTACK(FUNCTION_NAME);
2299 MutexAutoLock envlock(m_env_mutex);
2300 //TODO check if one big lock could be faster then multiple small ones
2302 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2304 std::vector<PrioritySortedBlockTransfer> queue;
2306 s32 total_sending = 0;
2309 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2311 std::vector<u16> clients = m_clients.getClientIDs();
2314 for(std::vector<u16>::iterator i = clients.begin();
2315 i != clients.end(); ++i) {
2316 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2321 total_sending += client->SendingCount();
2322 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2328 // Lowest priority number comes first.
2329 // Lowest is most important.
2330 std::sort(queue.begin(), queue.end());
2333 for(u32 i=0; i<queue.size(); i++)
2335 //TODO: Calculate limit dynamically
2336 if(total_sending >= g_settings->getS32
2337 ("max_simultaneous_block_sends_server_total"))
2340 PrioritySortedBlockTransfer q = queue[i];
2342 MapBlock *block = NULL;
2345 block = m_env->getMap().getBlockNoCreate(q.pos);
2347 catch(InvalidPositionException &e)
2352 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2357 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2359 client->SentBlock(q.pos);
2365 void Server::fillMediaCache()
2367 DSTACK(FUNCTION_NAME);
2369 infostream<<"Server: Calculating media file checksums"<<std::endl;
2371 // Collect all media file paths
2372 std::vector<std::string> paths;
2373 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2374 i != m_mods.end(); ++i) {
2375 const ModSpec &mod = *i;
2376 paths.push_back(mod.path + DIR_DELIM + "textures");
2377 paths.push_back(mod.path + DIR_DELIM + "sounds");
2378 paths.push_back(mod.path + DIR_DELIM + "media");
2379 paths.push_back(mod.path + DIR_DELIM + "models");
2381 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2383 // Collect media file information from paths into cache
2384 for(std::vector<std::string>::iterator i = paths.begin();
2385 i != paths.end(); ++i) {
2386 std::string mediapath = *i;
2387 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2388 for (u32 j = 0; j < dirlist.size(); j++) {
2389 if (dirlist[j].dir) // Ignode dirs
2391 std::string filename = dirlist[j].name;
2392 // If name contains illegal characters, ignore the file
2393 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2394 infostream<<"Server: ignoring illegal file name: \""
2395 << filename << "\"" << std::endl;
2398 // If name is not in a supported format, ignore it
2399 const char *supported_ext[] = {
2400 ".png", ".jpg", ".bmp", ".tga",
2401 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2403 ".x", ".b3d", ".md2", ".obj",
2406 if (removeStringEnd(filename, supported_ext) == ""){
2407 infostream << "Server: ignoring unsupported file extension: \""
2408 << filename << "\"" << std::endl;
2411 // Ok, attempt to load the file and add to cache
2412 std::string filepath = mediapath + DIR_DELIM + filename;
2414 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2416 errorstream << "Server::fillMediaCache(): Could not open \""
2417 << filename << "\" for reading" << std::endl;
2420 std::ostringstream tmp_os(std::ios_base::binary);
2424 fis.read(buf, 1024);
2425 std::streamsize len = fis.gcount();
2426 tmp_os.write(buf, len);
2435 errorstream<<"Server::fillMediaCache(): Failed to read \""
2436 << filename << "\"" << std::endl;
2439 if(tmp_os.str().length() == 0) {
2440 errorstream << "Server::fillMediaCache(): Empty file \""
2441 << filepath << "\"" << std::endl;
2446 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2448 unsigned char *digest = sha1.getDigest();
2449 std::string sha1_base64 = base64_encode(digest, 20);
2450 std::string sha1_hex = hex_encode((char*)digest, 20);
2454 m_media[filename] = MediaInfo(filepath, sha1_base64);
2455 verbosestream << "Server: " << sha1_hex << " is " << filename
2461 void Server::sendMediaAnnouncement(u16 peer_id)
2463 DSTACK(FUNCTION_NAME);
2465 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2469 std::ostringstream os(std::ios_base::binary);
2471 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2472 pkt << (u16) m_media.size();
2474 for (UNORDERED_MAP<std::string, MediaInfo>::iterator i = m_media.begin();
2475 i != m_media.end(); ++i) {
2476 pkt << i->first << i->second.sha1_digest;
2479 pkt << g_settings->get("remote_media");
2483 struct SendableMedia
2489 SendableMedia(const std::string &name_="", const std::string &path_="",
2490 const std::string &data_=""):
2497 void Server::sendRequestedMedia(u16 peer_id,
2498 const std::vector<std::string> &tosend)
2500 DSTACK(FUNCTION_NAME);
2502 verbosestream<<"Server::sendRequestedMedia(): "
2503 <<"Sending files to client"<<std::endl;
2507 // Put 5kB in one bunch (this is not accurate)
2508 u32 bytes_per_bunch = 5000;
2510 std::vector< std::vector<SendableMedia> > file_bunches;
2511 file_bunches.push_back(std::vector<SendableMedia>());
2513 u32 file_size_bunch_total = 0;
2515 for(std::vector<std::string>::const_iterator i = tosend.begin();
2516 i != tosend.end(); ++i) {
2517 const std::string &name = *i;
2519 if (m_media.find(name) == m_media.end()) {
2520 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2521 <<"unknown file \""<<(name)<<"\""<<std::endl;
2525 //TODO get path + name
2526 std::string tpath = m_media[name].path;
2529 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2530 if(fis.good() == false){
2531 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2532 <<tpath<<"\" for reading"<<std::endl;
2535 std::ostringstream tmp_os(std::ios_base::binary);
2539 fis.read(buf, 1024);
2540 std::streamsize len = fis.gcount();
2541 tmp_os.write(buf, len);
2542 file_size_bunch_total += len;
2551 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2552 <<name<<"\""<<std::endl;
2555 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2556 <<tname<<"\""<<std::endl;*/
2558 file_bunches[file_bunches.size()-1].push_back(
2559 SendableMedia(name, tpath, tmp_os.str()));
2561 // Start next bunch if got enough data
2562 if(file_size_bunch_total >= bytes_per_bunch) {
2563 file_bunches.push_back(std::vector<SendableMedia>());
2564 file_size_bunch_total = 0;
2569 /* Create and send packets */
2571 u16 num_bunches = file_bunches.size();
2572 for(u16 i = 0; i < num_bunches; i++) {
2575 u16 total number of texture bunches
2576 u16 index of this bunch
2577 u32 number of files in this bunch
2586 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2587 pkt << num_bunches << i << (u32) file_bunches[i].size();
2589 for(std::vector<SendableMedia>::iterator
2590 j = file_bunches[i].begin();
2591 j != file_bunches[i].end(); ++j) {
2593 pkt.putLongString(j->data);
2596 verbosestream << "Server::sendRequestedMedia(): bunch "
2597 << i << "/" << num_bunches
2598 << " files=" << file_bunches[i].size()
2599 << " size=" << pkt.getSize() << std::endl;
2604 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2606 if(m_detached_inventories.count(name) == 0) {
2607 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2610 Inventory *inv = m_detached_inventories[name];
2611 std::ostringstream os(std::ios_base::binary);
2613 os << serializeString(name);
2617 std::string s = os.str();
2619 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2620 pkt.putRawString(s.c_str(), s.size());
2622 const std::string &check = m_detached_inventories_player[name];
2623 if (peer_id == PEER_ID_INEXISTENT) {
2625 return m_clients.sendToAll(&pkt);
2626 RemotePlayer *p = m_env->getPlayer(check.c_str());
2628 m_clients.send(p->peer_id, 0, &pkt, true);
2630 if (check == "" || getPlayerName(peer_id) == check)
2635 void Server::sendDetachedInventories(u16 peer_id)
2637 DSTACK(FUNCTION_NAME);
2639 for(std::map<std::string, Inventory*>::iterator
2640 i = m_detached_inventories.begin();
2641 i != m_detached_inventories.end(); ++i) {
2642 const std::string &name = i->first;
2643 //Inventory *inv = i->second;
2644 sendDetachedInventory(name, peer_id);
2652 void Server::DiePlayer(u16 peer_id)
2654 DSTACK(FUNCTION_NAME);
2655 PlayerSAO *playersao = getPlayerSAO(peer_id);
2656 // In some rare cases this can be NULL -- if the player is disconnected
2657 // when a Lua function modifies l_punch, for example
2661 infostream << "Server::DiePlayer(): Player "
2662 << playersao->getPlayer()->getName()
2663 << " dies" << std::endl;
2665 playersao->setHP(0);
2667 // Trigger scripted stuff
2668 m_script->on_dieplayer(playersao);
2670 SendPlayerHP(peer_id);
2671 SendDeathscreen(peer_id, false, v3f(0,0,0));
2674 void Server::RespawnPlayer(u16 peer_id)
2676 DSTACK(FUNCTION_NAME);
2678 PlayerSAO *playersao = getPlayerSAO(peer_id);
2681 infostream << "Server::RespawnPlayer(): Player "
2682 << playersao->getPlayer()->getName()
2683 << " respawns" << std::endl;
2685 playersao->setHP(PLAYER_MAX_HP);
2686 playersao->setBreath(PLAYER_MAX_BREATH);
2688 bool repositioned = m_script->on_respawnplayer(playersao);
2689 if (!repositioned) {
2690 // setPos will send the new position to client
2691 playersao->setPos(findSpawnPos());
2694 SendPlayerHP(peer_id);
2698 void Server::DenySudoAccess(u16 peer_id)
2700 DSTACK(FUNCTION_NAME);
2702 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2707 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2708 const std::string &str_reason, bool reconnect)
2710 if (proto_ver >= 25) {
2711 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2713 std::wstring wreason = utf8_to_wide(
2714 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2715 accessDeniedStrings[(u8)reason]);
2716 SendAccessDenied_Legacy(peer_id, wreason);
2719 m_clients.event(peer_id, CSE_SetDenied);
2720 m_con.DisconnectPeer(peer_id);
2724 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2726 DSTACK(FUNCTION_NAME);
2728 SendAccessDenied(peer_id, reason, custom_reason);
2729 m_clients.event(peer_id, CSE_SetDenied);
2730 m_con.DisconnectPeer(peer_id);
2733 // 13/03/15: remove this function when protocol version 25 will become
2734 // the minimum version for MT users, maybe in 1 year
2735 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2737 DSTACK(FUNCTION_NAME);
2739 SendAccessDenied_Legacy(peer_id, reason);
2740 m_clients.event(peer_id, CSE_SetDenied);
2741 m_con.DisconnectPeer(peer_id);
2744 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2746 DSTACK(FUNCTION_NAME);
2749 RemoteClient* client = getClient(peer_id, CS_Invalid);
2751 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2753 // Right now, the auth mechs don't change between login and sudo mode.
2754 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2755 client->allowed_sudo_mechs = sudo_auth_mechs;
2757 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2758 << g_settings->getFloat("dedicated_server_step")
2762 m_clients.event(peer_id, CSE_AuthAccept);
2764 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2766 // We only support SRP right now
2767 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2769 resp_pkt << sudo_auth_mechs;
2771 m_clients.event(peer_id, CSE_SudoSuccess);
2775 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2777 DSTACK(FUNCTION_NAME);
2778 std::wstring message;
2781 Clear references to playing sounds
2783 for (UNORDERED_MAP<s32, ServerPlayingSound>::iterator
2784 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2785 ServerPlayingSound &psound = i->second;
2786 psound.clients.erase(peer_id);
2787 if (psound.clients.empty())
2788 m_playing_sounds.erase(i++);
2793 RemotePlayer *player = m_env->getPlayer(peer_id);
2795 /* Run scripts and remove from environment */
2796 if (player != NULL) {
2797 PlayerSAO *playersao = player->getPlayerSAO();
2800 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2802 playersao->disconnected();
2809 if(player != NULL && reason != CDR_DENY) {
2810 std::ostringstream os(std::ios_base::binary);
2811 std::vector<u16> clients = m_clients.getClientIDs();
2813 for(std::vector<u16>::iterator i = clients.begin();
2814 i != clients.end(); ++i) {
2816 RemotePlayer *player = m_env->getPlayer(*i);
2820 // Get name of player
2821 os << player->getName() << " ";
2824 std::string name = player->getName();
2825 actionstream << name << " "
2826 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2827 << " List of players: " << os.str() << std::endl;
2829 m_admin_chat->outgoing_queue.push_back(
2830 new ChatEventNick(CET_NICK_REMOVE, name));
2834 MutexAutoLock env_lock(m_env_mutex);
2835 m_clients.DeleteClient(peer_id);
2839 // Send leave chat message to all remaining clients
2840 if(message.length() != 0)
2841 SendChatMessage(PEER_ID_INEXISTENT,message);
2844 void Server::UpdateCrafting(RemotePlayer *player)
2846 DSTACK(FUNCTION_NAME);
2848 // Get a preview for crafting
2850 InventoryLocation loc;
2851 loc.setPlayer(player->getName());
2852 std::vector<ItemStack> output_replacements;
2853 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2854 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2855 (&player->inventory)->getList("craft"), loc);
2857 // Put the new preview in
2858 InventoryList *plist = player->inventory.getList("craftpreview");
2859 sanity_check(plist);
2860 sanity_check(plist->getSize() >= 1);
2861 plist->changeItem(0, preview);
2864 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2866 if (evt->type == CET_NICK_ADD) {
2867 // The terminal informed us of its nick choice
2868 m_admin_nick = ((ChatEventNick *)evt)->nick;
2869 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2870 errorstream << "You haven't set up an account." << std::endl
2871 << "Please log in using the client as '"
2872 << m_admin_nick << "' with a secure password." << std::endl
2873 << "Until then, you can't execute admin tasks via the console," << std::endl
2874 << "and everybody can claim the user account instead of you," << std::endl
2875 << "giving them full control over this server." << std::endl;
2878 assert(evt->type == CET_CHAT);
2879 handleAdminChat((ChatEventChat *)evt);
2883 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2884 const std::wstring &wmessage, bool check_shout_priv, RemotePlayer *player)
2886 // If something goes wrong, this player is to blame
2887 RollbackScopeActor rollback_scope(m_rollback,
2888 std::string("player:") + name);
2891 switch (player->canSendChatMessage()) {
2892 case RPLAYER_CHATRESULT_FLOODING: {
2893 std::wstringstream ws;
2894 ws << L"You cannot send more messages. You are limited to "
2895 << g_settings->getFloat("chat_message_limit_per_10sec")
2896 << L" messages per 10 seconds.";
2899 case RPLAYER_CHATRESULT_KICK:
2900 DenyAccess_Legacy(player->peer_id,
2901 L"You have been kicked due to message flooding.");
2903 case RPLAYER_CHATRESULT_OK:
2906 FATAL_ERROR("Unhandled chat filtering result found.");
2910 if (m_max_chatmessage_length > 0
2911 && wmessage.length() > m_max_chatmessage_length) {
2912 return L"Your message exceed the maximum chat message limit set on the server. "
2913 L"It was refused. Send a shorter message";
2916 // Run script hook, exit if script ate the chat message
2917 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2922 // Whether to send line to the player that sent the message, or to all players
2923 bool broadcast_line = true;
2925 if (check_shout_priv && !checkPriv(name, "shout")) {
2926 line += L"-!- You don't have permission to shout.";
2927 broadcast_line = false;
2936 Tell calling method to send the message to sender
2938 if (!broadcast_line) {
2942 Send the message to others
2944 actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
2946 std::vector<u16> clients = m_clients.getClientIDs();
2949 Send the message back to the inital sender
2950 if they are using protocol version >= 29
2953 u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
2954 if (player && player->protocol_version >= 29)
2955 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2957 for (u16 i = 0; i < clients.size(); i++) {
2958 u16 cid = clients[i];
2959 if (cid != peer_id_to_avoid_sending)
2960 SendChatMessage(cid, line);
2966 void Server::handleAdminChat(const ChatEventChat *evt)
2968 std::string name = evt->nick;
2969 std::wstring wname = utf8_to_wide(name);
2970 std::wstring wmessage = evt->evt_msg;
2972 std::wstring answer = handleChat(name, wname, wmessage);
2974 // If asked to send answer to sender
2975 if (!answer.empty()) {
2976 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2980 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2982 RemoteClient *client = getClientNoEx(peer_id,state_min);
2984 throw ClientNotFoundException("Client not found");
2988 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2990 return m_clients.getClientNoEx(peer_id, state_min);
2993 std::string Server::getPlayerName(u16 peer_id)
2995 RemotePlayer *player = m_env->getPlayer(peer_id);
2997 return "[id="+itos(peer_id)+"]";
2998 return player->getName();
3001 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
3003 RemotePlayer *player = m_env->getPlayer(peer_id);
3006 return player->getPlayerSAO();
3009 std::wstring Server::getStatusString()
3011 std::wostringstream os(std::ios_base::binary);
3014 os<<L"version="<<narrow_to_wide(g_version_string);
3016 os<<L", uptime="<<m_uptime.get();
3018 os<<L", max_lag="<<m_env->getMaxLagEstimate();
3019 // Information about clients
3022 std::vector<u16> clients = m_clients.getClientIDs();
3023 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
3025 RemotePlayer *player = m_env->getPlayer(*i);
3026 // Get name of player
3027 std::wstring name = L"unknown";
3029 name = narrow_to_wide(player->getName());
3030 // Add name to information string
3038 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
3039 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
3040 if(g_settings->get("motd") != "")
3041 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
3045 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3047 std::set<std::string> privs;
3048 m_script->getAuth(name, NULL, &privs);
3052 bool Server::checkPriv(const std::string &name, const std::string &priv)
3054 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3055 return (privs.count(priv) != 0);
3058 void Server::reportPrivsModified(const std::string &name)
3061 std::vector<u16> clients = m_clients.getClientIDs();
3062 for(std::vector<u16>::iterator i = clients.begin();
3063 i != clients.end(); ++i) {
3064 RemotePlayer *player = m_env->getPlayer(*i);
3065 reportPrivsModified(player->getName());
3068 RemotePlayer *player = m_env->getPlayer(name.c_str());
3071 SendPlayerPrivileges(player->peer_id);
3072 PlayerSAO *sao = player->getPlayerSAO();
3075 sao->updatePrivileges(
3076 getPlayerEffectivePrivs(name),
3081 void Server::reportInventoryFormspecModified(const std::string &name)
3083 RemotePlayer *player = m_env->getPlayer(name.c_str());
3086 SendPlayerInventoryFormspec(player->peer_id);
3089 void Server::setIpBanned(const std::string &ip, const std::string &name)
3091 m_banmanager->add(ip, name);
3094 void Server::unsetIpBanned(const std::string &ip_or_name)
3096 m_banmanager->remove(ip_or_name);
3099 std::string Server::getBanDescription(const std::string &ip_or_name)
3101 return m_banmanager->getBanDescription(ip_or_name);
3104 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3106 // m_env will be NULL if the server is initializing
3110 if (m_admin_nick == name && !m_admin_nick.empty()) {
3111 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3114 RemotePlayer *player = m_env->getPlayer(name);
3119 if (player->peer_id == PEER_ID_INEXISTENT)
3122 SendChatMessage(player->peer_id, msg);
3125 bool Server::showFormspec(const char *playername, const std::string &formspec,
3126 const std::string &formname)
3128 // m_env will be NULL if the server is initializing
3132 RemotePlayer *player = m_env->getPlayer(playername);
3136 SendShowFormspecMessage(player->peer_id, formspec, formname);
3140 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3145 u32 id = player->addHud(form);
3147 SendHUDAdd(player->peer_id, id, form);
3152 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3156 HudElement* todel = player->removeHud(id);
3163 SendHUDRemove(player->peer_id, id);
3167 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3172 SendHUDChange(player->peer_id, id, stat, data);
3176 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3181 SendHUDSetFlags(player->peer_id, flags, mask);
3182 player->hud_flags &= ~mask;
3183 player->hud_flags |= flags;
3185 PlayerSAO* playersao = player->getPlayerSAO();
3187 if (playersao == NULL)
3190 m_script->player_event(playersao, "hud_changed");
3194 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3199 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3202 player->setHotbarItemcount(hotbar_itemcount);
3203 std::ostringstream os(std::ios::binary);
3204 writeS32(os, hotbar_itemcount);
3205 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3209 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3214 player->setHotbarImage(name);
3215 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
3218 std::string Server::hudGetHotbarImage(RemotePlayer *player)
3222 return player->getHotbarImage();
3225 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3230 player->setHotbarSelectedImage(name);
3231 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3234 bool Server::setLocalPlayerAnimations(RemotePlayer *player,
3235 v2s32 animation_frames[4], f32 frame_speed)
3240 player->setLocalAnimations(animation_frames, frame_speed);
3241 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3245 bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
3250 player->eye_offset_first = first;
3251 player->eye_offset_third = third;
3252 SendEyeOffset(player->peer_id, first, third);
3256 bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3257 const std::string &type, const std::vector<std::string> ¶ms)
3262 player->setSky(bgcolor, type, params);
3263 SendSetSky(player->peer_id, bgcolor, type, params);
3267 bool Server::setClouds(RemotePlayer *player, float density,
3268 const video::SColor &color_bright,
3269 const video::SColor &color_ambient,
3277 SendCloudParams(player->peer_id, density,
3278 color_bright, color_ambient, height,
3283 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3289 player->overrideDayNightRatio(do_override, ratio);
3290 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3294 void Server::notifyPlayers(const std::wstring &msg)
3296 SendChatMessage(PEER_ID_INEXISTENT,msg);
3299 void Server::spawnParticle(const std::string &playername, v3f pos,
3300 v3f velocity, v3f acceleration,
3301 float expirationtime, float size, bool
3302 collisiondetection, bool collision_removal,
3303 bool vertical, const std::string &texture,
3304 const struct TileAnimationParams &animation, u8 glow)
3306 // m_env will be NULL if the server is initializing
3310 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3311 if (playername != "") {
3312 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3315 peer_id = player->peer_id;
3316 proto_ver = player->protocol_version;
3319 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3320 expirationtime, size, collisiondetection,
3321 collision_removal, vertical, texture, animation, glow);
3324 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3325 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3326 float minexptime, float maxexptime, float minsize, float maxsize,
3327 bool collisiondetection, bool collision_removal,
3328 ServerActiveObject *attached, bool vertical, const std::string &texture,
3329 const std::string &playername, const struct TileAnimationParams &animation,
3332 // m_env will be NULL if the server is initializing
3336 u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
3337 if (playername != "") {
3338 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3341 peer_id = player->peer_id;
3342 proto_ver = player->protocol_version;
3345 u16 attached_id = attached ? attached->getId() : 0;
3348 if (attached_id == 0)
3349 id = m_env->addParticleSpawner(spawntime);
3351 id = m_env->addParticleSpawner(spawntime, attached_id);
3353 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3354 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3355 minexptime, maxexptime, minsize, maxsize,
3356 collisiondetection, collision_removal, attached_id, vertical,
3357 texture, id, animation, glow);
3362 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3364 // m_env will be NULL if the server is initializing
3366 throw ServerError("Can't delete particle spawners during initialisation!");
3368 u16 peer_id = PEER_ID_INEXISTENT;
3369 if (playername != "") {
3370 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3373 peer_id = player->peer_id;
3376 m_env->deleteParticleSpawner(id);
3377 SendDeleteParticleSpawner(peer_id, id);
3380 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3382 if(m_detached_inventories.count(name) > 0){
3383 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3384 delete m_detached_inventories[name];
3386 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3388 Inventory *inv = new Inventory(m_itemdef);
3390 m_detached_inventories[name] = inv;
3391 m_detached_inventories_player[name] = player;
3392 //TODO find a better way to do this
3393 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3397 // actions: time-reversed list
3398 // Return value: success/failure
3399 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3400 std::list<std::string> *log)
3402 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3403 ServerMap *map = (ServerMap*)(&m_env->getMap());
3405 // Fail if no actions to handle
3406 if(actions.empty()){
3407 log->push_back("Nothing to do.");
3414 for(std::list<RollbackAction>::const_iterator
3415 i = actions.begin();
3416 i != actions.end(); ++i)
3418 const RollbackAction &action = *i;
3420 bool success = action.applyRevert(map, this, this);
3423 std::ostringstream os;
3424 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3425 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3427 log->push_back(os.str());
3429 std::ostringstream os;
3430 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3431 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3433 log->push_back(os.str());
3437 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3438 <<" failed"<<std::endl;
3440 // Call it done if less than half failed
3441 return num_failed <= num_tried/2;
3444 // IGameDef interface
3446 IItemDefManager *Server::getItemDefManager()
3451 INodeDefManager *Server::getNodeDefManager()
3456 ICraftDefManager *Server::getCraftDefManager()
3461 u16 Server::allocateUnknownNodeId(const std::string &name)
3463 return m_nodedef->allocateDummy(name);
3466 MtEventManager *Server::getEventManager()
3471 IWritableItemDefManager *Server::getWritableItemDefManager()
3476 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3481 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3486 const ModSpec *Server::getModSpec(const std::string &modname) const
3488 std::vector<ModSpec>::const_iterator it;
3489 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3490 const ModSpec &mod = *it;
3491 if (mod.name == modname)
3497 void Server::getModNames(std::vector<std::string> &modlist)
3499 std::vector<ModSpec>::iterator it;
3500 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3501 modlist.push_back(it->name);
3504 std::string Server::getBuiltinLuaPath()
3506 return porting::path_share + DIR_DELIM + "builtin";
3509 std::string Server::getModStoragePath() const
3511 return m_path_world + DIR_DELIM + "mod_storage";
3514 v3f Server::findSpawnPos()
3516 ServerMap &map = m_env->getServerMap();
3518 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3519 return nodeposf * BS;
3522 bool is_good = false;
3524 // Try to find a good place a few times
3525 for(s32 i = 0; i < 4000 && !is_good; i++) {
3527 // We're going to try to throw the player to this position
3528 v2s16 nodepos2d = v2s16(
3529 -range + (myrand() % (range * 2)),
3530 -range + (myrand() % (range * 2)));
3532 // Get spawn level at point
3533 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3534 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3535 // the mapgen to signify an unsuitable spawn position
3536 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3539 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3542 for (s32 i = 0; i < 10; i++) {
3543 v3s16 blockpos = getNodeBlockPos(nodepos);
3544 map.emergeBlock(blockpos, true);
3545 content_t c = map.getNodeNoEx(nodepos).getContent();
3546 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3548 if (air_count >= 2) {
3549 nodeposf = intToFloat(nodepos, BS);
3550 // Don't spawn the player outside map boundaries
3551 if (objectpos_over_limit(nodeposf))
3564 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3566 m_shutdown_timer = delay;
3567 m_shutdown_msg = msg;
3568 m_shutdown_ask_reconnect = reconnect;
3570 if (delay == 0.0f) {
3571 // No delay, shutdown immediately
3572 m_shutdown_requested = true;
3573 // only print to the infostream, a chat message saying
3574 // "Server Shutting Down" is sent when the server destructs.
3575 infostream << "*** Immediate Server shutdown requested." << std::endl;
3576 } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
3577 // Negative delay, cancel shutdown if requested
3578 m_shutdown_timer = 0.0f;
3579 m_shutdown_msg = "";
3580 m_shutdown_ask_reconnect = false;
3581 m_shutdown_requested = false;
3582 std::wstringstream ws;
3584 ws << L"*** Server shutdown canceled.";
3586 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3587 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3588 } else if (delay > 0.0f) {
3589 // Positive delay, tell the clients when the server will shut down
3590 std::wstringstream ws;
3592 ws << L"*** Server shutting down in "
3593 << duration_to_string(myround(m_shutdown_timer)).c_str()
3596 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3597 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3601 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3604 Try to get an existing player
3606 RemotePlayer *player = m_env->getPlayer(name);
3608 // If player is already connected, cancel
3609 if (player != NULL && player->peer_id != 0) {
3610 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3615 If player with the wanted peer_id already exists, cancel.
3617 if (m_env->getPlayer(peer_id) != NULL) {
3618 infostream<<"emergePlayer(): Player with wrong name but same"
3619 " peer_id already exists"<<std::endl;
3624 player = new RemotePlayer(name, idef());
3627 bool newplayer = false;
3630 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3632 // Complete init with server parts
3633 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3634 player->protocol_version = proto_version;
3638 m_script->on_newplayer(playersao);
3644 bool Server::registerModStorage(ModMetadata *storage)
3646 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3647 errorstream << "Unable to register same mod storage twice. Storage name: "
3648 << storage->getModName() << std::endl;
3652 m_mod_storages[storage->getModName()] = storage;
3656 void Server::unregisterModStorage(const std::string &name)
3658 UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3659 if (it != m_mod_storages.end()) {
3660 // Save unconditionaly on unregistration
3661 it->second->save(getModStoragePath());
3662 m_mod_storages.erase(name);
3666 void dedicated_server_loop(Server &server, bool &kill)
3668 DSTACK(FUNCTION_NAME);
3670 verbosestream<<"dedicated_server_loop()"<<std::endl;
3672 IntervalLimiter m_profiler_interval;
3674 static const float steplen = g_settings->getFloat("dedicated_server_step");
3675 static const float profiler_print_interval =
3676 g_settings->getFloat("profiler_print_interval");
3679 // This is kind of a hack but can be done like this
3680 // because server.step() is very light
3682 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3683 sleep_ms((int)(steplen*1000.0));
3685 server.step(steplen);
3687 if (server.getShutdownRequested() || kill)
3693 if (profiler_print_interval != 0) {
3694 if(m_profiler_interval.step(steplen, profiler_print_interval))
3696 infostream<<"Profiler:"<<std::endl;
3697 g_profiler->print(infostream);
3698 g_profiler->clear();
3703 infostream << "Dedicated server quitting" << std::endl;
3705 if (g_settings->getBool("server_announce"))
3706 ServerList::sendAnnounce(ServerList::AA_DELETE,
3707 server.m_bind_addr.getPort());