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())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
107 m_server->AsyncRunStep();
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
165 const std::string &path_world,
166 const SubgameSpec &gamespec,
167 bool simple_singleplayer_mode,
170 m_path_world(path_world),
171 m_gamespec(gamespec),
172 m_simple_singleplayer_mode(simple_singleplayer_mode),
173 m_async_fatal_error(""),
182 m_enable_rollback_recording(false),
185 m_itemdef(createItemDefManager()),
186 m_nodedef(createNodeDefManager()),
187 m_craftdef(createCraftDefManager()),
188 m_event(new EventManager()),
190 m_time_of_day_send_timer(0),
193 m_shutdown_requested(false),
194 m_ignore_map_edit_events(false),
195 m_ignore_map_edit_events_peer_id(0),
199 m_liquid_transform_timer = 0.0;
200 m_liquid_transform_every = 1.0;
201 m_print_info_timer = 0.0;
202 m_masterserver_timer = 0.0;
203 m_objectdata_timer = 0.0;
204 m_emergethread_trigger_timer = 0.0;
205 m_savemap_timer = 0.0;
208 m_lag = g_settings->getFloat("dedicated_server_step");
211 throw ServerError("Supplied empty world path");
213 if(!gamespec.isValid())
214 throw ServerError("Supplied invalid gamespec");
216 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
217 if(m_simple_singleplayer_mode)
218 infostream<<" in simple singleplayer mode"<<std::endl;
220 infostream<<std::endl;
221 infostream<<"- world: "<<m_path_world<<std::endl;
222 infostream<<"- game: "<<m_gamespec.path<<std::endl;
224 // Create world if it doesn't exist
225 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
226 throw ServerError("Failed to initialize world");
228 // Create server thread
229 m_thread = new ServerThread(this);
231 // Create emerge manager
232 m_emerge = new EmergeManager(this);
234 // Create ban manager
235 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
236 m_banmanager = new BanManager(ban_path);
238 ModConfiguration modconf(m_path_world);
239 m_mods = modconf.getMods();
240 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
241 // complain about mods with unsatisfied dependencies
242 if(!modconf.isConsistent())
244 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
245 it != unsatisfied_mods.end(); ++it)
248 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
249 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
250 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
251 errorstream << " \"" << *dep_it << "\"";
252 errorstream << std::endl;
256 Settings worldmt_settings;
257 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
258 worldmt_settings.readConfigFile(worldmt.c_str());
259 std::vector<std::string> names = worldmt_settings.getNames();
260 std::set<std::string> load_mod_names;
261 for(std::vector<std::string>::iterator it = names.begin();
262 it != names.end(); ++it)
264 std::string name = *it;
265 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
266 load_mod_names.insert(name.substr(9));
268 // complain about mods declared to be loaded, but not found
269 for(std::vector<ModSpec>::iterator it = m_mods.begin();
270 it != m_mods.end(); ++it)
271 load_mod_names.erase((*it).name);
272 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
273 it != unsatisfied_mods.end(); ++it)
274 load_mod_names.erase((*it).name);
275 if(!load_mod_names.empty())
277 errorstream << "The following mods could not be found:";
278 for(std::set<std::string>::iterator it = load_mod_names.begin();
279 it != load_mod_names.end(); ++it)
280 errorstream << " \"" << (*it) << "\"";
281 errorstream << std::endl;
285 JMutexAutoLock envlock(m_env_mutex);
287 // Load mapgen params from Settings
288 m_emerge->loadMapgenParams();
290 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
291 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
293 // Initialize scripting
294 infostream<<"Server: Initializing Lua"<<std::endl;
296 m_script = new GameScripting(this);
298 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
300 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME)) {
301 throw ModError("Failed to load and run " + script_path);
305 infostream << "Server: Loading mods: ";
306 for(std::vector<ModSpec>::iterator i = m_mods.begin();
307 i != m_mods.end(); i++){
308 const ModSpec &mod = *i;
309 infostream << mod.name << " ";
311 infostream << std::endl;
312 // Load and run "mod" scripts
313 for (std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++) {
315 const ModSpec &mod = *i;
316 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
317 errorstream << "Error loading mod \"" << mod.name
318 << "\": mod_name does not follow naming conventions: "
319 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
320 throw ModError("Mod \"" + mod.name + "\" does not follow naming conventions.");
322 std::string script_path = mod.path + DIR_DELIM "init.lua";
323 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
324 << script_path << "\"]" << std::endl;
325 if (!m_script->loadMod(script_path, mod.name)) {
326 errorstream << "Server: Failed to load and run "
327 << script_path << std::endl;
328 throw ModError("Failed to load and run " + script_path);
332 // Read Textures and calculate sha1 sums
335 // Apply item aliases in the node definition manager
336 m_nodedef->updateAliases(m_itemdef);
338 m_nodedef->setNodeRegistrationStatus(true);
340 // Perform pending node name resolutions
341 m_nodedef->runNodeResolveCallbacks();
343 // init the recipe hashes to speed up crafting
344 m_craftdef->initHashes(this);
346 // Initialize Environment
347 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
349 m_clients.setEnv(m_env);
351 // Initialize mapgens
352 m_emerge->initMapgens();
354 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
355 if (m_enable_rollback_recording) {
356 // Create rollback manager
357 m_rollback = new RollbackManager(m_path_world, this);
360 // Give environment reference to scripting api
361 m_script->initializeEnvironment(m_env);
363 // Register us to receive map edit events
364 servermap->addEventReceiver(this);
366 // If file exists, load environment metadata
367 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
369 infostream<<"Server: Loading environment metadata"<<std::endl;
373 // Add some test ActiveBlockModifiers to environment
374 add_legacy_abms(m_env, m_nodedef);
376 m_liquid_transform_every = g_settings->getFloat("liquid_update");
381 infostream<<"Server destructing"<<std::endl;
383 // Send shutdown message
384 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
387 JMutexAutoLock envlock(m_env_mutex);
389 // Execute script shutdown hooks
390 m_script->on_shutdown();
392 infostream<<"Server: Saving players"<<std::endl;
393 m_env->saveLoadedPlayers();
395 infostream<<"Server: Saving environment metadata"<<std::endl;
403 // stop all emerge threads before deleting players that may have
404 // requested blocks to be emerged
405 m_emerge->stopThreads();
407 // Delete things in the reverse order of creation
410 // N.B. the EmergeManager should be deleted after the Environment since Map
411 // depends on EmergeManager to write its current params to the map meta
420 // Deinitialize scripting
421 infostream<<"Server: Deinitializing scripting"<<std::endl;
424 // Delete detached inventories
425 for (std::map<std::string, Inventory*>::iterator
426 i = m_detached_inventories.begin();
427 i != m_detached_inventories.end(); i++) {
432 void Server::start(Address bind_addr)
434 DSTACK(__FUNCTION_NAME);
436 m_bind_addr = bind_addr;
438 infostream<<"Starting server on "
439 << bind_addr.serializeString() <<"..."<<std::endl;
441 // Stop thread if already running
444 // Initialize connection
445 m_con.SetTimeoutMs(30);
446 m_con.Serve(bind_addr);
451 // ASCII art for the win!
453 <<" .__ __ __ "<<std::endl
454 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
455 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
456 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
457 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
458 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
459 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
460 actionstream<<"Server for gameid=\""<<m_gamespec.id
461 <<"\" listening on "<<bind_addr.serializeString()<<":"
462 <<bind_addr.getPort() << "."<<std::endl;
467 DSTACK(__FUNCTION_NAME);
469 infostream<<"Server: Stopping and waiting threads"<<std::endl;
471 // Stop threads (set run=false first so both start stopping)
473 //m_emergethread.setRun(false);
475 //m_emergethread.stop();
477 infostream<<"Server: Threads stopped"<<std::endl;
480 void Server::step(float dtime)
482 DSTACK(__FUNCTION_NAME);
487 JMutexAutoLock lock(m_step_dtime_mutex);
488 m_step_dtime += dtime;
490 // Throw if fatal error occurred in thread
491 std::string async_err = m_async_fatal_error.get();
492 if(async_err != "") {
493 if (m_simple_singleplayer_mode) {
494 throw ServerError(async_err);
497 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
498 << "Please fix the following error:" << std::endl
499 << async_err << std::endl;
500 FATAL_ERROR(async_err.c_str());
505 void Server::AsyncRunStep(bool initial_step)
507 DSTACK(__FUNCTION_NAME);
509 g_profiler->add("Server::AsyncRunStep (num)", 1);
513 JMutexAutoLock lock1(m_step_dtime_mutex);
514 dtime = m_step_dtime;
518 // Send blocks to clients
522 if((dtime < 0.001) && (initial_step == false))
525 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
527 //infostream<<"Server steps "<<dtime<<std::endl;
528 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
531 JMutexAutoLock lock1(m_step_dtime_mutex);
532 m_step_dtime -= dtime;
539 m_uptime.set(m_uptime.get() + dtime);
545 Update time of day and overall game time
547 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
550 Send to clients at constant intervals
553 m_time_of_day_send_timer -= dtime;
554 if(m_time_of_day_send_timer < 0.0) {
555 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
556 u16 time = m_env->getTimeOfDay();
557 float time_speed = g_settings->getFloat("time_speed");
558 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
562 JMutexAutoLock lock(m_env_mutex);
563 // Figure out and report maximum lag to environment
564 float max_lag = m_env->getMaxLagEstimate();
565 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
567 if(dtime > 0.1 && dtime > max_lag * 2.0)
568 infostream<<"Server: Maximum lag peaked to "<<dtime
572 m_env->reportMaxLagEstimate(max_lag);
574 ScopeProfiler sp(g_profiler, "SEnv step");
575 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
579 static const float map_timer_and_unload_dtime = 2.92;
580 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
582 JMutexAutoLock lock(m_env_mutex);
583 // Run Map's timers and unload unused data
584 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
585 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
586 g_settings->getFloat("server_unload_unused_data_timeout"));
593 /* Transform liquids */
594 m_liquid_transform_timer += dtime;
595 if(m_liquid_transform_timer >= m_liquid_transform_every)
597 m_liquid_transform_timer -= m_liquid_transform_every;
599 JMutexAutoLock lock(m_env_mutex);
601 ScopeProfiler sp(g_profiler, "Server: liquid transform");
603 std::map<v3s16, MapBlock*> modified_blocks;
604 m_env->getMap().transformLiquids(modified_blocks);
609 core::map<v3s16, MapBlock*> lighting_modified_blocks;
610 ServerMap &map = ((ServerMap&)m_env->getMap());
611 map.updateLighting(modified_blocks, lighting_modified_blocks);
613 // Add blocks modified by lighting to modified_blocks
614 for(core::map<v3s16, MapBlock*>::Iterator
615 i = lighting_modified_blocks.getIterator();
616 i.atEnd() == false; i++)
618 MapBlock *block = i.getNode()->getValue();
619 modified_blocks.insert(block->getPos(), block);
623 Set the modified blocks unsent for all the clients
625 if(!modified_blocks.empty())
627 SetBlocksNotSent(modified_blocks);
630 m_clients.step(dtime);
632 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
634 // send masterserver announce
636 float &counter = m_masterserver_timer;
637 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
638 g_settings->getBool("server_announce"))
640 ServerList::sendAnnounce(counter ? "update" : "start",
641 m_bind_addr.getPort(),
642 m_clients.getPlayerNames(),
644 m_env->getGameTime(),
647 m_emerge->params.mg_name,
656 Check added and deleted active objects
659 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
660 JMutexAutoLock envlock(m_env_mutex);
663 std::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 s16 radius = g_settings->getS16("active_object_send_range_blocks");
668 s16 player_radius = g_settings->getS16("player_transfer_distance");
670 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
671 !g_settings->getBool("unlimited_player_transfer_distance"))
672 player_radius = radius;
674 radius *= MAP_BLOCKSIZE;
675 player_radius *= MAP_BLOCKSIZE;
677 for(std::map<u16, RemoteClient*>::iterator
679 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 Player *player = m_env->getPlayer(client->peer_id);
691 // This can happen if the client timeouts somehow
692 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
694 <<" has no associated player"<<std::endl;*/
697 v3s16 pos = floatToInt(player->getPosition(), BS);
699 std::set<u16> removed_objects;
700 std::set<u16> added_objects;
701 m_env->getRemovedActiveObjects(pos, radius, player_radius,
702 client->m_known_objects, removed_objects);
703 m_env->getAddedActiveObjects(pos, radius, player_radius,
704 client->m_known_objects, added_objects);
706 // Ignore if nothing happened
707 if(removed_objects.empty() && added_objects.empty())
709 //infostream<<"active objects: none changed"<<std::endl;
713 std::string data_buffer;
717 // Handle removed objects
718 writeU16((u8*)buf, removed_objects.size());
719 data_buffer.append(buf, 2);
720 for(std::set<u16>::iterator
721 i = removed_objects.begin();
722 i != removed_objects.end(); ++i)
726 ServerActiveObject* obj = m_env->getActiveObject(id);
728 // Add to data buffer for sending
729 writeU16((u8*)buf, id);
730 data_buffer.append(buf, 2);
732 // Remove from known objects
733 client->m_known_objects.erase(id);
735 if(obj && obj->m_known_by_count > 0)
736 obj->m_known_by_count--;
739 // Handle added objects
740 writeU16((u8*)buf, added_objects.size());
741 data_buffer.append(buf, 2);
742 for(std::set<u16>::iterator
743 i = added_objects.begin();
744 i != added_objects.end(); ++i)
748 ServerActiveObject* obj = m_env->getActiveObject(id);
751 u8 type = ACTIVEOBJECT_TYPE_INVALID;
753 infostream<<"WARNING: "<<__FUNCTION_NAME
754 <<": NULL object"<<std::endl;
756 type = obj->getSendType();
758 // Add to data buffer for sending
759 writeU16((u8*)buf, id);
760 data_buffer.append(buf, 2);
761 writeU8((u8*)buf, type);
762 data_buffer.append(buf, 1);
765 data_buffer.append(serializeLongString(
766 obj->getClientInitializationData(client->net_proto_version)));
768 data_buffer.append(serializeLongString(""));
770 // Add to known objects
771 client->m_known_objects.insert(id);
774 obj->m_known_by_count++;
777 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
778 verbosestream << "Server: Sent object remove/add: "
779 << removed_objects.size() << " removed, "
780 << added_objects.size() << " added, "
781 << "packet size is " << pktSize << std::endl;
790 JMutexAutoLock envlock(m_env_mutex);
791 ScopeProfiler sp(g_profiler, "Server: sending object messages");
794 // Value = data sent by object
795 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
797 // Get active object messages from environment
799 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
803 std::vector<ActiveObjectMessage>* message_list = NULL;
804 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
805 n = buffered_messages.find(aom.id);
806 if (n == buffered_messages.end()) {
807 message_list = new std::vector<ActiveObjectMessage>;
808 buffered_messages[aom.id] = message_list;
811 message_list = n->second;
813 message_list->push_back(aom);
817 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
818 // Route data to every client
819 for (std::map<u16, RemoteClient*>::iterator
821 i != clients.end(); ++i) {
822 RemoteClient *client = i->second;
823 std::string reliable_data;
824 std::string unreliable_data;
825 // Go through all objects in message buffer
826 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
827 j = buffered_messages.begin();
828 j != buffered_messages.end(); ++j) {
829 // If object is not known by client, skip it
831 if (client->m_known_objects.find(id) == client->m_known_objects.end())
834 // Get message list of object
835 std::vector<ActiveObjectMessage>* list = j->second;
836 // Go through every message
837 for (std::vector<ActiveObjectMessage>::iterator
838 k = list->begin(); k != list->end(); ++k) {
839 // Compose the full new data with header
840 ActiveObjectMessage aom = *k;
841 std::string new_data;
844 writeU16((u8*)&buf[0], aom.id);
845 new_data.append(buf, 2);
847 new_data += serializeString(aom.datastring);
848 // Add data to buffer
850 reliable_data += new_data;
852 unreliable_data += new_data;
856 reliable_data and unreliable_data are now ready.
859 if(reliable_data.size() > 0) {
860 SendActiveObjectMessages(client->peer_id, reliable_data);
863 if(unreliable_data.size() > 0) {
864 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
869 // Clear buffered_messages
870 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
871 i = buffered_messages.begin();
872 i != buffered_messages.end(); ++i) {
878 Send queued-for-sending map edit events.
881 // We will be accessing the environment
882 JMutexAutoLock lock(m_env_mutex);
884 // Don't send too many at a time
887 // Single change sending is disabled if queue size is not small
888 bool disable_single_change_sending = false;
889 if(m_unsent_map_edit_queue.size() >= 4)
890 disable_single_change_sending = true;
892 int event_count = m_unsent_map_edit_queue.size();
894 // We'll log the amount of each
897 while(m_unsent_map_edit_queue.size() != 0)
899 MapEditEvent* event = m_unsent_map_edit_queue.front();
900 m_unsent_map_edit_queue.pop();
902 // Players far away from the change are stored here.
903 // Instead of sending the changes, MapBlocks are set not sent
905 std::vector<u16> far_players;
907 switch (event->type) {
910 prof.add("MEET_ADDNODE", 1);
911 sendAddNode(event->p, event->n, event->already_known_by_peer,
912 &far_players, disable_single_change_sending ? 5 : 30,
913 event->type == MEET_ADDNODE);
915 case MEET_REMOVENODE:
916 prof.add("MEET_REMOVENODE", 1);
917 sendRemoveNode(event->p, event->already_known_by_peer,
918 &far_players, disable_single_change_sending ? 5 : 30);
920 case MEET_BLOCK_NODE_METADATA_CHANGED:
921 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
922 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
923 setBlockNotSent(event->p);
926 infostream << "Server: MEET_OTHER" << std::endl;
927 prof.add("MEET_OTHER", 1);
928 for(std::set<v3s16>::iterator
929 i = event->modified_blocks.begin();
930 i != event->modified_blocks.end(); ++i) {
935 prof.add("unknown", 1);
936 infostream << "WARNING: Server: Unknown MapEditEvent "
937 << ((u32)event->type) << std::endl;
942 Set blocks not sent to far players
944 if(!far_players.empty()) {
945 // Convert list format to that wanted by SetBlocksNotSent
946 std::map<v3s16, MapBlock*> modified_blocks2;
947 for(std::set<v3s16>::iterator
948 i = event->modified_blocks.begin();
949 i != event->modified_blocks.end(); ++i) {
950 modified_blocks2[*i] =
951 m_env->getMap().getBlockNoCreateNoEx(*i);
954 // Set blocks not sent
955 for(std::vector<u16>::iterator
956 i = far_players.begin();
957 i != far_players.end(); ++i) {
958 if(RemoteClient *client = getClient(*i))
959 client->SetBlocksNotSent(modified_blocks2);
965 /*// Don't send too many at a time
967 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
971 if(event_count >= 5){
972 infostream<<"Server: MapEditEvents:"<<std::endl;
973 prof.print(infostream);
974 } else if(event_count != 0){
975 verbosestream<<"Server: MapEditEvents:"<<std::endl;
976 prof.print(verbosestream);
982 Trigger emergethread (it somehow gets to a non-triggered but
983 bysy state sometimes)
986 float &counter = m_emergethread_trigger_timer;
992 m_emerge->startThreads();
996 // Save map, players and auth stuff
998 float &counter = m_savemap_timer;
1000 if(counter >= g_settings->getFloat("server_map_save_interval"))
1003 JMutexAutoLock lock(m_env_mutex);
1005 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1008 if (m_banmanager->isModified()) {
1009 m_banmanager->save();
1012 // Save changed parts of map
1013 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1016 m_env->saveLoadedPlayers();
1018 // Save environment metadata
1024 void Server::Receive()
1026 DSTACK(__FUNCTION_NAME);
1027 SharedBuffer<u8> data;
1031 m_con.Receive(&pkt);
1032 peer_id = pkt.getPeerId();
1035 catch(con::InvalidIncomingDataException &e) {
1036 infostream<<"Server::Receive(): "
1037 "InvalidIncomingDataException: what()="
1038 <<e.what()<<std::endl;
1040 catch(SerializationError &e) {
1041 infostream<<"Server::Receive(): "
1042 "SerializationError: what()="
1043 <<e.what()<<std::endl;
1045 catch(ClientStateError &e) {
1046 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1047 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1048 L"Try reconnecting or updating your client");
1050 catch(con::PeerNotFoundException &e) {
1055 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1057 std::string playername = "";
1058 PlayerSAO *playersao = NULL;
1061 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1062 if (client != NULL) {
1063 playername = client->getName();
1064 playersao = emergePlayer(playername.c_str(), peer_id);
1066 } catch (std::exception &e) {
1072 RemotePlayer *player =
1073 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1075 // If failed, cancel
1076 if((playersao == NULL) || (player == NULL)) {
1077 if(player && player->peer_id != 0) {
1078 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1079 <<" (player allocated to an another client)"<<std::endl;
1080 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1081 L"name. If your client closed unexpectedly, try again in "
1084 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1086 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1092 Send complete position information
1094 SendMovePlayer(peer_id);
1097 SendPlayerPrivileges(peer_id);
1099 // Send inventory formspec
1100 SendPlayerInventoryFormspec(peer_id);
1103 SendInventory(playersao);
1106 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1109 SendPlayerBreath(peer_id);
1111 // Show death screen if necessary
1112 if(player->isDead())
1113 SendDeathscreen(peer_id, false, v3f(0,0,0));
1115 // Note things in chat if not in simple singleplayer mode
1116 if(!m_simple_singleplayer_mode) {
1117 // Send information about server to player in chat
1118 SendChatMessage(peer_id, getStatusString());
1120 // Send information about joining in chat
1122 std::wstring name = L"unknown";
1123 Player *player = m_env->getPlayer(peer_id);
1125 name = narrow_to_wide(player->getName());
1127 std::wstring message;
1130 message += L" joined the game.";
1131 SendChatMessage(PEER_ID_INEXISTENT,message);
1134 Address addr = getPeerAddress(player->peer_id);
1135 std::string ip_str = addr.serializeString();
1136 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1141 std::vector<std::string> names = m_clients.getPlayerNames();
1143 actionstream<<player->getName() <<" joins game. List of players: ";
1145 for (std::vector<std::string>::iterator i = names.begin();
1146 i != names.end(); i++) {
1147 actionstream << *i << " ";
1150 actionstream << player->getName() <<std::endl;
1155 inline void Server::handleCommand(NetworkPacket* pkt)
1157 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1158 (this->*opHandle.handler)(pkt);
1161 void Server::ProcessData(NetworkPacket *pkt)
1163 DSTACK(__FUNCTION_NAME);
1164 // Environment is locked first.
1165 JMutexAutoLock envlock(m_env_mutex);
1167 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1168 u32 peer_id = pkt->getPeerId();
1171 Address address = getPeerAddress(peer_id);
1172 std::string addr_s = address.serializeString();
1174 if(m_banmanager->isIpBanned(addr_s)) {
1175 std::string ban_name = m_banmanager->getBanName(addr_s);
1176 infostream << "Server: A banned client tried to connect from "
1177 << addr_s << "; banned name was "
1178 << ban_name << std::endl;
1179 // This actually doesn't seem to transfer to the client
1180 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1181 + narrow_to_wide(ban_name));
1185 catch(con::PeerNotFoundException &e) {
1187 * no peer for this packet found
1188 * most common reason is peer timeout, e.g. peer didn't
1189 * respond for some time, your server was overloaded or
1192 infostream << "Server::ProcessData(): Canceling: peer "
1193 << peer_id << " not found" << std::endl;
1198 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1200 // Command must be handled into ToServerCommandHandler
1201 if (command >= TOSERVER_NUM_MSG_TYPES) {
1202 infostream << "Server: Ignoring unknown command "
1203 << command << std::endl;
1206 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1211 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1213 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1214 errorstream << "Server::ProcessData(): Cancelling: Peer"
1215 " serialization format invalid or not initialized."
1216 " Skipping incoming command=" << command << std::endl;
1220 /* Handle commands related to client startup */
1221 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1226 if (m_clients.getClientState(peer_id) < CS_Active) {
1227 if (command == TOSERVER_PLAYERPOS) return;
1229 errorstream << "Got packet command: " << command << " for peer id "
1230 << peer_id << " but client isn't active yet. Dropping packet "
1236 } catch (SendFailedException &e) {
1237 errorstream << "Server::ProcessData(): SendFailedException: "
1238 << "what=" << e.what()
1240 } catch (PacketError &e) {
1241 actionstream << "Server::ProcessData(): PacketError: "
1242 << "what=" << e.what()
1247 void Server::setTimeOfDay(u32 time)
1249 m_env->setTimeOfDay(time);
1250 m_time_of_day_send_timer = 0;
1253 void Server::onMapEditEvent(MapEditEvent *event)
1255 if(m_ignore_map_edit_events)
1257 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1259 MapEditEvent *e = event->clone();
1260 m_unsent_map_edit_queue.push(e);
1263 Inventory* Server::getInventory(const InventoryLocation &loc)
1266 case InventoryLocation::UNDEFINED:
1267 case InventoryLocation::CURRENT_PLAYER:
1269 case InventoryLocation::PLAYER:
1271 Player *player = m_env->getPlayer(loc.name.c_str());
1274 PlayerSAO *playersao = player->getPlayerSAO();
1277 return playersao->getInventory();
1280 case InventoryLocation::NODEMETA:
1282 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1285 return meta->getInventory();
1288 case InventoryLocation::DETACHED:
1290 if(m_detached_inventories.count(loc.name) == 0)
1292 return m_detached_inventories[loc.name];
1296 sanity_check(false); // abort
1301 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1304 case InventoryLocation::UNDEFINED:
1306 case InventoryLocation::PLAYER:
1311 Player *player = m_env->getPlayer(loc.name.c_str());
1314 PlayerSAO *playersao = player->getPlayerSAO();
1318 SendInventory(playersao);
1321 case InventoryLocation::NODEMETA:
1323 v3s16 blockpos = getNodeBlockPos(loc.p);
1325 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1327 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1329 setBlockNotSent(blockpos);
1332 case InventoryLocation::DETACHED:
1334 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1338 sanity_check(false); // abort
1343 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1345 std::vector<u16> clients = m_clients.getClientIDs();
1347 // Set the modified blocks unsent for all the clients
1348 for (std::vector<u16>::iterator i = clients.begin();
1349 i != clients.end(); ++i) {
1350 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1351 client->SetBlocksNotSent(block);
1356 void Server::peerAdded(con::Peer *peer)
1358 DSTACK(__FUNCTION_NAME);
1359 verbosestream<<"Server::peerAdded(): peer->id="
1360 <<peer->id<<std::endl;
1363 c.type = con::PEER_ADDED;
1364 c.peer_id = peer->id;
1366 m_peer_change_queue.push(c);
1369 void Server::deletingPeer(con::Peer *peer, bool timeout)
1371 DSTACK(__FUNCTION_NAME);
1372 verbosestream<<"Server::deletingPeer(): peer->id="
1373 <<peer->id<<", timeout="<<timeout<<std::endl;
1375 m_clients.event(peer->id, CSE_Disconnect);
1377 c.type = con::PEER_REMOVED;
1378 c.peer_id = peer->id;
1379 c.timeout = timeout;
1380 m_peer_change_queue.push(c);
1383 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1385 *retval = m_con.getPeerStat(peer_id,type);
1386 if (*retval == -1) return false;
1390 bool Server::getClientInfo(
1399 std::string* vers_string
1402 *state = m_clients.getClientState(peer_id);
1404 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1406 if (client == NULL) {
1411 *uptime = client->uptime();
1412 *ser_vers = client->serialization_version;
1413 *prot_vers = client->net_proto_version;
1415 *major = client->getMajor();
1416 *minor = client->getMinor();
1417 *patch = client->getPatch();
1418 *vers_string = client->getPatch();
1425 void Server::handlePeerChanges()
1427 while(m_peer_change_queue.size() > 0)
1429 con::PeerChange c = m_peer_change_queue.front();
1430 m_peer_change_queue.pop();
1432 verbosestream<<"Server: Handling peer change: "
1433 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1438 case con::PEER_ADDED:
1439 m_clients.CreateClient(c.peer_id);
1442 case con::PEER_REMOVED:
1443 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1447 FATAL_ERROR("Invalid peer change event received!");
1453 void Server::Send(NetworkPacket* pkt)
1455 m_clients.send(pkt->getPeerId(),
1456 clientCommandFactoryTable[pkt->getCommand()].channel,
1458 clientCommandFactoryTable[pkt->getCommand()].reliable);
1461 void Server::SendMovement(u16 peer_id)
1463 DSTACK(__FUNCTION_NAME);
1464 std::ostringstream os(std::ios_base::binary);
1466 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1468 pkt << g_settings->getFloat("movement_acceleration_default");
1469 pkt << g_settings->getFloat("movement_acceleration_air");
1470 pkt << g_settings->getFloat("movement_acceleration_fast");
1471 pkt << g_settings->getFloat("movement_speed_walk");
1472 pkt << g_settings->getFloat("movement_speed_crouch");
1473 pkt << g_settings->getFloat("movement_speed_fast");
1474 pkt << g_settings->getFloat("movement_speed_climb");
1475 pkt << g_settings->getFloat("movement_speed_jump");
1476 pkt << g_settings->getFloat("movement_liquid_fluidity");
1477 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1478 pkt << g_settings->getFloat("movement_liquid_sink");
1479 pkt << g_settings->getFloat("movement_gravity");
1484 void Server::SendHP(u16 peer_id, u8 hp)
1486 DSTACK(__FUNCTION_NAME);
1488 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1493 void Server::SendBreath(u16 peer_id, u16 breath)
1495 DSTACK(__FUNCTION_NAME);
1497 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1498 pkt << (u16) breath;
1502 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1504 DSTACK(__FUNCTION_NAME);
1506 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1509 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1510 pkt << custom_reason;
1515 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1517 DSTACK(__FUNCTION_NAME);
1519 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1524 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1525 v3f camera_point_target)
1527 DSTACK(__FUNCTION_NAME);
1529 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1530 pkt << set_camera_point_target << camera_point_target;
1534 void Server::SendItemDef(u16 peer_id,
1535 IItemDefManager *itemdef, u16 protocol_version)
1537 DSTACK(__FUNCTION_NAME);
1539 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1543 u32 length of the next item
1544 zlib-compressed serialized ItemDefManager
1546 std::ostringstream tmp_os(std::ios::binary);
1547 itemdef->serialize(tmp_os, protocol_version);
1548 std::ostringstream tmp_os2(std::ios::binary);
1549 compressZlib(tmp_os.str(), tmp_os2);
1550 pkt.putLongString(tmp_os2.str());
1553 verbosestream << "Server: Sending item definitions to id(" << peer_id
1554 << "): size=" << pkt.getSize() << std::endl;
1559 void Server::SendNodeDef(u16 peer_id,
1560 INodeDefManager *nodedef, u16 protocol_version)
1562 DSTACK(__FUNCTION_NAME);
1564 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1568 u32 length of the next item
1569 zlib-compressed serialized NodeDefManager
1571 std::ostringstream tmp_os(std::ios::binary);
1572 nodedef->serialize(tmp_os, protocol_version);
1573 std::ostringstream tmp_os2(std::ios::binary);
1574 compressZlib(tmp_os.str(), tmp_os2);
1576 pkt.putLongString(tmp_os2.str());
1579 verbosestream << "Server: Sending node definitions to id(" << peer_id
1580 << "): size=" << pkt.getSize() << std::endl;
1586 Non-static send methods
1589 void Server::SendInventory(PlayerSAO* playerSAO)
1591 DSTACK(__FUNCTION_NAME);
1593 UpdateCrafting(playerSAO->getPlayer());
1599 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1601 std::ostringstream os;
1602 playerSAO->getInventory()->serialize(os);
1604 std::string s = os.str();
1606 pkt.putRawString(s.c_str(), s.size());
1610 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1612 DSTACK(__FUNCTION_NAME);
1614 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1617 if (peer_id != PEER_ID_INEXISTENT) {
1621 m_clients.sendToAll(0, &pkt, true);
1625 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1626 const std::string &formname)
1628 DSTACK(__FUNCTION_NAME);
1630 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1632 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1638 // Spawns a particle on peer with peer_id
1639 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1640 float expirationtime, float size, bool collisiondetection,
1641 bool vertical, std::string texture)
1643 DSTACK(__FUNCTION_NAME);
1645 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1647 pkt << pos << velocity << acceleration << expirationtime
1648 << size << collisiondetection;
1649 pkt.putLongString(texture);
1652 if (peer_id != PEER_ID_INEXISTENT) {
1656 m_clients.sendToAll(0, &pkt, true);
1660 // Adds a ParticleSpawner on peer with peer_id
1661 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1662 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1663 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1665 DSTACK(__FUNCTION_NAME);
1667 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1669 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1670 << minacc << maxacc << minexptime << maxexptime << minsize
1671 << maxsize << collisiondetection;
1673 pkt.putLongString(texture);
1675 pkt << id << vertical;
1677 if (peer_id != PEER_ID_INEXISTENT) {
1681 m_clients.sendToAll(0, &pkt, true);
1685 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1687 DSTACK(__FUNCTION_NAME);
1689 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1691 // Ugly error in this packet
1694 if (peer_id != PEER_ID_INEXISTENT) {
1698 m_clients.sendToAll(0, &pkt, true);
1703 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1705 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1707 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1708 << form->text << form->number << form->item << form->dir
1709 << form->align << form->offset << form->world_pos << form->size;
1714 void Server::SendHUDRemove(u16 peer_id, u32 id)
1716 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1721 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1723 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1724 pkt << id << (u8) stat;
1728 case HUD_STAT_SCALE:
1729 case HUD_STAT_ALIGN:
1730 case HUD_STAT_OFFSET:
1731 pkt << *(v2f *) value;
1735 pkt << *(std::string *) value;
1737 case HUD_STAT_WORLD_POS:
1738 pkt << *(v3f *) value;
1741 pkt << *(v2s32 *) value;
1743 case HUD_STAT_NUMBER:
1747 pkt << *(u32 *) value;
1754 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1756 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1758 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1760 pkt << flags << mask;
1765 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1767 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1768 pkt << param << value;
1772 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1773 const std::string &type, const std::vector<std::string> ¶ms)
1775 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1776 pkt << bgcolor << type << (u16) params.size();
1778 for(size_t i=0; i<params.size(); i++)
1784 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1787 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1790 pkt << do_override << (u16) (ratio * 65535);
1795 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1797 DSTACK(__FUNCTION_NAME);
1799 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1800 pkt << time << time_speed;
1802 if (peer_id == PEER_ID_INEXISTENT) {
1803 m_clients.sendToAll(0, &pkt, true);
1810 void Server::SendPlayerHP(u16 peer_id)
1812 DSTACK(__FUNCTION_NAME);
1813 PlayerSAO *playersao = getPlayerSAO(peer_id);
1814 // In some rare case, if the player is disconnected
1815 // while Lua call l_punch, for example, this can be NULL
1819 SendHP(peer_id, playersao->getHP());
1820 m_script->player_event(playersao,"health_changed");
1822 // Send to other clients
1823 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1824 ActiveObjectMessage aom(playersao->getId(), true, str);
1825 playersao->m_messages_out.push(aom);
1828 void Server::SendPlayerBreath(u16 peer_id)
1830 DSTACK(__FUNCTION_NAME);
1831 PlayerSAO *playersao = getPlayerSAO(peer_id);
1834 m_script->player_event(playersao, "breath_changed");
1835 SendBreath(peer_id, playersao->getBreath());
1838 void Server::SendMovePlayer(u16 peer_id)
1840 DSTACK(__FUNCTION_NAME);
1841 Player *player = m_env->getPlayer(peer_id);
1844 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1845 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1848 v3f pos = player->getPosition();
1849 f32 pitch = player->getPitch();
1850 f32 yaw = player->getYaw();
1851 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1852 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1853 << " pitch=" << pitch
1861 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1863 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1866 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1867 << animation_frames[3] << animation_speed;
1872 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1874 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1875 pkt << first << third;
1878 void Server::SendPlayerPrivileges(u16 peer_id)
1880 Player *player = m_env->getPlayer(peer_id);
1882 if(player->peer_id == PEER_ID_INEXISTENT)
1885 std::set<std::string> privs;
1886 m_script->getAuth(player->getName(), NULL, &privs);
1888 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1889 pkt << (u16) privs.size();
1891 for(std::set<std::string>::const_iterator i = privs.begin();
1892 i != privs.end(); i++) {
1899 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1901 Player *player = m_env->getPlayer(peer_id);
1903 if(player->peer_id == PEER_ID_INEXISTENT)
1906 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1907 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1911 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1913 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1914 pkt.putRawString(datas.c_str(), datas.size());
1916 return pkt.getSize();
1919 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1921 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1922 datas.size(), peer_id);
1924 pkt.putRawString(datas.c_str(), datas.size());
1926 m_clients.send(pkt.getPeerId(),
1927 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1932 s32 Server::playSound(const SimpleSoundSpec &spec,
1933 const ServerSoundParams ¶ms)
1935 // Find out initial position of sound
1936 bool pos_exists = false;
1937 v3f pos = params.getPos(m_env, &pos_exists);
1938 // If position is not found while it should be, cancel sound
1939 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1942 // Filter destination clients
1943 std::vector<u16> dst_clients;
1944 if(params.to_player != "")
1946 Player *player = m_env->getPlayer(params.to_player.c_str());
1948 infostream<<"Server::playSound: Player \""<<params.to_player
1949 <<"\" not found"<<std::endl;
1952 if(player->peer_id == PEER_ID_INEXISTENT){
1953 infostream<<"Server::playSound: Player \""<<params.to_player
1954 <<"\" not connected"<<std::endl;
1957 dst_clients.push_back(player->peer_id);
1960 std::vector<u16> clients = m_clients.getClientIDs();
1962 for(std::vector<u16>::iterator
1963 i = clients.begin(); i != clients.end(); ++i) {
1964 Player *player = m_env->getPlayer(*i);
1969 if(player->getPosition().getDistanceFrom(pos) >
1970 params.max_hear_distance)
1973 dst_clients.push_back(*i);
1977 if(dst_clients.empty())
1981 s32 id = m_next_sound_id++;
1982 // The sound will exist as a reference in m_playing_sounds
1983 m_playing_sounds[id] = ServerPlayingSound();
1984 ServerPlayingSound &psound = m_playing_sounds[id];
1985 psound.params = params;
1987 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1988 pkt << id << spec.name << (float) (spec.gain * params.gain)
1989 << (u8) params.type << pos << params.object << params.loop;
1991 for(std::vector<u16>::iterator i = dst_clients.begin();
1992 i != dst_clients.end(); i++) {
1993 psound.clients.insert(*i);
1994 m_clients.send(*i, 0, &pkt, true);
1998 void Server::stopSound(s32 handle)
2000 // Get sound reference
2001 std::map<s32, ServerPlayingSound>::iterator i =
2002 m_playing_sounds.find(handle);
2003 if(i == m_playing_sounds.end())
2005 ServerPlayingSound &psound = i->second;
2007 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2010 for(std::set<u16>::iterator i = psound.clients.begin();
2011 i != psound.clients.end(); i++) {
2013 m_clients.send(*i, 0, &pkt, true);
2015 // Remove sound reference
2016 m_playing_sounds.erase(i);
2019 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2020 std::vector<u16> *far_players, float far_d_nodes)
2022 float maxd = far_d_nodes*BS;
2023 v3f p_f = intToFloat(p, BS);
2025 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2028 std::vector<u16> clients = m_clients.getClientIDs();
2029 for(std::vector<u16>::iterator i = clients.begin();
2030 i != clients.end(); ++i) {
2033 if(Player *player = m_env->getPlayer(*i)) {
2034 // If player is far away, only set modified blocks not sent
2035 v3f player_pos = player->getPosition();
2036 if(player_pos.getDistanceFrom(p_f) > maxd) {
2037 far_players->push_back(*i);
2044 m_clients.send(*i, 0, &pkt, true);
2048 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2049 std::vector<u16> *far_players, float far_d_nodes,
2050 bool remove_metadata)
2052 float maxd = far_d_nodes*BS;
2053 v3f p_f = intToFloat(p, BS);
2055 std::vector<u16> clients = m_clients.getClientIDs();
2056 for(std::vector<u16>::iterator i = clients.begin();
2057 i != clients.end(); ++i) {
2061 if(Player *player = m_env->getPlayer(*i)) {
2062 // If player is far away, only set modified blocks not sent
2063 v3f player_pos = player->getPosition();
2064 if(player_pos.getDistanceFrom(p_f) > maxd) {
2065 far_players->push_back(*i);
2071 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2073 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2075 pkt << p << n.param0 << n.param1 << n.param2
2076 << (u8) (remove_metadata ? 0 : 1);
2078 if (!remove_metadata) {
2079 if (client->net_proto_version <= 21) {
2080 // Old clients always clear metadata; fix it
2081 // by sending the full block again.
2082 client->SetBlockNotSent(p);
2089 if (pkt.getSize() > 0)
2090 m_clients.send(*i, 0, &pkt, true);
2094 void Server::setBlockNotSent(v3s16 p)
2096 std::vector<u16> clients = m_clients.getClientIDs();
2098 for(std::vector<u16>::iterator i = clients.begin();
2099 i != clients.end(); ++i) {
2100 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2101 client->SetBlockNotSent(p);
2106 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2108 DSTACK(__FUNCTION_NAME);
2110 v3s16 p = block->getPos();
2113 Create a packet with the block in the right format
2116 std::ostringstream os(std::ios_base::binary);
2117 block->serialize(os, ver, false);
2118 block->serializeNetworkSpecific(os, net_proto_version);
2119 std::string s = os.str();
2121 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2124 pkt.putRawString(s.c_str(), s.size());
2128 void Server::SendBlocks(float dtime)
2130 DSTACK(__FUNCTION_NAME);
2132 JMutexAutoLock envlock(m_env_mutex);
2133 //TODO check if one big lock could be faster then multiple small ones
2135 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2137 std::vector<PrioritySortedBlockTransfer> queue;
2139 s32 total_sending = 0;
2142 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2144 std::vector<u16> clients = m_clients.getClientIDs();
2147 for(std::vector<u16>::iterator i = clients.begin();
2148 i != clients.end(); ++i) {
2149 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2154 total_sending += client->SendingCount();
2155 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2161 // Lowest priority number comes first.
2162 // Lowest is most important.
2163 std::sort(queue.begin(), queue.end());
2166 for(u32 i=0; i<queue.size(); i++)
2168 //TODO: Calculate limit dynamically
2169 if(total_sending >= g_settings->getS32
2170 ("max_simultaneous_block_sends_server_total"))
2173 PrioritySortedBlockTransfer q = queue[i];
2175 MapBlock *block = NULL;
2178 block = m_env->getMap().getBlockNoCreate(q.pos);
2180 catch(InvalidPositionException &e)
2185 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2190 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2192 client->SentBlock(q.pos);
2198 void Server::fillMediaCache()
2200 DSTACK(__FUNCTION_NAME);
2202 infostream<<"Server: Calculating media file checksums"<<std::endl;
2204 // Collect all media file paths
2205 std::vector<std::string> paths;
2206 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2207 i != m_mods.end(); i++) {
2208 const ModSpec &mod = *i;
2209 paths.push_back(mod.path + DIR_DELIM + "textures");
2210 paths.push_back(mod.path + DIR_DELIM + "sounds");
2211 paths.push_back(mod.path + DIR_DELIM + "media");
2212 paths.push_back(mod.path + DIR_DELIM + "models");
2214 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2216 // Collect media file information from paths into cache
2217 for(std::vector<std::string>::iterator i = paths.begin();
2218 i != paths.end(); i++) {
2219 std::string mediapath = *i;
2220 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2221 for (u32 j = 0; j < dirlist.size(); j++) {
2222 if (dirlist[j].dir) // Ignode dirs
2224 std::string filename = dirlist[j].name;
2225 // If name contains illegal characters, ignore the file
2226 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2227 infostream<<"Server: ignoring illegal file name: \""
2228 << filename << "\"" << std::endl;
2231 // If name is not in a supported format, ignore it
2232 const char *supported_ext[] = {
2233 ".png", ".jpg", ".bmp", ".tga",
2234 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2236 ".x", ".b3d", ".md2", ".obj",
2239 if (removeStringEnd(filename, supported_ext) == ""){
2240 infostream << "Server: ignoring unsupported file extension: \""
2241 << filename << "\"" << std::endl;
2244 // Ok, attempt to load the file and add to cache
2245 std::string filepath = mediapath + DIR_DELIM + filename;
2247 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2249 errorstream << "Server::fillMediaCache(): Could not open \""
2250 << filename << "\" for reading" << std::endl;
2253 std::ostringstream tmp_os(std::ios_base::binary);
2257 fis.read(buf, 1024);
2258 std::streamsize len = fis.gcount();
2259 tmp_os.write(buf, len);
2268 errorstream<<"Server::fillMediaCache(): Failed to read \""
2269 << filename << "\"" << std::endl;
2272 if(tmp_os.str().length() == 0) {
2273 errorstream << "Server::fillMediaCache(): Empty file \""
2274 << filepath << "\"" << std::endl;
2279 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2281 unsigned char *digest = sha1.getDigest();
2282 std::string sha1_base64 = base64_encode(digest, 20);
2283 std::string sha1_hex = hex_encode((char*)digest, 20);
2287 m_media[filename] = MediaInfo(filepath, sha1_base64);
2288 verbosestream << "Server: " << sha1_hex << " is " << filename
2294 struct SendableMediaAnnouncement
2297 std::string sha1_digest;
2299 SendableMediaAnnouncement(const std::string &name_="",
2300 const std::string &sha1_digest_=""):
2302 sha1_digest(sha1_digest_)
2306 void Server::sendMediaAnnouncement(u16 peer_id)
2308 DSTACK(__FUNCTION_NAME);
2310 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2313 std::vector<SendableMediaAnnouncement> file_announcements;
2315 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2316 i != m_media.end(); i++){
2318 file_announcements.push_back(
2319 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2323 std::ostringstream os(std::ios_base::binary);
2325 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2326 pkt << (u16) file_announcements.size();
2328 for (std::vector<SendableMediaAnnouncement>::iterator
2329 j = file_announcements.begin();
2330 j != file_announcements.end(); ++j) {
2331 pkt << j->name << j->sha1_digest;
2334 pkt << g_settings->get("remote_media");
2338 struct SendableMedia
2344 SendableMedia(const std::string &name_="", const std::string &path_="",
2345 const std::string &data_=""):
2352 void Server::sendRequestedMedia(u16 peer_id,
2353 const std::vector<std::string> &tosend)
2355 DSTACK(__FUNCTION_NAME);
2357 verbosestream<<"Server::sendRequestedMedia(): "
2358 <<"Sending files to client"<<std::endl;
2362 // Put 5kB in one bunch (this is not accurate)
2363 u32 bytes_per_bunch = 5000;
2365 std::vector< std::vector<SendableMedia> > file_bunches;
2366 file_bunches.push_back(std::vector<SendableMedia>());
2368 u32 file_size_bunch_total = 0;
2370 for(std::vector<std::string>::const_iterator i = tosend.begin();
2371 i != tosend.end(); ++i) {
2372 const std::string &name = *i;
2374 if(m_media.find(name) == m_media.end()) {
2375 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2376 <<"unknown file \""<<(name)<<"\""<<std::endl;
2380 //TODO get path + name
2381 std::string tpath = m_media[name].path;
2384 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2385 if(fis.good() == false){
2386 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2387 <<tpath<<"\" for reading"<<std::endl;
2390 std::ostringstream tmp_os(std::ios_base::binary);
2394 fis.read(buf, 1024);
2395 std::streamsize len = fis.gcount();
2396 tmp_os.write(buf, len);
2397 file_size_bunch_total += len;
2406 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2407 <<name<<"\""<<std::endl;
2410 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2411 <<tname<<"\""<<std::endl;*/
2413 file_bunches[file_bunches.size()-1].push_back(
2414 SendableMedia(name, tpath, tmp_os.str()));
2416 // Start next bunch if got enough data
2417 if(file_size_bunch_total >= bytes_per_bunch) {
2418 file_bunches.push_back(std::vector<SendableMedia>());
2419 file_size_bunch_total = 0;
2424 /* Create and send packets */
2426 u16 num_bunches = file_bunches.size();
2427 for(u16 i = 0; i < num_bunches; i++) {
2430 u16 total number of texture bunches
2431 u16 index of this bunch
2432 u32 number of files in this bunch
2441 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2442 pkt << num_bunches << i << (u32) file_bunches[i].size();
2444 for(std::vector<SendableMedia>::iterator
2445 j = file_bunches[i].begin();
2446 j != file_bunches[i].end(); ++j) {
2448 pkt.putLongString(j->data);
2451 verbosestream << "Server::sendRequestedMedia(): bunch "
2452 << i << "/" << num_bunches
2453 << " files=" << file_bunches[i].size()
2454 << " size=" << pkt.getSize() << std::endl;
2459 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2461 if(m_detached_inventories.count(name) == 0) {
2462 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2465 Inventory *inv = m_detached_inventories[name];
2466 std::ostringstream os(std::ios_base::binary);
2468 os << serializeString(name);
2472 std::string s = os.str();
2474 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2475 pkt.putRawString(s.c_str(), s.size());
2477 if (peer_id != PEER_ID_INEXISTENT) {
2481 m_clients.sendToAll(0, &pkt, true);
2485 void Server::sendDetachedInventories(u16 peer_id)
2487 DSTACK(__FUNCTION_NAME);
2489 for(std::map<std::string, Inventory*>::iterator
2490 i = m_detached_inventories.begin();
2491 i != m_detached_inventories.end(); i++) {
2492 const std::string &name = i->first;
2493 //Inventory *inv = i->second;
2494 sendDetachedInventory(name, peer_id);
2502 void Server::DiePlayer(u16 peer_id)
2504 DSTACK(__FUNCTION_NAME);
2506 PlayerSAO *playersao = getPlayerSAO(peer_id);
2509 infostream << "Server::DiePlayer(): Player "
2510 << playersao->getPlayer()->getName()
2511 << " dies" << std::endl;
2513 playersao->setHP(0);
2515 // Trigger scripted stuff
2516 m_script->on_dieplayer(playersao);
2518 SendPlayerHP(peer_id);
2519 SendDeathscreen(peer_id, false, v3f(0,0,0));
2522 void Server::RespawnPlayer(u16 peer_id)
2524 DSTACK(__FUNCTION_NAME);
2526 PlayerSAO *playersao = getPlayerSAO(peer_id);
2529 infostream << "Server::RespawnPlayer(): Player "
2530 << playersao->getPlayer()->getName()
2531 << " respawns" << std::endl;
2533 playersao->setHP(PLAYER_MAX_HP);
2534 playersao->setBreath(PLAYER_MAX_BREATH);
2536 SendPlayerHP(peer_id);
2537 SendPlayerBreath(peer_id);
2539 bool repositioned = m_script->on_respawnplayer(playersao);
2541 v3f pos = findSpawnPos();
2542 // setPos will send the new position to client
2543 playersao->setPos(pos);
2546 void Server::DenySudoAccess(u16 peer_id)
2548 DSTACK(__FUNCTION_NAME);
2550 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2554 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2556 DSTACK(__FUNCTION_NAME);
2558 SendAccessDenied(peer_id, reason, custom_reason);
2559 m_clients.event(peer_id, CSE_SetDenied);
2560 m_con.DisconnectPeer(peer_id);
2563 // 13/03/15: remove this function when protocol version 25 will become
2564 // the minimum version for MT users, maybe in 1 year
2565 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2567 DSTACK(__FUNCTION_NAME);
2569 SendAccessDenied_Legacy(peer_id, reason);
2570 m_clients.event(peer_id, CSE_SetDenied);
2571 m_con.DisconnectPeer(peer_id);
2574 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2576 DSTACK(__FUNCTION_NAME);
2579 RemoteClient* client = getClient(peer_id, CS_Invalid);
2581 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2583 // Right now, the auth mechs don't change between login and sudo mode.
2584 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2585 client->allowed_sudo_mechs = sudo_auth_mechs;
2587 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2588 << g_settings->getFloat("dedicated_server_step")
2592 m_clients.event(peer_id, CSE_AuthAccept);
2594 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2596 // We only support SRP right now
2597 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2599 resp_pkt << sudo_auth_mechs;
2601 m_clients.event(peer_id, CSE_SudoSuccess);
2605 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2607 DSTACK(__FUNCTION_NAME);
2608 std::wstring message;
2611 Clear references to playing sounds
2613 for(std::map<s32, ServerPlayingSound>::iterator
2614 i = m_playing_sounds.begin();
2615 i != m_playing_sounds.end();)
2617 ServerPlayingSound &psound = i->second;
2618 psound.clients.erase(peer_id);
2619 if(psound.clients.empty())
2620 m_playing_sounds.erase(i++);
2625 Player *player = m_env->getPlayer(peer_id);
2627 // Collect information about leaving in chat
2629 if(player != NULL && reason != CDR_DENY)
2631 std::wstring name = narrow_to_wide(player->getName());
2634 message += L" left the game.";
2635 if(reason == CDR_TIMEOUT)
2636 message += L" (timed out)";
2640 /* Run scripts and remove from environment */
2644 PlayerSAO *playersao = player->getPlayerSAO();
2647 m_script->on_leaveplayer(playersao);
2649 playersao->disconnected();
2657 if(player != NULL && reason != CDR_DENY) {
2658 std::ostringstream os(std::ios_base::binary);
2659 std::vector<u16> clients = m_clients.getClientIDs();
2661 for(std::vector<u16>::iterator i = clients.begin();
2662 i != clients.end(); ++i) {
2664 Player *player = m_env->getPlayer(*i);
2668 // Get name of player
2669 os << player->getName() << " ";
2672 actionstream << player->getName() << " "
2673 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2674 << " List of players: " << os.str() << std::endl;
2678 JMutexAutoLock env_lock(m_env_mutex);
2679 m_clients.DeleteClient(peer_id);
2683 // Send leave chat message to all remaining clients
2684 if(message.length() != 0)
2685 SendChatMessage(PEER_ID_INEXISTENT,message);
2688 void Server::UpdateCrafting(Player* player)
2690 DSTACK(__FUNCTION_NAME);
2692 // Get a preview for crafting
2694 InventoryLocation loc;
2695 loc.setPlayer(player->getName());
2696 getCraftingResult(&player->inventory, preview, false, this);
2697 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2699 // Put the new preview in
2700 InventoryList *plist = player->inventory.getList("craftpreview");
2701 sanity_check(plist);
2702 sanity_check(plist->getSize() >= 1);
2703 plist->changeItem(0, preview);
2706 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2708 RemoteClient *client = getClientNoEx(peer_id,state_min);
2710 throw ClientNotFoundException("Client not found");
2714 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2716 return m_clients.getClientNoEx(peer_id, state_min);
2719 std::string Server::getPlayerName(u16 peer_id)
2721 Player *player = m_env->getPlayer(peer_id);
2723 return "[id="+itos(peer_id)+"]";
2724 return player->getName();
2727 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2729 Player *player = m_env->getPlayer(peer_id);
2732 return player->getPlayerSAO();
2735 std::wstring Server::getStatusString()
2737 std::wostringstream os(std::ios_base::binary);
2740 os<<L"version="<<narrow_to_wide(g_version_string);
2742 os<<L", uptime="<<m_uptime.get();
2744 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2745 // Information about clients
2748 std::vector<u16> clients = m_clients.getClientIDs();
2749 for(std::vector<u16>::iterator i = clients.begin();
2750 i != clients.end(); ++i) {
2752 Player *player = m_env->getPlayer(*i);
2753 // Get name of player
2754 std::wstring name = L"unknown";
2756 name = narrow_to_wide(player->getName());
2757 // Add name to information string
2765 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2766 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2767 if(g_settings->get("motd") != "")
2768 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2772 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2774 std::set<std::string> privs;
2775 m_script->getAuth(name, NULL, &privs);
2779 bool Server::checkPriv(const std::string &name, const std::string &priv)
2781 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2782 return (privs.count(priv) != 0);
2785 void Server::reportPrivsModified(const std::string &name)
2788 std::vector<u16> clients = m_clients.getClientIDs();
2789 for(std::vector<u16>::iterator i = clients.begin();
2790 i != clients.end(); ++i) {
2791 Player *player = m_env->getPlayer(*i);
2792 reportPrivsModified(player->getName());
2795 Player *player = m_env->getPlayer(name.c_str());
2798 SendPlayerPrivileges(player->peer_id);
2799 PlayerSAO *sao = player->getPlayerSAO();
2802 sao->updatePrivileges(
2803 getPlayerEffectivePrivs(name),
2808 void Server::reportInventoryFormspecModified(const std::string &name)
2810 Player *player = m_env->getPlayer(name.c_str());
2813 SendPlayerInventoryFormspec(player->peer_id);
2816 void Server::setIpBanned(const std::string &ip, const std::string &name)
2818 m_banmanager->add(ip, name);
2821 void Server::unsetIpBanned(const std::string &ip_or_name)
2823 m_banmanager->remove(ip_or_name);
2826 std::string Server::getBanDescription(const std::string &ip_or_name)
2828 return m_banmanager->getBanDescription(ip_or_name);
2831 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2833 Player *player = m_env->getPlayer(name);
2837 if (player->peer_id == PEER_ID_INEXISTENT)
2840 SendChatMessage(player->peer_id, msg);
2843 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2845 Player *player = m_env->getPlayer(playername);
2849 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2853 SendShowFormspecMessage(player->peer_id, formspec, formname);
2857 u32 Server::hudAdd(Player *player, HudElement *form) {
2861 u32 id = player->addHud(form);
2863 SendHUDAdd(player->peer_id, id, form);
2868 bool Server::hudRemove(Player *player, u32 id) {
2872 HudElement* todel = player->removeHud(id);
2879 SendHUDRemove(player->peer_id, id);
2883 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2887 SendHUDChange(player->peer_id, id, stat, data);
2891 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2895 SendHUDSetFlags(player->peer_id, flags, mask);
2896 player->hud_flags = flags;
2898 PlayerSAO* playersao = player->getPlayerSAO();
2900 if (playersao == NULL)
2903 m_script->player_event(playersao, "hud_changed");
2907 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2910 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2913 std::ostringstream os(std::ios::binary);
2914 writeS32(os, hotbar_itemcount);
2915 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2919 void Server::hudSetHotbarImage(Player *player, std::string name) {
2923 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2926 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2930 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2933 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2938 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2942 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2947 SendEyeOffset(player->peer_id, first, third);
2951 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2952 const std::string &type, const std::vector<std::string> ¶ms)
2957 SendSetSky(player->peer_id, bgcolor, type, params);
2961 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2967 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2971 void Server::notifyPlayers(const std::wstring &msg)
2973 SendChatMessage(PEER_ID_INEXISTENT,msg);
2976 void Server::spawnParticle(const char *playername, v3f pos,
2977 v3f velocity, v3f acceleration,
2978 float expirationtime, float size, bool
2979 collisiondetection, bool vertical, std::string texture)
2981 Player *player = m_env->getPlayer(playername);
2984 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2985 expirationtime, size, collisiondetection, vertical, texture);
2988 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2989 float expirationtime, float size,
2990 bool collisiondetection, bool vertical, std::string texture)
2992 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2993 expirationtime, size, collisiondetection, vertical, texture);
2996 u32 Server::addParticleSpawner(const char *playername,
2997 u16 amount, float spawntime,
2998 v3f minpos, v3f maxpos,
2999 v3f minvel, v3f maxvel,
3000 v3f minacc, v3f maxacc,
3001 float minexptime, float maxexptime,
3002 float minsize, float maxsize,
3003 bool collisiondetection, bool vertical, std::string texture)
3005 Player *player = m_env->getPlayer(playername);
3010 for(;;) // look for unused particlespawner id
3013 if (std::find(m_particlespawner_ids.begin(),
3014 m_particlespawner_ids.end(), id)
3015 == m_particlespawner_ids.end())
3017 m_particlespawner_ids.push_back(id);
3022 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3023 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3024 minexptime, maxexptime, minsize, maxsize,
3025 collisiondetection, vertical, texture, id);
3030 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3031 v3f minpos, v3f maxpos,
3032 v3f minvel, v3f maxvel,
3033 v3f minacc, v3f maxacc,
3034 float minexptime, float maxexptime,
3035 float minsize, float maxsize,
3036 bool collisiondetection, bool vertical, std::string texture)
3039 for(;;) // look for unused particlespawner id
3042 if (std::find(m_particlespawner_ids.begin(),
3043 m_particlespawner_ids.end(), id)
3044 == m_particlespawner_ids.end())
3046 m_particlespawner_ids.push_back(id);
3051 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3052 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3053 minexptime, maxexptime, minsize, maxsize,
3054 collisiondetection, vertical, texture, id);
3059 void Server::deleteParticleSpawner(const char *playername, u32 id)
3061 Player *player = m_env->getPlayer(playername);
3065 m_particlespawner_ids.erase(
3066 std::remove(m_particlespawner_ids.begin(),
3067 m_particlespawner_ids.end(), id),
3068 m_particlespawner_ids.end());
3069 SendDeleteParticleSpawner(player->peer_id, id);
3072 void Server::deleteParticleSpawnerAll(u32 id)
3074 m_particlespawner_ids.erase(
3075 std::remove(m_particlespawner_ids.begin(),
3076 m_particlespawner_ids.end(), id),
3077 m_particlespawner_ids.end());
3078 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3081 Inventory* Server::createDetachedInventory(const std::string &name)
3083 if(m_detached_inventories.count(name) > 0){
3084 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3085 delete m_detached_inventories[name];
3087 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3089 Inventory *inv = new Inventory(m_itemdef);
3091 m_detached_inventories[name] = inv;
3092 //TODO find a better way to do this
3093 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3100 BoolScopeSet(bool *dst, bool val):
3103 m_orig_state = *m_dst;
3108 *m_dst = m_orig_state;
3115 // actions: time-reversed list
3116 // Return value: success/failure
3117 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3118 std::list<std::string> *log)
3120 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3121 ServerMap *map = (ServerMap*)(&m_env->getMap());
3123 // Fail if no actions to handle
3124 if(actions.empty()){
3125 log->push_back("Nothing to do.");
3132 for(std::list<RollbackAction>::const_iterator
3133 i = actions.begin();
3134 i != actions.end(); i++)
3136 const RollbackAction &action = *i;
3138 bool success = action.applyRevert(map, this, this);
3141 std::ostringstream os;
3142 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3143 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3145 log->push_back(os.str());
3147 std::ostringstream os;
3148 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3149 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3151 log->push_back(os.str());
3155 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3156 <<" failed"<<std::endl;
3158 // Call it done if less than half failed
3159 return num_failed <= num_tried/2;
3162 // IGameDef interface
3164 IItemDefManager* Server::getItemDefManager()
3168 INodeDefManager* Server::getNodeDefManager()
3172 ICraftDefManager* Server::getCraftDefManager()
3176 ITextureSource* Server::getTextureSource()
3180 IShaderSource* Server::getShaderSource()
3184 scene::ISceneManager* Server::getSceneManager()
3189 u16 Server::allocateUnknownNodeId(const std::string &name)
3191 return m_nodedef->allocateDummy(name);
3193 ISoundManager* Server::getSoundManager()
3195 return &dummySoundManager;
3197 MtEventManager* Server::getEventManager()
3202 IWritableItemDefManager* Server::getWritableItemDefManager()
3206 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3210 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3215 const ModSpec* Server::getModSpec(const std::string &modname) const
3217 for(std::vector<ModSpec>::const_iterator i = m_mods.begin();
3218 i != m_mods.end(); i++){
3219 const ModSpec &mod = *i;
3220 if(mod.name == modname)
3225 void Server::getModNames(std::vector<std::string> &modlist)
3227 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3228 modlist.push_back(i->name);
3231 std::string Server::getBuiltinLuaPath()
3233 return porting::path_share + DIR_DELIM + "builtin";
3236 v3f Server::findSpawnPos()
3238 ServerMap &map = m_env->getServerMap();
3240 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3241 return nodeposf * BS;
3244 // Default position is static_spawnpoint
3245 // We will return it if we don't found a good place
3246 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3248 s16 water_level = map.getWaterLevel();
3250 bool is_good = false;
3252 // Try to find a good place a few times
3253 for(s32 i = 0; i < 1000 && !is_good; i++) {
3255 // We're going to try to throw the player to this position
3256 v2s16 nodepos2d = v2s16(
3257 -range + (myrand() % (range * 2)),
3258 -range + (myrand() % (range * 2)));
3260 // Get ground height at point
3261 s16 groundheight = map.findGroundLevel(nodepos2d);
3262 if (groundheight <= water_level) // Don't go underwater
3264 if (groundheight > water_level + 6) // Don't go to high places
3267 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3270 for (s32 i = 0; i < 10; i++) {
3271 v3s16 blockpos = getNodeBlockPos(nodepos);
3272 map.emergeBlock(blockpos, true);
3273 content_t c = map.getNodeNoEx(nodepos).getContent();
3274 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3276 if (air_count >= 2){
3285 return intToFloat(nodepos, BS);
3288 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3290 bool newplayer = false;
3293 Try to get an existing player
3295 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3297 // If player is already connected, cancel
3298 if(player != NULL && player->peer_id != 0)
3300 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3305 If player with the wanted peer_id already exists, cancel.
3307 if(m_env->getPlayer(peer_id) != NULL)
3309 infostream<<"emergePlayer(): Player with wrong name but same"
3310 " peer_id already exists"<<std::endl;
3314 // Load player if it isn't already loaded
3316 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3319 // Create player if it doesn't exist
3322 player = new RemotePlayer(this, name);
3323 // Set player position
3324 infostream<<"Server: Finding spawn place for player \""
3325 <<name<<"\""<<std::endl;
3326 v3f pos = findSpawnPos();
3327 player->setPosition(pos);
3329 // Make sure the player is saved
3330 player->setModified(true);
3332 // Add player to environment
3333 m_env->addPlayer(player);
3336 // Create a new player active object
3337 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3338 getPlayerEffectivePrivs(player->getName()),
3341 /* Clean up old HUD elements from previous sessions */
3344 /* Add object to environment */
3345 m_env->addActiveObject(playersao);
3349 m_script->on_newplayer(playersao);
3355 void dedicated_server_loop(Server &server, bool &kill)
3357 DSTACK(__FUNCTION_NAME);
3359 verbosestream<<"dedicated_server_loop()"<<std::endl;
3361 IntervalLimiter m_profiler_interval;
3365 float steplen = g_settings->getFloat("dedicated_server_step");
3366 // This is kind of a hack but can be done like this
3367 // because server.step() is very light
3369 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3370 sleep_ms((int)(steplen*1000.0));
3372 server.step(steplen);
3374 if(server.getShutdownRequested() || kill)
3376 infostream<<"Dedicated server quitting"<<std::endl;
3378 if(g_settings->getBool("server_announce"))
3379 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3387 float profiler_print_interval =
3388 g_settings->getFloat("profiler_print_interval");
3389 if(profiler_print_interval != 0)
3391 if(m_profiler_interval.step(steplen, profiler_print_interval))
3393 infostream<<"Profiler:"<<std::endl;
3394 g_profiler->print(infostream);
3395 g_profiler->clear();