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 "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public JThread
80 ServerThread(Server *server):
89 void *ServerThread::Thread()
91 log_register_thread("ServerThread");
93 DSTACK(__FUNCTION_NAME);
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
100 porting::setThreadName("ServerThread");
102 while (!StopRequested()) {
104 //TimeTaker timer("AsyncRunStep() + Receive()");
106 m_server->AsyncRunStep();
110 } catch (con::NoIncomingDataException &e) {
111 } catch (con::PeerNotFoundException &e) {
112 infostream<<"Server: PeerNotFoundException"<<std::endl;
113 } catch (ClientNotFoundException &e) {
114 } catch (con::ConnectionBindFailed &e) {
115 m_server->setAsyncFatalError(e.what());
116 } catch (LuaError &e) {
117 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
121 END_DEBUG_EXCEPTION_HANDLER(errorstream)
126 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
128 if(pos_exists) *pos_exists = false;
133 if(pos_exists) *pos_exists = true;
138 ServerActiveObject *sao = env->getActiveObject(object);
141 if(pos_exists) *pos_exists = true;
142 return sao->getBasePosition(); }
154 const std::string &path_world,
155 const SubgameSpec &gamespec,
156 bool simple_singleplayer_mode,
159 m_path_world(path_world),
160 m_gamespec(gamespec),
161 m_simple_singleplayer_mode(simple_singleplayer_mode),
162 m_async_fatal_error(""),
171 m_enable_rollback_recording(false),
174 m_itemdef(createItemDefManager()),
175 m_nodedef(createNodeDefManager()),
176 m_craftdef(createCraftDefManager()),
177 m_event(new EventManager()),
179 m_time_of_day_send_timer(0),
182 m_shutdown_requested(false),
183 m_shutdown_ask_reconnect(false),
184 m_ignore_map_edit_events(false),
185 m_ignore_map_edit_events_peer_id(0),
189 m_liquid_transform_timer = 0.0;
190 m_liquid_transform_every = 1.0;
191 m_print_info_timer = 0.0;
192 m_masterserver_timer = 0.0;
193 m_objectdata_timer = 0.0;
194 m_emergethread_trigger_timer = 0.0;
195 m_savemap_timer = 0.0;
198 m_lag = g_settings->getFloat("dedicated_server_step");
201 throw ServerError("Supplied empty world path");
203 if(!gamespec.isValid())
204 throw ServerError("Supplied invalid gamespec");
206 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
207 if(m_simple_singleplayer_mode)
208 infostream<<" in simple singleplayer mode"<<std::endl;
210 infostream<<std::endl;
211 infostream<<"- world: "<<m_path_world<<std::endl;
212 infostream<<"- game: "<<m_gamespec.path<<std::endl;
214 // Create world if it doesn't exist
215 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
216 throw ServerError("Failed to initialize world");
218 // Create server thread
219 m_thread = new ServerThread(this);
221 // Create emerge manager
222 m_emerge = new EmergeManager(this);
224 // Create ban manager
225 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
226 m_banmanager = new BanManager(ban_path);
228 ModConfiguration modconf(m_path_world);
229 m_mods = modconf.getMods();
230 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
231 // complain about mods with unsatisfied dependencies
232 if(!modconf.isConsistent()) {
233 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
234 it != unsatisfied_mods.end(); ++it) {
236 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
237 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
238 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
239 errorstream << " \"" << *dep_it << "\"";
240 errorstream << std::endl;
244 Settings worldmt_settings;
245 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
246 worldmt_settings.readConfigFile(worldmt.c_str());
247 std::vector<std::string> names = worldmt_settings.getNames();
248 std::set<std::string> load_mod_names;
249 for(std::vector<std::string>::iterator it = names.begin();
250 it != names.end(); ++it) {
251 std::string name = *it;
252 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
253 load_mod_names.insert(name.substr(9));
255 // complain about mods declared to be loaded, but not found
256 for(std::vector<ModSpec>::iterator it = m_mods.begin();
257 it != m_mods.end(); ++it)
258 load_mod_names.erase((*it).name);
259 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
260 it != unsatisfied_mods.end(); ++it)
261 load_mod_names.erase((*it).name);
262 if(!load_mod_names.empty()) {
263 errorstream << "The following mods could not be found:";
264 for(std::set<std::string>::iterator it = load_mod_names.begin();
265 it != load_mod_names.end(); ++it)
266 errorstream << " \"" << (*it) << "\"";
267 errorstream << std::endl;
271 JMutexAutoLock envlock(m_env_mutex);
273 // Load mapgen params from Settings
274 m_emerge->loadMapgenParams();
276 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
277 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
279 // Initialize scripting
280 infostream<<"Server: Initializing Lua"<<std::endl;
282 m_script = new GameScripting(this);
284 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
285 std::string error_msg;
287 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
288 throw ModError("Failed to load and run " + script_path
289 + "\nError from Lua:\n" + error_msg);
292 infostream << "Server: Loading mods: ";
293 for(std::vector<ModSpec>::iterator i = m_mods.begin();
294 i != m_mods.end(); i++) {
295 const ModSpec &mod = *i;
296 infostream << mod.name << " ";
298 infostream << std::endl;
299 // Load and run "mod" scripts
300 for (std::vector<ModSpec>::iterator i = m_mods.begin();
301 i != m_mods.end(); i++) {
302 const ModSpec &mod = *i;
303 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
304 std::ostringstream err;
305 err << "Error loading mod \"" << mod.name
306 << "\": mod_name does not follow naming conventions: "
307 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
308 errorstream << err.str().c_str();
309 throw ModError(err.str());
311 std::string script_path = mod.path + DIR_DELIM "init.lua";
312 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
313 << script_path << "\"]" << std::endl;
314 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
315 errorstream << "Server: Failed to load and run "
316 << script_path << std::endl;
317 throw ModError("Failed to load and run " + script_path
318 + "\nError from Lua:\n" + error_msg);
322 // Read Textures and calculate sha1 sums
325 // Apply item aliases in the node definition manager
326 m_nodedef->updateAliases(m_itemdef);
328 // Apply texture overrides from texturepack/override.txt
329 std::string texture_path = g_settings->get("texture_path");
330 if (texture_path != "" && fs::IsDir(texture_path))
331 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
333 m_nodedef->setNodeRegistrationStatus(true);
335 // Perform pending node name resolutions
336 m_nodedef->runNodeResolveCallbacks();
338 // init the recipe hashes to speed up crafting
339 m_craftdef->initHashes(this);
341 // Initialize Environment
342 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
344 m_clients.setEnv(m_env);
346 // Initialize mapgens
347 m_emerge->initMapgens();
349 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
350 if (m_enable_rollback_recording) {
351 // Create rollback manager
352 m_rollback = new RollbackManager(m_path_world, this);
355 // Give environment reference to scripting api
356 m_script->initializeEnvironment(m_env);
358 // Register us to receive map edit events
359 servermap->addEventReceiver(this);
361 // If file exists, load environment metadata
362 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
364 infostream<<"Server: Loading environment metadata"<<std::endl;
368 // Add some test ActiveBlockModifiers to environment
369 add_legacy_abms(m_env, m_nodedef);
371 m_liquid_transform_every = g_settings->getFloat("liquid_update");
376 infostream<<"Server destructing"<<std::endl;
378 // Send shutdown message
379 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
382 JMutexAutoLock envlock(m_env_mutex);
384 // Execute script shutdown hooks
385 m_script->on_shutdown();
387 infostream << "Server: Saving players" << std::endl;
388 m_env->saveLoadedPlayers();
390 infostream << "Server: Kicking players" << std::endl;
391 std::string kick_msg;
392 bool reconnect = false;
393 if (getShutdownRequested()) {
394 reconnect = m_shutdown_ask_reconnect;
395 kick_msg = m_shutdown_msg;
397 if (kick_msg == "") {
398 kick_msg = g_settings->get("kick_msg_shutdown");
400 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
401 kick_msg, reconnect);
403 infostream << "Server: Saving environment metadata" << std::endl;
411 // stop all emerge threads before deleting players that may have
412 // requested blocks to be emerged
413 m_emerge->stopThreads();
415 // Delete things in the reverse order of creation
418 // N.B. the EmergeManager should be deleted after the Environment since Map
419 // depends on EmergeManager to write its current params to the map meta
428 // Deinitialize scripting
429 infostream<<"Server: Deinitializing scripting"<<std::endl;
432 // Delete detached inventories
433 for (std::map<std::string, Inventory*>::iterator
434 i = m_detached_inventories.begin();
435 i != m_detached_inventories.end(); i++) {
440 void Server::start(Address bind_addr)
442 DSTACK(__FUNCTION_NAME);
444 m_bind_addr = bind_addr;
446 infostream<<"Starting server on "
447 << bind_addr.serializeString() <<"..."<<std::endl;
449 // Stop thread if already running
452 // Initialize connection
453 m_con.SetTimeoutMs(30);
454 m_con.Serve(bind_addr);
459 // ASCII art for the win!
461 <<" .__ __ __ "<<std::endl
462 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
463 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
464 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
465 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
466 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
467 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
468 actionstream<<"Server for gameid=\""<<m_gamespec.id
469 <<"\" listening on "<<bind_addr.serializeString()<<":"
470 <<bind_addr.getPort() << "."<<std::endl;
475 DSTACK(__FUNCTION_NAME);
477 infostream<<"Server: Stopping and waiting threads"<<std::endl;
479 // Stop threads (set run=false first so both start stopping)
481 //m_emergethread.setRun(false);
483 //m_emergethread.stop();
485 infostream<<"Server: Threads stopped"<<std::endl;
488 void Server::step(float dtime)
490 DSTACK(__FUNCTION_NAME);
495 JMutexAutoLock lock(m_step_dtime_mutex);
496 m_step_dtime += dtime;
498 // Throw if fatal error occurred in thread
499 std::string async_err = m_async_fatal_error.get();
500 if(async_err != "") {
501 if (m_simple_singleplayer_mode) {
502 throw ServerError(async_err);
505 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
506 g_settings->get("kick_msg_crash"),
507 g_settings->getBool("ask_reconnect_on_crash"));
508 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
509 << "Please fix the following error:" << std::endl
510 << async_err << std::endl;
511 FATAL_ERROR(async_err.c_str());
516 void Server::AsyncRunStep(bool initial_step)
518 DSTACK(__FUNCTION_NAME);
520 g_profiler->add("Server::AsyncRunStep (num)", 1);
524 JMutexAutoLock lock1(m_step_dtime_mutex);
525 dtime = m_step_dtime;
529 // Send blocks to clients
533 if((dtime < 0.001) && (initial_step == false))
536 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
538 //infostream<<"Server steps "<<dtime<<std::endl;
539 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
542 JMutexAutoLock lock1(m_step_dtime_mutex);
543 m_step_dtime -= dtime;
550 m_uptime.set(m_uptime.get() + dtime);
556 Update time of day and overall game time
558 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
561 Send to clients at constant intervals
564 m_time_of_day_send_timer -= dtime;
565 if(m_time_of_day_send_timer < 0.0) {
566 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
567 u16 time = m_env->getTimeOfDay();
568 float time_speed = g_settings->getFloat("time_speed");
569 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
573 JMutexAutoLock lock(m_env_mutex);
574 // Figure out and report maximum lag to environment
575 float max_lag = m_env->getMaxLagEstimate();
576 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
578 if(dtime > 0.1 && dtime > max_lag * 2.0)
579 infostream<<"Server: Maximum lag peaked to "<<dtime
583 m_env->reportMaxLagEstimate(max_lag);
585 ScopeProfiler sp(g_profiler, "SEnv step");
586 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
590 static const float map_timer_and_unload_dtime = 2.92;
591 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
593 JMutexAutoLock lock(m_env_mutex);
594 // Run Map's timers and unload unused data
595 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
596 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
597 g_settings->getFloat("server_unload_unused_data_timeout"),
605 /* Transform liquids */
606 m_liquid_transform_timer += dtime;
607 if(m_liquid_transform_timer >= m_liquid_transform_every)
609 m_liquid_transform_timer -= m_liquid_transform_every;
611 JMutexAutoLock lock(m_env_mutex);
613 ScopeProfiler sp(g_profiler, "Server: liquid transform");
615 std::map<v3s16, MapBlock*> modified_blocks;
616 m_env->getMap().transformLiquids(modified_blocks);
621 core::map<v3s16, MapBlock*> lighting_modified_blocks;
622 ServerMap &map = ((ServerMap&)m_env->getMap());
623 map.updateLighting(modified_blocks, lighting_modified_blocks);
625 // Add blocks modified by lighting to modified_blocks
626 for(core::map<v3s16, MapBlock*>::Iterator
627 i = lighting_modified_blocks.getIterator();
628 i.atEnd() == false; i++)
630 MapBlock *block = i.getNode()->getValue();
631 modified_blocks.insert(block->getPos(), block);
635 Set the modified blocks unsent for all the clients
637 if(!modified_blocks.empty())
639 SetBlocksNotSent(modified_blocks);
642 m_clients.step(dtime);
644 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
646 // send masterserver announce
648 float &counter = m_masterserver_timer;
649 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
650 g_settings->getBool("server_announce"))
652 ServerList::sendAnnounce(counter ? "update" : "start",
653 m_bind_addr.getPort(),
654 m_clients.getPlayerNames(),
656 m_env->getGameTime(),
659 m_emerge->params.mg_name,
668 Check added and deleted active objects
671 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
672 JMutexAutoLock envlock(m_env_mutex);
675 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
676 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
678 // Radius inside which objects are active
679 s16 radius = g_settings->getS16("active_object_send_range_blocks");
680 s16 player_radius = g_settings->getS16("player_transfer_distance");
682 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
683 !g_settings->getBool("unlimited_player_transfer_distance"))
684 player_radius = radius;
686 radius *= MAP_BLOCKSIZE;
687 player_radius *= MAP_BLOCKSIZE;
689 for(std::map<u16, RemoteClient*>::iterator
691 i != clients.end(); ++i)
693 RemoteClient *client = i->second;
695 // If definitions and textures have not been sent, don't
696 // send objects either
697 if (client->getState() < CS_DefinitionsSent)
700 Player *player = m_env->getPlayer(client->peer_id);
703 // This can happen if the client timeouts somehow
704 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
706 <<" has no associated player"<<std::endl;*/
709 v3s16 pos = floatToInt(player->getPosition(), BS);
711 std::set<u16> removed_objects;
712 std::set<u16> added_objects;
713 m_env->getRemovedActiveObjects(pos, radius, player_radius,
714 client->m_known_objects, removed_objects);
715 m_env->getAddedActiveObjects(pos, radius, player_radius,
716 client->m_known_objects, added_objects);
718 // Ignore if nothing happened
719 if(removed_objects.empty() && added_objects.empty())
721 //infostream<<"active objects: none changed"<<std::endl;
725 std::string data_buffer;
729 // Handle removed objects
730 writeU16((u8*)buf, removed_objects.size());
731 data_buffer.append(buf, 2);
732 for(std::set<u16>::iterator
733 i = removed_objects.begin();
734 i != removed_objects.end(); ++i)
738 ServerActiveObject* obj = m_env->getActiveObject(id);
740 // Add to data buffer for sending
741 writeU16((u8*)buf, id);
742 data_buffer.append(buf, 2);
744 // Remove from known objects
745 client->m_known_objects.erase(id);
747 if(obj && obj->m_known_by_count > 0)
748 obj->m_known_by_count--;
751 // Handle added objects
752 writeU16((u8*)buf, added_objects.size());
753 data_buffer.append(buf, 2);
754 for(std::set<u16>::iterator
755 i = added_objects.begin();
756 i != added_objects.end(); ++i)
760 ServerActiveObject* obj = m_env->getActiveObject(id);
763 u8 type = ACTIVEOBJECT_TYPE_INVALID;
765 infostream<<"WARNING: "<<__FUNCTION_NAME
766 <<": NULL object"<<std::endl;
768 type = obj->getSendType();
770 // Add to data buffer for sending
771 writeU16((u8*)buf, id);
772 data_buffer.append(buf, 2);
773 writeU8((u8*)buf, type);
774 data_buffer.append(buf, 1);
777 data_buffer.append(serializeLongString(
778 obj->getClientInitializationData(client->net_proto_version)));
780 data_buffer.append(serializeLongString(""));
782 // Add to known objects
783 client->m_known_objects.insert(id);
786 obj->m_known_by_count++;
789 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
790 verbosestream << "Server: Sent object remove/add: "
791 << removed_objects.size() << " removed, "
792 << added_objects.size() << " added, "
793 << "packet size is " << pktSize << std::endl;
802 JMutexAutoLock envlock(m_env_mutex);
803 ScopeProfiler sp(g_profiler, "Server: sending object messages");
806 // Value = data sent by object
807 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
809 // Get active object messages from environment
811 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
815 std::vector<ActiveObjectMessage>* message_list = NULL;
816 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
817 n = buffered_messages.find(aom.id);
818 if (n == buffered_messages.end()) {
819 message_list = new std::vector<ActiveObjectMessage>;
820 buffered_messages[aom.id] = message_list;
823 message_list = n->second;
825 message_list->push_back(aom);
829 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
830 // Route data to every client
831 for (std::map<u16, RemoteClient*>::iterator
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 (std::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(std::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 JMutexAutoLock 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 infostream << "WARNING: 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;
1004 m_emerge->startThreads();
1008 // Save map, players and auth stuff
1010 float &counter = m_savemap_timer;
1012 if(counter >= g_settings->getFloat("server_map_save_interval"))
1015 JMutexAutoLock 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 void Server::Receive()
1038 DSTACK(__FUNCTION_NAME);
1039 SharedBuffer<u8> data;
1043 m_con.Receive(&pkt);
1044 peer_id = pkt.getPeerId();
1047 catch(con::InvalidIncomingDataException &e) {
1048 infostream<<"Server::Receive(): "
1049 "InvalidIncomingDataException: what()="
1050 <<e.what()<<std::endl;
1052 catch(SerializationError &e) {
1053 infostream<<"Server::Receive(): "
1054 "SerializationError: what()="
1055 <<e.what()<<std::endl;
1057 catch(ClientStateError &e) {
1058 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1059 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1060 L"Try reconnecting or updating your client");
1062 catch(con::PeerNotFoundException &e) {
1067 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1069 std::string playername = "";
1070 PlayerSAO *playersao = NULL;
1073 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1074 if (client != NULL) {
1075 playername = client->getName();
1076 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1078 } catch (std::exception &e) {
1084 RemotePlayer *player =
1085 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1087 // If failed, cancel
1088 if ((playersao == NULL) || (player == NULL)) {
1089 if (player && player->peer_id != 0) {
1090 actionstream << "Server: Failed to emerge player \"" << playername
1091 << "\" (player allocated to an another client)" << std::endl;
1092 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1093 L"name. If your client closed unexpectedly, try again in "
1096 errorstream << "Server: " << playername << ": Failed to emerge player"
1098 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1104 Send complete position information
1106 SendMovePlayer(peer_id);
1109 SendPlayerPrivileges(peer_id);
1111 // Send inventory formspec
1112 SendPlayerInventoryFormspec(peer_id);
1115 SendInventory(playersao);
1118 SendPlayerHPOrDie(playersao);
1121 SendPlayerBreath(peer_id);
1123 // Show death screen if necessary
1124 if(player->isDead())
1125 SendDeathscreen(peer_id, false, v3f(0,0,0));
1127 // Note things in chat if not in simple singleplayer mode
1128 if(!m_simple_singleplayer_mode) {
1129 // Send information about server to player in chat
1130 SendChatMessage(peer_id, getStatusString());
1132 // Send information about joining in chat
1134 std::wstring name = L"unknown";
1135 Player *player = m_env->getPlayer(peer_id);
1137 name = narrow_to_wide(player->getName());
1139 std::wstring message;
1142 message += L" joined the game.";
1143 SendChatMessage(PEER_ID_INEXISTENT,message);
1146 Address addr = getPeerAddress(player->peer_id);
1147 std::string ip_str = addr.serializeString();
1148 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1153 std::vector<std::string> names = m_clients.getPlayerNames();
1155 actionstream<<player->getName() <<" joins game. List of players: ";
1157 for (std::vector<std::string>::iterator i = names.begin();
1158 i != names.end(); i++) {
1159 actionstream << *i << " ";
1162 actionstream << player->getName() <<std::endl;
1167 inline void Server::handleCommand(NetworkPacket* pkt)
1169 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1170 (this->*opHandle.handler)(pkt);
1173 void Server::ProcessData(NetworkPacket *pkt)
1175 DSTACK(__FUNCTION_NAME);
1176 // Environment is locked first.
1177 JMutexAutoLock envlock(m_env_mutex);
1179 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1180 u32 peer_id = pkt->getPeerId();
1183 Address address = getPeerAddress(peer_id);
1184 std::string addr_s = address.serializeString();
1186 if(m_banmanager->isIpBanned(addr_s)) {
1187 std::string ban_name = m_banmanager->getBanName(addr_s);
1188 infostream << "Server: A banned client tried to connect from "
1189 << addr_s << "; banned name was "
1190 << ban_name << std::endl;
1191 // This actually doesn't seem to transfer to the client
1192 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1193 + utf8_to_wide(ban_name));
1197 catch(con::PeerNotFoundException &e) {
1199 * no peer for this packet found
1200 * most common reason is peer timeout, e.g. peer didn't
1201 * respond for some time, your server was overloaded or
1204 infostream << "Server::ProcessData(): Canceling: peer "
1205 << peer_id << " not found" << std::endl;
1210 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1212 // Command must be handled into ToServerCommandHandler
1213 if (command >= TOSERVER_NUM_MSG_TYPES) {
1214 infostream << "Server: Ignoring unknown command "
1215 << command << std::endl;
1219 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1224 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1226 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1227 errorstream << "Server::ProcessData(): Cancelling: Peer"
1228 " serialization format invalid or not initialized."
1229 " Skipping incoming command=" << command << std::endl;
1233 /* Handle commands related to client startup */
1234 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1239 if (m_clients.getClientState(peer_id) < CS_Active) {
1240 if (command == TOSERVER_PLAYERPOS) return;
1242 errorstream << "Got packet command: " << command << " for peer id "
1243 << peer_id << " but client isn't active yet. Dropping packet "
1249 } catch (SendFailedException &e) {
1250 errorstream << "Server::ProcessData(): SendFailedException: "
1251 << "what=" << e.what()
1253 } catch (PacketError &e) {
1254 actionstream << "Server::ProcessData(): PacketError: "
1255 << "what=" << e.what()
1260 void Server::setTimeOfDay(u32 time)
1262 m_env->setTimeOfDay(time);
1263 m_time_of_day_send_timer = 0;
1266 void Server::onMapEditEvent(MapEditEvent *event)
1268 if(m_ignore_map_edit_events)
1270 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1272 MapEditEvent *e = event->clone();
1273 m_unsent_map_edit_queue.push(e);
1276 Inventory* Server::getInventory(const InventoryLocation &loc)
1279 case InventoryLocation::UNDEFINED:
1280 case InventoryLocation::CURRENT_PLAYER:
1282 case InventoryLocation::PLAYER:
1284 Player *player = m_env->getPlayer(loc.name.c_str());
1287 PlayerSAO *playersao = player->getPlayerSAO();
1290 return playersao->getInventory();
1293 case InventoryLocation::NODEMETA:
1295 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1298 return meta->getInventory();
1301 case InventoryLocation::DETACHED:
1303 if(m_detached_inventories.count(loc.name) == 0)
1305 return m_detached_inventories[loc.name];
1309 sanity_check(false); // abort
1314 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1317 case InventoryLocation::UNDEFINED:
1319 case InventoryLocation::PLAYER:
1324 Player *player = m_env->getPlayer(loc.name.c_str());
1327 PlayerSAO *playersao = player->getPlayerSAO();
1331 SendInventory(playersao);
1334 case InventoryLocation::NODEMETA:
1336 v3s16 blockpos = getNodeBlockPos(loc.p);
1338 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1340 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1342 setBlockNotSent(blockpos);
1345 case InventoryLocation::DETACHED:
1347 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1351 sanity_check(false); // abort
1356 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1358 std::vector<u16> clients = m_clients.getClientIDs();
1360 // Set the modified blocks unsent for all the clients
1361 for (std::vector<u16>::iterator i = clients.begin();
1362 i != clients.end(); ++i) {
1363 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1364 client->SetBlocksNotSent(block);
1369 void Server::peerAdded(con::Peer *peer)
1371 DSTACK(__FUNCTION_NAME);
1372 verbosestream<<"Server::peerAdded(): peer->id="
1373 <<peer->id<<std::endl;
1376 c.type = con::PEER_ADDED;
1377 c.peer_id = peer->id;
1379 m_peer_change_queue.push(c);
1382 void Server::deletingPeer(con::Peer *peer, bool timeout)
1384 DSTACK(__FUNCTION_NAME);
1385 verbosestream<<"Server::deletingPeer(): peer->id="
1386 <<peer->id<<", timeout="<<timeout<<std::endl;
1388 m_clients.event(peer->id, CSE_Disconnect);
1390 c.type = con::PEER_REMOVED;
1391 c.peer_id = peer->id;
1392 c.timeout = timeout;
1393 m_peer_change_queue.push(c);
1396 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1398 *retval = m_con.getPeerStat(peer_id,type);
1399 if (*retval == -1) return false;
1403 bool Server::getClientInfo(
1412 std::string* vers_string
1415 *state = m_clients.getClientState(peer_id);
1417 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1419 if (client == NULL) {
1424 *uptime = client->uptime();
1425 *ser_vers = client->serialization_version;
1426 *prot_vers = client->net_proto_version;
1428 *major = client->getMajor();
1429 *minor = client->getMinor();
1430 *patch = client->getPatch();
1431 *vers_string = client->getPatch();
1438 void Server::handlePeerChanges()
1440 while(m_peer_change_queue.size() > 0)
1442 con::PeerChange c = m_peer_change_queue.front();
1443 m_peer_change_queue.pop();
1445 verbosestream<<"Server: Handling peer change: "
1446 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1451 case con::PEER_ADDED:
1452 m_clients.CreateClient(c.peer_id);
1455 case con::PEER_REMOVED:
1456 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1460 FATAL_ERROR("Invalid peer change event received!");
1466 void Server::Send(NetworkPacket* pkt)
1468 m_clients.send(pkt->getPeerId(),
1469 clientCommandFactoryTable[pkt->getCommand()].channel,
1471 clientCommandFactoryTable[pkt->getCommand()].reliable);
1474 void Server::SendMovement(u16 peer_id)
1476 DSTACK(__FUNCTION_NAME);
1477 std::ostringstream os(std::ios_base::binary);
1479 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1481 pkt << g_settings->getFloat("movement_acceleration_default");
1482 pkt << g_settings->getFloat("movement_acceleration_air");
1483 pkt << g_settings->getFloat("movement_acceleration_fast");
1484 pkt << g_settings->getFloat("movement_speed_walk");
1485 pkt << g_settings->getFloat("movement_speed_crouch");
1486 pkt << g_settings->getFloat("movement_speed_fast");
1487 pkt << g_settings->getFloat("movement_speed_climb");
1488 pkt << g_settings->getFloat("movement_speed_jump");
1489 pkt << g_settings->getFloat("movement_liquid_fluidity");
1490 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1491 pkt << g_settings->getFloat("movement_liquid_sink");
1492 pkt << g_settings->getFloat("movement_gravity");
1497 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1499 if (!g_settings->getBool("enable_damage"))
1502 u16 peer_id = playersao->getPeerID();
1503 bool is_alive = playersao->getHP() > 0;
1506 SendPlayerHP(peer_id);
1511 void Server::SendHP(u16 peer_id, u8 hp)
1513 DSTACK(__FUNCTION_NAME);
1515 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1520 void Server::SendBreath(u16 peer_id, u16 breath)
1522 DSTACK(__FUNCTION_NAME);
1524 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1525 pkt << (u16) breath;
1529 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1530 const std::string &custom_reason, bool reconnect)
1532 assert(reason < SERVER_ACCESSDENIED_MAX);
1534 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1536 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1537 pkt << custom_reason;
1538 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1539 reason == SERVER_ACCESSDENIED_CRASH)
1540 pkt << custom_reason << (u8)reconnect;
1544 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1546 DSTACK(__FUNCTION_NAME);
1548 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1553 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1554 v3f camera_point_target)
1556 DSTACK(__FUNCTION_NAME);
1558 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1559 pkt << set_camera_point_target << camera_point_target;
1563 void Server::SendItemDef(u16 peer_id,
1564 IItemDefManager *itemdef, u16 protocol_version)
1566 DSTACK(__FUNCTION_NAME);
1568 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1572 u32 length of the next item
1573 zlib-compressed serialized ItemDefManager
1575 std::ostringstream tmp_os(std::ios::binary);
1576 itemdef->serialize(tmp_os, protocol_version);
1577 std::ostringstream tmp_os2(std::ios::binary);
1578 compressZlib(tmp_os.str(), tmp_os2);
1579 pkt.putLongString(tmp_os2.str());
1582 verbosestream << "Server: Sending item definitions to id(" << peer_id
1583 << "): size=" << pkt.getSize() << std::endl;
1588 void Server::SendNodeDef(u16 peer_id,
1589 INodeDefManager *nodedef, u16 protocol_version)
1591 DSTACK(__FUNCTION_NAME);
1593 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1597 u32 length of the next item
1598 zlib-compressed serialized NodeDefManager
1600 std::ostringstream tmp_os(std::ios::binary);
1601 nodedef->serialize(tmp_os, protocol_version);
1602 std::ostringstream tmp_os2(std::ios::binary);
1603 compressZlib(tmp_os.str(), tmp_os2);
1605 pkt.putLongString(tmp_os2.str());
1608 verbosestream << "Server: Sending node definitions to id(" << peer_id
1609 << "): size=" << pkt.getSize() << std::endl;
1615 Non-static send methods
1618 void Server::SendInventory(PlayerSAO* playerSAO)
1620 DSTACK(__FUNCTION_NAME);
1622 UpdateCrafting(playerSAO->getPlayer());
1628 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1630 std::ostringstream os;
1631 playerSAO->getInventory()->serialize(os);
1633 std::string s = os.str();
1635 pkt.putRawString(s.c_str(), s.size());
1639 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1641 DSTACK(__FUNCTION_NAME);
1643 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1646 if (peer_id != PEER_ID_INEXISTENT) {
1650 m_clients.sendToAll(0, &pkt, true);
1654 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1655 const std::string &formname)
1657 DSTACK(__FUNCTION_NAME);
1659 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1661 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1667 // Spawns a particle on peer with peer_id
1668 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1669 float expirationtime, float size, bool collisiondetection,
1670 bool vertical, std::string texture)
1672 DSTACK(__FUNCTION_NAME);
1674 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1676 pkt << pos << velocity << acceleration << expirationtime
1677 << size << collisiondetection;
1678 pkt.putLongString(texture);
1681 if (peer_id != PEER_ID_INEXISTENT) {
1685 m_clients.sendToAll(0, &pkt, true);
1689 // Adds a ParticleSpawner on peer with peer_id
1690 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1691 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1692 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1694 DSTACK(__FUNCTION_NAME);
1696 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1698 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1699 << minacc << maxacc << minexptime << maxexptime << minsize
1700 << maxsize << collisiondetection;
1702 pkt.putLongString(texture);
1704 pkt << id << vertical;
1706 if (peer_id != PEER_ID_INEXISTENT) {
1710 m_clients.sendToAll(0, &pkt, true);
1714 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1716 DSTACK(__FUNCTION_NAME);
1718 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1720 // Ugly error in this packet
1723 if (peer_id != PEER_ID_INEXISTENT) {
1727 m_clients.sendToAll(0, &pkt, true);
1732 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1734 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1736 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1737 << form->text << form->number << form->item << form->dir
1738 << form->align << form->offset << form->world_pos << form->size;
1743 void Server::SendHUDRemove(u16 peer_id, u32 id)
1745 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1750 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1752 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1753 pkt << id << (u8) stat;
1757 case HUD_STAT_SCALE:
1758 case HUD_STAT_ALIGN:
1759 case HUD_STAT_OFFSET:
1760 pkt << *(v2f *) value;
1764 pkt << *(std::string *) value;
1766 case HUD_STAT_WORLD_POS:
1767 pkt << *(v3f *) value;
1770 pkt << *(v2s32 *) value;
1772 case HUD_STAT_NUMBER:
1776 pkt << *(u32 *) value;
1783 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1785 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1787 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1789 pkt << flags << mask;
1794 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1796 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1797 pkt << param << value;
1801 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1802 const std::string &type, const std::vector<std::string> ¶ms)
1804 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1805 pkt << bgcolor << type << (u16) params.size();
1807 for(size_t i=0; i<params.size(); i++)
1813 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1816 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1819 pkt << do_override << (u16) (ratio * 65535);
1824 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1826 DSTACK(__FUNCTION_NAME);
1828 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1829 pkt << time << time_speed;
1831 if (peer_id == PEER_ID_INEXISTENT) {
1832 m_clients.sendToAll(0, &pkt, true);
1839 void Server::SendPlayerHP(u16 peer_id)
1841 DSTACK(__FUNCTION_NAME);
1842 PlayerSAO *playersao = getPlayerSAO(peer_id);
1843 // In some rare case, if the player is disconnected
1844 // while Lua call l_punch, for example, this can be NULL
1848 SendHP(peer_id, playersao->getHP());
1849 m_script->player_event(playersao,"health_changed");
1851 // Send to other clients
1852 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1853 ActiveObjectMessage aom(playersao->getId(), true, str);
1854 playersao->m_messages_out.push(aom);
1857 void Server::SendPlayerBreath(u16 peer_id)
1859 DSTACK(__FUNCTION_NAME);
1860 PlayerSAO *playersao = getPlayerSAO(peer_id);
1863 m_script->player_event(playersao, "breath_changed");
1864 SendBreath(peer_id, playersao->getBreath());
1867 void Server::SendMovePlayer(u16 peer_id)
1869 DSTACK(__FUNCTION_NAME);
1870 Player *player = m_env->getPlayer(peer_id);
1873 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1874 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1877 v3f pos = player->getPosition();
1878 f32 pitch = player->getPitch();
1879 f32 yaw = player->getYaw();
1880 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1881 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1882 << " pitch=" << pitch
1890 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1892 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1895 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1896 << animation_frames[3] << animation_speed;
1901 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1903 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1904 pkt << first << third;
1907 void Server::SendPlayerPrivileges(u16 peer_id)
1909 Player *player = m_env->getPlayer(peer_id);
1911 if(player->peer_id == PEER_ID_INEXISTENT)
1914 std::set<std::string> privs;
1915 m_script->getAuth(player->getName(), NULL, &privs);
1917 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1918 pkt << (u16) privs.size();
1920 for(std::set<std::string>::const_iterator i = privs.begin();
1921 i != privs.end(); i++) {
1928 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1930 Player *player = m_env->getPlayer(peer_id);
1932 if(player->peer_id == PEER_ID_INEXISTENT)
1935 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1936 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1940 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1942 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 return pkt.getSize();
1948 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1950 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1951 datas.size(), peer_id);
1953 pkt.putRawString(datas.c_str(), datas.size());
1955 m_clients.send(pkt.getPeerId(),
1956 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1961 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<u16> dst_clients;
1973 if(params.to_player != "")
1975 Player *player = m_env->getPlayer(params.to_player.c_str());
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not found"<<std::endl;
1981 if(player->peer_id == PEER_ID_INEXISTENT){
1982 infostream<<"Server::playSound: Player \""<<params.to_player
1983 <<"\" not connected"<<std::endl;
1986 dst_clients.push_back(player->peer_id);
1989 std::vector<u16> clients = m_clients.getClientIDs();
1991 for(std::vector<u16>::iterator
1992 i = clients.begin(); i != clients.end(); ++i) {
1993 Player *player = m_env->getPlayer(*i);
1998 if(player->getPosition().getDistanceFrom(pos) >
1999 params.max_hear_distance)
2002 dst_clients.push_back(*i);
2006 if(dst_clients.empty())
2010 s32 id = m_next_sound_id++;
2011 // The sound will exist as a reference in m_playing_sounds
2012 m_playing_sounds[id] = ServerPlayingSound();
2013 ServerPlayingSound &psound = m_playing_sounds[id];
2014 psound.params = params;
2016 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2017 pkt << id << spec.name << (float) (spec.gain * params.gain)
2018 << (u8) params.type << pos << params.object << params.loop;
2020 for(std::vector<u16>::iterator i = dst_clients.begin();
2021 i != dst_clients.end(); i++) {
2022 psound.clients.insert(*i);
2023 m_clients.send(*i, 0, &pkt, true);
2027 void Server::stopSound(s32 handle)
2029 // Get sound reference
2030 std::map<s32, ServerPlayingSound>::iterator i =
2031 m_playing_sounds.find(handle);
2032 if(i == m_playing_sounds.end())
2034 ServerPlayingSound &psound = i->second;
2036 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2039 for(std::set<u16>::iterator i = psound.clients.begin();
2040 i != psound.clients.end(); i++) {
2042 m_clients.send(*i, 0, &pkt, true);
2044 // Remove sound reference
2045 m_playing_sounds.erase(i);
2048 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2049 std::vector<u16> *far_players, float far_d_nodes)
2051 float maxd = far_d_nodes*BS;
2052 v3f p_f = intToFloat(p, BS);
2054 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2057 std::vector<u16> clients = m_clients.getClientIDs();
2058 for(std::vector<u16>::iterator i = clients.begin();
2059 i != clients.end(); ++i) {
2062 if(Player *player = m_env->getPlayer(*i)) {
2063 // If player is far away, only set modified blocks not sent
2064 v3f player_pos = player->getPosition();
2065 if(player_pos.getDistanceFrom(p_f) > maxd) {
2066 far_players->push_back(*i);
2073 m_clients.send(*i, 0, &pkt, true);
2077 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2078 std::vector<u16> *far_players, float far_d_nodes,
2079 bool remove_metadata)
2081 float maxd = far_d_nodes*BS;
2082 v3f p_f = intToFloat(p, BS);
2084 std::vector<u16> clients = m_clients.getClientIDs();
2085 for(std::vector<u16>::iterator i = clients.begin();
2086 i != clients.end(); ++i) {
2090 if(Player *player = m_env->getPlayer(*i)) {
2091 // If player is far away, only set modified blocks not sent
2092 v3f player_pos = player->getPosition();
2093 if(player_pos.getDistanceFrom(p_f) > maxd) {
2094 far_players->push_back(*i);
2100 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2102 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2104 pkt << p << n.param0 << n.param1 << n.param2
2105 << (u8) (remove_metadata ? 0 : 1);
2107 if (!remove_metadata) {
2108 if (client->net_proto_version <= 21) {
2109 // Old clients always clear metadata; fix it
2110 // by sending the full block again.
2111 client->SetBlockNotSent(p);
2118 if (pkt.getSize() > 0)
2119 m_clients.send(*i, 0, &pkt, true);
2123 void Server::setBlockNotSent(v3s16 p)
2125 std::vector<u16> clients = m_clients.getClientIDs();
2127 for(std::vector<u16>::iterator i = clients.begin();
2128 i != clients.end(); ++i) {
2129 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2130 client->SetBlockNotSent(p);
2135 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2137 DSTACK(__FUNCTION_NAME);
2139 v3s16 p = block->getPos();
2142 Create a packet with the block in the right format
2145 std::ostringstream os(std::ios_base::binary);
2146 block->serialize(os, ver, false);
2147 block->serializeNetworkSpecific(os, net_proto_version);
2148 std::string s = os.str();
2150 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2153 pkt.putRawString(s.c_str(), s.size());
2157 void Server::SendBlocks(float dtime)
2159 DSTACK(__FUNCTION_NAME);
2161 JMutexAutoLock envlock(m_env_mutex);
2162 //TODO check if one big lock could be faster then multiple small ones
2164 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2166 std::vector<PrioritySortedBlockTransfer> queue;
2168 s32 total_sending = 0;
2171 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2173 std::vector<u16> clients = m_clients.getClientIDs();
2176 for(std::vector<u16>::iterator i = clients.begin();
2177 i != clients.end(); ++i) {
2178 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2183 total_sending += client->SendingCount();
2184 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2190 // Lowest priority number comes first.
2191 // Lowest is most important.
2192 std::sort(queue.begin(), queue.end());
2195 for(u32 i=0; i<queue.size(); i++)
2197 //TODO: Calculate limit dynamically
2198 if(total_sending >= g_settings->getS32
2199 ("max_simultaneous_block_sends_server_total"))
2202 PrioritySortedBlockTransfer q = queue[i];
2204 MapBlock *block = NULL;
2207 block = m_env->getMap().getBlockNoCreate(q.pos);
2209 catch(InvalidPositionException &e)
2214 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2219 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2221 client->SentBlock(q.pos);
2227 void Server::fillMediaCache()
2229 DSTACK(__FUNCTION_NAME);
2231 infostream<<"Server: Calculating media file checksums"<<std::endl;
2233 // Collect all media file paths
2234 std::vector<std::string> paths;
2235 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2236 i != m_mods.end(); i++) {
2237 const ModSpec &mod = *i;
2238 paths.push_back(mod.path + DIR_DELIM + "textures");
2239 paths.push_back(mod.path + DIR_DELIM + "sounds");
2240 paths.push_back(mod.path + DIR_DELIM + "media");
2241 paths.push_back(mod.path + DIR_DELIM + "models");
2243 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2245 // Collect media file information from paths into cache
2246 for(std::vector<std::string>::iterator i = paths.begin();
2247 i != paths.end(); i++) {
2248 std::string mediapath = *i;
2249 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2250 for (u32 j = 0; j < dirlist.size(); j++) {
2251 if (dirlist[j].dir) // Ignode dirs
2253 std::string filename = dirlist[j].name;
2254 // If name contains illegal characters, ignore the file
2255 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2256 infostream<<"Server: ignoring illegal file name: \""
2257 << filename << "\"" << std::endl;
2260 // If name is not in a supported format, ignore it
2261 const char *supported_ext[] = {
2262 ".png", ".jpg", ".bmp", ".tga",
2263 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2265 ".x", ".b3d", ".md2", ".obj",
2268 if (removeStringEnd(filename, supported_ext) == ""){
2269 infostream << "Server: ignoring unsupported file extension: \""
2270 << filename << "\"" << std::endl;
2273 // Ok, attempt to load the file and add to cache
2274 std::string filepath = mediapath + DIR_DELIM + filename;
2276 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2278 errorstream << "Server::fillMediaCache(): Could not open \""
2279 << filename << "\" for reading" << std::endl;
2282 std::ostringstream tmp_os(std::ios_base::binary);
2286 fis.read(buf, 1024);
2287 std::streamsize len = fis.gcount();
2288 tmp_os.write(buf, len);
2297 errorstream<<"Server::fillMediaCache(): Failed to read \""
2298 << filename << "\"" << std::endl;
2301 if(tmp_os.str().length() == 0) {
2302 errorstream << "Server::fillMediaCache(): Empty file \""
2303 << filepath << "\"" << std::endl;
2308 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2310 unsigned char *digest = sha1.getDigest();
2311 std::string sha1_base64 = base64_encode(digest, 20);
2312 std::string sha1_hex = hex_encode((char*)digest, 20);
2316 m_media[filename] = MediaInfo(filepath, sha1_base64);
2317 verbosestream << "Server: " << sha1_hex << " is " << filename
2323 void Server::sendMediaAnnouncement(u16 peer_id)
2325 DSTACK(__FUNCTION_NAME);
2327 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2331 std::ostringstream os(std::ios_base::binary);
2333 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2334 pkt << (u16) m_media.size();
2336 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2337 i != m_media.end(); ++i) {
2338 pkt << i->first << i->second.sha1_digest;
2341 pkt << g_settings->get("remote_media");
2345 struct SendableMedia
2351 SendableMedia(const std::string &name_="", const std::string &path_="",
2352 const std::string &data_=""):
2359 void Server::sendRequestedMedia(u16 peer_id,
2360 const std::vector<std::string> &tosend)
2362 DSTACK(__FUNCTION_NAME);
2364 verbosestream<<"Server::sendRequestedMedia(): "
2365 <<"Sending files to client"<<std::endl;
2369 // Put 5kB in one bunch (this is not accurate)
2370 u32 bytes_per_bunch = 5000;
2372 std::vector< std::vector<SendableMedia> > file_bunches;
2373 file_bunches.push_back(std::vector<SendableMedia>());
2375 u32 file_size_bunch_total = 0;
2377 for(std::vector<std::string>::const_iterator i = tosend.begin();
2378 i != tosend.end(); ++i) {
2379 const std::string &name = *i;
2381 if(m_media.find(name) == m_media.end()) {
2382 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2383 <<"unknown file \""<<(name)<<"\""<<std::endl;
2387 //TODO get path + name
2388 std::string tpath = m_media[name].path;
2391 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2392 if(fis.good() == false){
2393 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2394 <<tpath<<"\" for reading"<<std::endl;
2397 std::ostringstream tmp_os(std::ios_base::binary);
2401 fis.read(buf, 1024);
2402 std::streamsize len = fis.gcount();
2403 tmp_os.write(buf, len);
2404 file_size_bunch_total += len;
2413 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2414 <<name<<"\""<<std::endl;
2417 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2418 <<tname<<"\""<<std::endl;*/
2420 file_bunches[file_bunches.size()-1].push_back(
2421 SendableMedia(name, tpath, tmp_os.str()));
2423 // Start next bunch if got enough data
2424 if(file_size_bunch_total >= bytes_per_bunch) {
2425 file_bunches.push_back(std::vector<SendableMedia>());
2426 file_size_bunch_total = 0;
2431 /* Create and send packets */
2433 u16 num_bunches = file_bunches.size();
2434 for(u16 i = 0; i < num_bunches; i++) {
2437 u16 total number of texture bunches
2438 u16 index of this bunch
2439 u32 number of files in this bunch
2448 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2449 pkt << num_bunches << i << (u32) file_bunches[i].size();
2451 for(std::vector<SendableMedia>::iterator
2452 j = file_bunches[i].begin();
2453 j != file_bunches[i].end(); ++j) {
2455 pkt.putLongString(j->data);
2458 verbosestream << "Server::sendRequestedMedia(): bunch "
2459 << i << "/" << num_bunches
2460 << " files=" << file_bunches[i].size()
2461 << " size=" << pkt.getSize() << std::endl;
2466 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2468 if(m_detached_inventories.count(name) == 0) {
2469 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2472 Inventory *inv = m_detached_inventories[name];
2473 std::ostringstream os(std::ios_base::binary);
2475 os << serializeString(name);
2479 std::string s = os.str();
2481 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2482 pkt.putRawString(s.c_str(), s.size());
2484 if (peer_id != PEER_ID_INEXISTENT) {
2488 m_clients.sendToAll(0, &pkt, true);
2492 void Server::sendDetachedInventories(u16 peer_id)
2494 DSTACK(__FUNCTION_NAME);
2496 for(std::map<std::string, Inventory*>::iterator
2497 i = m_detached_inventories.begin();
2498 i != m_detached_inventories.end(); i++) {
2499 const std::string &name = i->first;
2500 //Inventory *inv = i->second;
2501 sendDetachedInventory(name, peer_id);
2509 void Server::DiePlayer(u16 peer_id)
2511 DSTACK(__FUNCTION_NAME);
2513 PlayerSAO *playersao = getPlayerSAO(peer_id);
2516 infostream << "Server::DiePlayer(): Player "
2517 << playersao->getPlayer()->getName()
2518 << " dies" << std::endl;
2520 playersao->setHP(0);
2522 // Trigger scripted stuff
2523 m_script->on_dieplayer(playersao);
2525 SendPlayerHP(peer_id);
2526 SendDeathscreen(peer_id, false, v3f(0,0,0));
2529 void Server::RespawnPlayer(u16 peer_id)
2531 DSTACK(__FUNCTION_NAME);
2533 PlayerSAO *playersao = getPlayerSAO(peer_id);
2536 infostream << "Server::RespawnPlayer(): Player "
2537 << playersao->getPlayer()->getName()
2538 << " respawns" << std::endl;
2540 playersao->setHP(PLAYER_MAX_HP);
2541 playersao->setBreath(PLAYER_MAX_BREATH);
2543 SendPlayerHP(peer_id);
2544 SendPlayerBreath(peer_id);
2546 bool repositioned = m_script->on_respawnplayer(playersao);
2548 v3f pos = findSpawnPos();
2549 // setPos will send the new position to client
2550 playersao->setPos(pos);
2555 void Server::DenySudoAccess(u16 peer_id)
2557 DSTACK(__FUNCTION_NAME);
2559 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2564 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2565 const std::string &str_reason, bool reconnect)
2567 if (proto_ver >= 25) {
2568 SendAccessDenied(peer_id, reason, str_reason);
2570 std::wstring wreason = utf8_to_wide(
2571 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2572 accessDeniedStrings[(u8)reason]);
2573 SendAccessDenied_Legacy(peer_id, wreason);
2576 m_clients.event(peer_id, CSE_SetDenied);
2577 m_con.DisconnectPeer(peer_id);
2581 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2583 DSTACK(__FUNCTION_NAME);
2585 SendAccessDenied(peer_id, reason, custom_reason);
2586 m_clients.event(peer_id, CSE_SetDenied);
2587 m_con.DisconnectPeer(peer_id);
2590 // 13/03/15: remove this function when protocol version 25 will become
2591 // the minimum version for MT users, maybe in 1 year
2592 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2594 DSTACK(__FUNCTION_NAME);
2596 SendAccessDenied_Legacy(peer_id, reason);
2597 m_clients.event(peer_id, CSE_SetDenied);
2598 m_con.DisconnectPeer(peer_id);
2601 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2603 DSTACK(__FUNCTION_NAME);
2606 RemoteClient* client = getClient(peer_id, CS_Invalid);
2608 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2610 // Right now, the auth mechs don't change between login and sudo mode.
2611 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2612 client->allowed_sudo_mechs = sudo_auth_mechs;
2614 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2615 << g_settings->getFloat("dedicated_server_step")
2619 m_clients.event(peer_id, CSE_AuthAccept);
2621 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2623 // We only support SRP right now
2624 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2626 resp_pkt << sudo_auth_mechs;
2628 m_clients.event(peer_id, CSE_SudoSuccess);
2632 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2634 DSTACK(__FUNCTION_NAME);
2635 std::wstring message;
2638 Clear references to playing sounds
2640 for(std::map<s32, ServerPlayingSound>::iterator
2641 i = m_playing_sounds.begin();
2642 i != m_playing_sounds.end();)
2644 ServerPlayingSound &psound = i->second;
2645 psound.clients.erase(peer_id);
2646 if(psound.clients.empty())
2647 m_playing_sounds.erase(i++);
2652 Player *player = m_env->getPlayer(peer_id);
2654 // Collect information about leaving in chat
2656 if(player != NULL && reason != CDR_DENY)
2658 std::wstring name = narrow_to_wide(player->getName());
2661 message += L" left the game.";
2662 if(reason == CDR_TIMEOUT)
2663 message += L" (timed out)";
2667 /* Run scripts and remove from environment */
2671 PlayerSAO *playersao = player->getPlayerSAO();
2674 m_script->on_leaveplayer(playersao);
2676 playersao->disconnected();
2684 if(player != NULL && reason != CDR_DENY) {
2685 std::ostringstream os(std::ios_base::binary);
2686 std::vector<u16> clients = m_clients.getClientIDs();
2688 for(std::vector<u16>::iterator i = clients.begin();
2689 i != clients.end(); ++i) {
2691 Player *player = m_env->getPlayer(*i);
2695 // Get name of player
2696 os << player->getName() << " ";
2699 actionstream << player->getName() << " "
2700 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2701 << " List of players: " << os.str() << std::endl;
2705 JMutexAutoLock env_lock(m_env_mutex);
2706 m_clients.DeleteClient(peer_id);
2710 // Send leave chat message to all remaining clients
2711 if(message.length() != 0)
2712 SendChatMessage(PEER_ID_INEXISTENT,message);
2715 void Server::UpdateCrafting(Player* player)
2717 DSTACK(__FUNCTION_NAME);
2719 // Get a preview for crafting
2721 InventoryLocation loc;
2722 loc.setPlayer(player->getName());
2723 std::vector<ItemStack> output_replacements;
2724 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2725 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2727 // Put the new preview in
2728 InventoryList *plist = player->inventory.getList("craftpreview");
2729 sanity_check(plist);
2730 sanity_check(plist->getSize() >= 1);
2731 plist->changeItem(0, preview);
2734 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2736 RemoteClient *client = getClientNoEx(peer_id,state_min);
2738 throw ClientNotFoundException("Client not found");
2742 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2744 return m_clients.getClientNoEx(peer_id, state_min);
2747 std::string Server::getPlayerName(u16 peer_id)
2749 Player *player = m_env->getPlayer(peer_id);
2751 return "[id="+itos(peer_id)+"]";
2752 return player->getName();
2755 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2757 Player *player = m_env->getPlayer(peer_id);
2760 return player->getPlayerSAO();
2763 std::wstring Server::getStatusString()
2765 std::wostringstream os(std::ios_base::binary);
2768 os<<L"version="<<narrow_to_wide(g_version_string);
2770 os<<L", uptime="<<m_uptime.get();
2772 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2773 // Information about clients
2776 std::vector<u16> clients = m_clients.getClientIDs();
2777 for(std::vector<u16>::iterator i = clients.begin();
2778 i != clients.end(); ++i) {
2780 Player *player = m_env->getPlayer(*i);
2781 // Get name of player
2782 std::wstring name = L"unknown";
2784 name = narrow_to_wide(player->getName());
2785 // Add name to information string
2793 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2794 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2795 if(g_settings->get("motd") != "")
2796 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2800 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2802 std::set<std::string> privs;
2803 m_script->getAuth(name, NULL, &privs);
2807 bool Server::checkPriv(const std::string &name, const std::string &priv)
2809 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2810 return (privs.count(priv) != 0);
2813 void Server::reportPrivsModified(const std::string &name)
2816 std::vector<u16> clients = m_clients.getClientIDs();
2817 for(std::vector<u16>::iterator i = clients.begin();
2818 i != clients.end(); ++i) {
2819 Player *player = m_env->getPlayer(*i);
2820 reportPrivsModified(player->getName());
2823 Player *player = m_env->getPlayer(name.c_str());
2826 SendPlayerPrivileges(player->peer_id);
2827 PlayerSAO *sao = player->getPlayerSAO();
2830 sao->updatePrivileges(
2831 getPlayerEffectivePrivs(name),
2836 void Server::reportInventoryFormspecModified(const std::string &name)
2838 Player *player = m_env->getPlayer(name.c_str());
2841 SendPlayerInventoryFormspec(player->peer_id);
2844 void Server::setIpBanned(const std::string &ip, const std::string &name)
2846 m_banmanager->add(ip, name);
2849 void Server::unsetIpBanned(const std::string &ip_or_name)
2851 m_banmanager->remove(ip_or_name);
2854 std::string Server::getBanDescription(const std::string &ip_or_name)
2856 return m_banmanager->getBanDescription(ip_or_name);
2859 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2861 // m_env will be NULL if the server is initializing
2865 Player *player = m_env->getPlayer(name);
2869 if (player->peer_id == PEER_ID_INEXISTENT)
2872 SendChatMessage(player->peer_id, msg);
2875 bool Server::showFormspec(const char *playername, const std::string &formspec,
2876 const std::string &formname)
2878 // m_env will be NULL if the server is initializing
2882 Player *player = m_env->getPlayer(playername);
2886 SendShowFormspecMessage(player->peer_id, formspec, formname);
2890 u32 Server::hudAdd(Player *player, HudElement *form)
2895 u32 id = player->addHud(form);
2897 SendHUDAdd(player->peer_id, id, form);
2902 bool Server::hudRemove(Player *player, u32 id) {
2906 HudElement* todel = player->removeHud(id);
2913 SendHUDRemove(player->peer_id, id);
2917 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2922 SendHUDChange(player->peer_id, id, stat, data);
2926 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2931 SendHUDSetFlags(player->peer_id, flags, mask);
2932 player->hud_flags = flags;
2934 PlayerSAO* playersao = player->getPlayerSAO();
2936 if (playersao == NULL)
2939 m_script->player_event(playersao, "hud_changed");
2943 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2947 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2950 player->setHotbarItemcount(hotbar_itemcount);
2951 std::ostringstream os(std::ios::binary);
2952 writeS32(os, hotbar_itemcount);
2953 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2957 s32 Server::hudGetHotbarItemcount(Player *player)
2961 return player->getHotbarItemcount();
2964 void Server::hudSetHotbarImage(Player *player, std::string name)
2969 player->setHotbarImage(name);
2970 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2973 std::string Server::hudGetHotbarImage(Player *player)
2977 return player->getHotbarImage();
2980 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2985 player->setHotbarSelectedImage(name);
2986 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2989 std::string Server::hudGetHotbarSelectedImage(Player *player)
2994 return player->getHotbarSelectedImage();
2997 bool Server::setLocalPlayerAnimations(Player *player,
2998 v2s32 animation_frames[4], f32 frame_speed)
3003 player->setLocalAnimations(animation_frames, frame_speed);
3004 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3008 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3013 player->eye_offset_first = first;
3014 player->eye_offset_third = third;
3015 SendEyeOffset(player->peer_id, first, third);
3019 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3020 const std::string &type, const std::vector<std::string> ¶ms)
3025 player->setSky(bgcolor, type, params);
3026 SendSetSky(player->peer_id, bgcolor, type, params);
3030 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3036 player->overrideDayNightRatio(do_override, ratio);
3037 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3041 void Server::notifyPlayers(const std::wstring &msg)
3043 SendChatMessage(PEER_ID_INEXISTENT,msg);
3046 void Server::spawnParticle(const std::string &playername, v3f pos,
3047 v3f velocity, v3f acceleration,
3048 float expirationtime, float size, bool
3049 collisiondetection, bool vertical, const std::string &texture)
3051 // m_env will be NULL if the server is initializing
3055 u16 peer_id = PEER_ID_INEXISTENT;
3056 if (playername != "") {
3057 Player* player = m_env->getPlayer(playername.c_str());
3060 peer_id = player->peer_id;
3063 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3064 expirationtime, size, collisiondetection, vertical, texture);
3067 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3068 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3069 float minexptime, float maxexptime, float minsize, float maxsize,
3070 bool collisiondetection, bool vertical, const std::string &texture,
3071 const std::string &playername)
3073 // m_env will be NULL if the server is initializing
3077 u16 peer_id = PEER_ID_INEXISTENT;
3078 if (playername != "") {
3079 Player* player = m_env->getPlayer(playername.c_str());
3082 peer_id = player->peer_id;
3086 for(;;) // look for unused particlespawner id
3089 if (std::find(m_particlespawner_ids.begin(),
3090 m_particlespawner_ids.end(), id)
3091 == m_particlespawner_ids.end())
3093 m_particlespawner_ids.push_back(id);
3098 SendAddParticleSpawner(peer_id, amount, spawntime,
3099 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3100 minexptime, maxexptime, minsize, maxsize,
3101 collisiondetection, vertical, texture, id);
3106 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3108 // m_env will be NULL if the server is initializing
3110 throw ServerError("Can't delete particle spawners during initialisation!");
3112 u16 peer_id = PEER_ID_INEXISTENT;
3113 if (playername != "") {
3114 Player* player = m_env->getPlayer(playername.c_str());
3117 peer_id = player->peer_id;
3120 m_particlespawner_ids.erase(
3121 std::remove(m_particlespawner_ids.begin(),
3122 m_particlespawner_ids.end(), id),
3123 m_particlespawner_ids.end());
3124 SendDeleteParticleSpawner(peer_id, id);
3127 Inventory* Server::createDetachedInventory(const std::string &name)
3129 if(m_detached_inventories.count(name) > 0){
3130 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3131 delete m_detached_inventories[name];
3133 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3135 Inventory *inv = new Inventory(m_itemdef);
3137 m_detached_inventories[name] = inv;
3138 //TODO find a better way to do this
3139 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3143 // actions: time-reversed list
3144 // Return value: success/failure
3145 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3146 std::list<std::string> *log)
3148 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3149 ServerMap *map = (ServerMap*)(&m_env->getMap());
3151 // Fail if no actions to handle
3152 if(actions.empty()){
3153 log->push_back("Nothing to do.");
3160 for(std::list<RollbackAction>::const_iterator
3161 i = actions.begin();
3162 i != actions.end(); i++)
3164 const RollbackAction &action = *i;
3166 bool success = action.applyRevert(map, this, this);
3169 std::ostringstream os;
3170 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3171 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3173 log->push_back(os.str());
3175 std::ostringstream os;
3176 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3177 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3179 log->push_back(os.str());
3183 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3184 <<" failed"<<std::endl;
3186 // Call it done if less than half failed
3187 return num_failed <= num_tried/2;
3190 // IGameDef interface
3192 IItemDefManager *Server::getItemDefManager()
3197 INodeDefManager *Server::getNodeDefManager()
3202 ICraftDefManager *Server::getCraftDefManager()
3206 ITextureSource *Server::getTextureSource()
3210 IShaderSource *Server::getShaderSource()
3214 scene::ISceneManager *Server::getSceneManager()
3219 u16 Server::allocateUnknownNodeId(const std::string &name)
3221 return m_nodedef->allocateDummy(name);
3224 ISoundManager *Server::getSoundManager()
3226 return &dummySoundManager;
3229 MtEventManager *Server::getEventManager()
3234 IWritableItemDefManager *Server::getWritableItemDefManager()
3239 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3244 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3249 const ModSpec *Server::getModSpec(const std::string &modname) const
3251 std::vector<ModSpec>::const_iterator it;
3252 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3253 const ModSpec &mod = *it;
3254 if (mod.name == modname)
3260 void Server::getModNames(std::vector<std::string> &modlist)
3262 std::vector<ModSpec>::iterator it;
3263 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3264 modlist.push_back(it->name);
3267 std::string Server::getBuiltinLuaPath()
3269 return porting::path_share + DIR_DELIM + "builtin";
3272 v3f Server::findSpawnPos()
3274 ServerMap &map = m_env->getServerMap();
3276 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3277 return nodeposf * BS;
3280 // Default position is static_spawnpoint
3281 // We will return it if we don't found a good place
3282 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3284 s16 water_level = map.getWaterLevel();
3286 bool is_good = false;
3288 // Try to find a good place a few times
3289 for(s32 i = 0; i < 1000 && !is_good; i++) {
3291 // We're going to try to throw the player to this position
3292 v2s16 nodepos2d = v2s16(
3293 -range + (myrand() % (range * 2)),
3294 -range + (myrand() % (range * 2)));
3296 // Get ground height at point
3297 s16 groundheight = map.findGroundLevel(nodepos2d);
3298 if (groundheight <= water_level) // Don't go underwater
3300 if (groundheight > water_level + 6) // Don't go to high places
3303 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3306 for (s32 i = 0; i < 10; i++) {
3307 v3s16 blockpos = getNodeBlockPos(nodepos);
3308 map.emergeBlock(blockpos, true);
3309 content_t c = map.getNodeNoEx(nodepos).getContent();
3310 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3312 if (air_count >= 2){
3321 return intToFloat(nodepos, BS);
3324 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3326 bool newplayer = false;
3329 Try to get an existing player
3331 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3333 // If player is already connected, cancel
3334 if(player != NULL && player->peer_id != 0)
3336 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3341 If player with the wanted peer_id already exists, cancel.
3343 if(m_env->getPlayer(peer_id) != NULL)
3345 infostream<<"emergePlayer(): Player with wrong name but same"
3346 " peer_id already exists"<<std::endl;
3350 // Load player if it isn't already loaded
3352 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3355 // Create player if it doesn't exist
3358 player = new RemotePlayer(this, name);
3359 // Set player position
3360 infostream<<"Server: Finding spawn place for player \""
3361 <<name<<"\""<<std::endl;
3362 v3f pos = findSpawnPos();
3363 player->setPosition(pos);
3365 // Make sure the player is saved
3366 player->setModified(true);
3368 // Add player to environment
3369 m_env->addPlayer(player);
3372 // Create a new player active object
3373 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3374 getPlayerEffectivePrivs(player->getName()),
3377 player->protocol_version = proto_version;
3379 /* Clean up old HUD elements from previous sessions */
3382 /* Add object to environment */
3383 m_env->addActiveObject(playersao);
3387 m_script->on_newplayer(playersao);
3393 void dedicated_server_loop(Server &server, bool &kill)
3395 DSTACK(__FUNCTION_NAME);
3397 verbosestream<<"dedicated_server_loop()"<<std::endl;
3399 IntervalLimiter m_profiler_interval;
3403 float steplen = g_settings->getFloat("dedicated_server_step");
3404 // This is kind of a hack but can be done like this
3405 // because server.step() is very light
3407 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3408 sleep_ms((int)(steplen*1000.0));
3410 server.step(steplen);
3412 if(server.getShutdownRequested() || kill)
3414 infostream<<"Dedicated server quitting"<<std::endl;
3416 if(g_settings->getBool("server_announce"))
3417 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3425 float profiler_print_interval =
3426 g_settings->getFloat("profiler_print_interval");
3427 if(profiler_print_interval != 0)
3429 if(m_profiler_interval.step(steplen, profiler_print_interval))
3431 infostream<<"Profiler:"<<std::endl;
3432 g_profiler->print(infostream);
3433 g_profiler->clear();