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 scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
300 if (!m_script->loadScript(scriptpath))
301 throw ModError("Failed to load and run " + scriptpath);
304 infostream<<"Server: Loading mods: ";
305 for(std::vector<ModSpec>::iterator i = m_mods.begin();
306 i != m_mods.end(); i++){
307 const ModSpec &mod = *i;
308 infostream<<mod.name<<" ";
310 infostream<<std::endl;
311 // Load and run "mod" scripts
312 for(std::vector<ModSpec>::iterator i = m_mods.begin();
313 i != m_mods.end(); i++){
314 const ModSpec &mod = *i;
315 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
316 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
317 <<scriptpath<<"\"]"<<std::endl;
318 bool success = m_script->loadMod(scriptpath, mod.name);
320 errorstream<<"Server: Failed to load and run "
321 <<scriptpath<<std::endl;
322 throw ModError("Failed to load and run "+scriptpath);
326 // Read Textures and calculate sha1 sums
329 // Apply item aliases in the node definition manager
330 m_nodedef->updateAliases(m_itemdef);
332 m_nodedef->setNodeRegistrationStatus(true);
334 // Perform pending node name resolutions
335 m_nodedef->runNodeResolveCallbacks();
337 // init the recipe hashes to speed up crafting
338 m_craftdef->initHashes(this);
340 // Initialize Environment
341 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
343 m_clients.setEnv(m_env);
345 // Initialize mapgens
346 m_emerge->initMapgens();
348 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
349 if (m_enable_rollback_recording) {
350 // Create rollback manager
351 m_rollback = new RollbackManager(m_path_world, this);
354 // Give environment reference to scripting api
355 m_script->initializeEnvironment(m_env);
357 // Register us to receive map edit events
358 servermap->addEventReceiver(this);
360 // If file exists, load environment metadata
361 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
363 infostream<<"Server: Loading environment metadata"<<std::endl;
367 // Add some test ActiveBlockModifiers to environment
368 add_legacy_abms(m_env, m_nodedef);
370 m_liquid_transform_every = g_settings->getFloat("liquid_update");
375 infostream<<"Server destructing"<<std::endl;
377 // Send shutdown message
378 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
381 JMutexAutoLock envlock(m_env_mutex);
383 // Execute script shutdown hooks
384 m_script->on_shutdown();
386 infostream<<"Server: Saving players"<<std::endl;
387 m_env->saveLoadedPlayers();
389 infostream<<"Server: Saving environment metadata"<<std::endl;
397 // stop all emerge threads before deleting players that may have
398 // requested blocks to be emerged
399 m_emerge->stopThreads();
401 // Delete things in the reverse order of creation
404 // N.B. the EmergeManager should be deleted after the Environment since Map
405 // depends on EmergeManager to write its current params to the map meta
414 // Deinitialize scripting
415 infostream<<"Server: Deinitializing scripting"<<std::endl;
418 // Delete detached inventories
419 for (std::map<std::string, Inventory*>::iterator
420 i = m_detached_inventories.begin();
421 i != m_detached_inventories.end(); i++) {
426 void Server::start(Address bind_addr)
428 DSTACK(__FUNCTION_NAME);
430 m_bind_addr = bind_addr;
432 infostream<<"Starting server on "
433 << bind_addr.serializeString() <<"..."<<std::endl;
435 // Stop thread if already running
438 // Initialize connection
439 m_con.SetTimeoutMs(30);
440 m_con.Serve(bind_addr);
445 // ASCII art for the win!
447 <<" .__ __ __ "<<std::endl
448 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
449 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
450 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
451 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
452 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
453 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
454 actionstream<<"Server for gameid=\""<<m_gamespec.id
455 <<"\" listening on "<<bind_addr.serializeString()<<":"
456 <<bind_addr.getPort() << "."<<std::endl;
461 DSTACK(__FUNCTION_NAME);
463 infostream<<"Server: Stopping and waiting threads"<<std::endl;
465 // Stop threads (set run=false first so both start stopping)
467 //m_emergethread.setRun(false);
469 //m_emergethread.stop();
471 infostream<<"Server: Threads stopped"<<std::endl;
474 void Server::step(float dtime)
476 DSTACK(__FUNCTION_NAME);
481 JMutexAutoLock lock(m_step_dtime_mutex);
482 m_step_dtime += dtime;
484 // Throw if fatal error occurred in thread
485 std::string async_err = m_async_fatal_error.get();
486 if(async_err != "") {
487 if (m_simple_singleplayer_mode) {
488 throw ServerError(async_err);
491 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
492 << "Please fix the following error:" << std::endl
493 << async_err << std::endl;
494 FATAL_ERROR(async_err.c_str());
499 void Server::AsyncRunStep(bool initial_step)
501 DSTACK(__FUNCTION_NAME);
503 g_profiler->add("Server::AsyncRunStep (num)", 1);
507 JMutexAutoLock lock1(m_step_dtime_mutex);
508 dtime = m_step_dtime;
512 // Send blocks to clients
516 if((dtime < 0.001) && (initial_step == false))
519 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
521 //infostream<<"Server steps "<<dtime<<std::endl;
522 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
525 JMutexAutoLock lock1(m_step_dtime_mutex);
526 m_step_dtime -= dtime;
533 m_uptime.set(m_uptime.get() + dtime);
539 Update time of day and overall game time
541 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
544 Send to clients at constant intervals
547 m_time_of_day_send_timer -= dtime;
548 if(m_time_of_day_send_timer < 0.0) {
549 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
550 u16 time = m_env->getTimeOfDay();
551 float time_speed = g_settings->getFloat("time_speed");
552 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
556 JMutexAutoLock lock(m_env_mutex);
557 // Figure out and report maximum lag to environment
558 float max_lag = m_env->getMaxLagEstimate();
559 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
561 if(dtime > 0.1 && dtime > max_lag * 2.0)
562 infostream<<"Server: Maximum lag peaked to "<<dtime
566 m_env->reportMaxLagEstimate(max_lag);
568 ScopeProfiler sp(g_profiler, "SEnv step");
569 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
573 static const float map_timer_and_unload_dtime = 2.92;
574 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
576 JMutexAutoLock lock(m_env_mutex);
577 // Run Map's timers and unload unused data
578 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
579 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
580 g_settings->getFloat("server_unload_unused_data_timeout"));
587 /* Transform liquids */
588 m_liquid_transform_timer += dtime;
589 if(m_liquid_transform_timer >= m_liquid_transform_every)
591 m_liquid_transform_timer -= m_liquid_transform_every;
593 JMutexAutoLock lock(m_env_mutex);
595 ScopeProfiler sp(g_profiler, "Server: liquid transform");
597 std::map<v3s16, MapBlock*> modified_blocks;
598 m_env->getMap().transformLiquids(modified_blocks);
603 core::map<v3s16, MapBlock*> lighting_modified_blocks;
604 ServerMap &map = ((ServerMap&)m_env->getMap());
605 map.updateLighting(modified_blocks, lighting_modified_blocks);
607 // Add blocks modified by lighting to modified_blocks
608 for(core::map<v3s16, MapBlock*>::Iterator
609 i = lighting_modified_blocks.getIterator();
610 i.atEnd() == false; i++)
612 MapBlock *block = i.getNode()->getValue();
613 modified_blocks.insert(block->getPos(), block);
617 Set the modified blocks unsent for all the clients
619 if(!modified_blocks.empty())
621 SetBlocksNotSent(modified_blocks);
624 m_clients.step(dtime);
626 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
628 // send masterserver announce
630 float &counter = m_masterserver_timer;
631 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
632 g_settings->getBool("server_announce"))
634 ServerList::sendAnnounce(counter ? "update" : "start",
635 m_bind_addr.getPort(),
636 m_clients.getPlayerNames(),
638 m_env->getGameTime(),
641 m_emerge->params.mg_name,
650 Check added and deleted active objects
653 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
654 JMutexAutoLock envlock(m_env_mutex);
657 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
658 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
660 // Radius inside which objects are active
661 s16 radius = g_settings->getS16("active_object_send_range_blocks");
662 s16 player_radius = g_settings->getS16("player_transfer_distance");
664 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
665 !g_settings->getBool("unlimited_player_transfer_distance"))
666 player_radius = radius;
668 radius *= MAP_BLOCKSIZE;
669 player_radius *= MAP_BLOCKSIZE;
671 for(std::map<u16, RemoteClient*>::iterator
673 i != clients.end(); ++i)
675 RemoteClient *client = i->second;
677 // If definitions and textures have not been sent, don't
678 // send objects either
679 if (client->getState() < CS_DefinitionsSent)
682 Player *player = m_env->getPlayer(client->peer_id);
685 // This can happen if the client timeouts somehow
686 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
688 <<" has no associated player"<<std::endl;*/
691 v3s16 pos = floatToInt(player->getPosition(), BS);
693 std::set<u16> removed_objects;
694 std::set<u16> added_objects;
695 m_env->getRemovedActiveObjects(pos, radius, player_radius,
696 client->m_known_objects, removed_objects);
697 m_env->getAddedActiveObjects(pos, radius, player_radius,
698 client->m_known_objects, added_objects);
700 // Ignore if nothing happened
701 if(removed_objects.empty() && added_objects.empty())
703 //infostream<<"active objects: none changed"<<std::endl;
707 std::string data_buffer;
711 // Handle removed objects
712 writeU16((u8*)buf, removed_objects.size());
713 data_buffer.append(buf, 2);
714 for(std::set<u16>::iterator
715 i = removed_objects.begin();
716 i != removed_objects.end(); ++i)
720 ServerActiveObject* obj = m_env->getActiveObject(id);
722 // Add to data buffer for sending
723 writeU16((u8*)buf, id);
724 data_buffer.append(buf, 2);
726 // Remove from known objects
727 client->m_known_objects.erase(id);
729 if(obj && obj->m_known_by_count > 0)
730 obj->m_known_by_count--;
733 // Handle added objects
734 writeU16((u8*)buf, added_objects.size());
735 data_buffer.append(buf, 2);
736 for(std::set<u16>::iterator
737 i = added_objects.begin();
738 i != added_objects.end(); ++i)
742 ServerActiveObject* obj = m_env->getActiveObject(id);
745 u8 type = ACTIVEOBJECT_TYPE_INVALID;
747 infostream<<"WARNING: "<<__FUNCTION_NAME
748 <<": NULL object"<<std::endl;
750 type = obj->getSendType();
752 // Add to data buffer for sending
753 writeU16((u8*)buf, id);
754 data_buffer.append(buf, 2);
755 writeU8((u8*)buf, type);
756 data_buffer.append(buf, 1);
759 data_buffer.append(serializeLongString(
760 obj->getClientInitializationData(client->net_proto_version)));
762 data_buffer.append(serializeLongString(""));
764 // Add to known objects
765 client->m_known_objects.insert(id);
768 obj->m_known_by_count++;
771 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
772 verbosestream << "Server: Sent object remove/add: "
773 << removed_objects.size() << " removed, "
774 << added_objects.size() << " added, "
775 << "packet size is " << pktSize << std::endl;
784 JMutexAutoLock envlock(m_env_mutex);
785 ScopeProfiler sp(g_profiler, "Server: sending object messages");
788 // Value = data sent by object
789 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
791 // Get active object messages from environment
793 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
797 std::vector<ActiveObjectMessage>* message_list = NULL;
798 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
799 n = buffered_messages.find(aom.id);
800 if (n == buffered_messages.end()) {
801 message_list = new std::vector<ActiveObjectMessage>;
802 buffered_messages[aom.id] = message_list;
805 message_list = n->second;
807 message_list->push_back(aom);
811 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
812 // Route data to every client
813 for (std::map<u16, RemoteClient*>::iterator
815 i != clients.end(); ++i) {
816 RemoteClient *client = i->second;
817 std::string reliable_data;
818 std::string unreliable_data;
819 // Go through all objects in message buffer
820 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
821 j = buffered_messages.begin();
822 j != buffered_messages.end(); ++j) {
823 // If object is not known by client, skip it
825 if (client->m_known_objects.find(id) == client->m_known_objects.end())
828 // Get message list of object
829 std::vector<ActiveObjectMessage>* list = j->second;
830 // Go through every message
831 for (std::vector<ActiveObjectMessage>::iterator
832 k = list->begin(); k != list->end(); ++k) {
833 // Compose the full new data with header
834 ActiveObjectMessage aom = *k;
835 std::string new_data;
838 writeU16((u8*)&buf[0], aom.id);
839 new_data.append(buf, 2);
841 new_data += serializeString(aom.datastring);
842 // Add data to buffer
844 reliable_data += new_data;
846 unreliable_data += new_data;
850 reliable_data and unreliable_data are now ready.
853 if(reliable_data.size() > 0) {
854 SendActiveObjectMessages(client->peer_id, reliable_data);
857 if(unreliable_data.size() > 0) {
858 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
863 // Clear buffered_messages
864 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
865 i = buffered_messages.begin();
866 i != buffered_messages.end(); ++i) {
872 Send queued-for-sending map edit events.
875 // We will be accessing the environment
876 JMutexAutoLock lock(m_env_mutex);
878 // Don't send too many at a time
881 // Single change sending is disabled if queue size is not small
882 bool disable_single_change_sending = false;
883 if(m_unsent_map_edit_queue.size() >= 4)
884 disable_single_change_sending = true;
886 int event_count = m_unsent_map_edit_queue.size();
888 // We'll log the amount of each
891 while(m_unsent_map_edit_queue.size() != 0)
893 MapEditEvent* event = m_unsent_map_edit_queue.front();
894 m_unsent_map_edit_queue.pop();
896 // Players far away from the change are stored here.
897 // Instead of sending the changes, MapBlocks are set not sent
899 std::vector<u16> far_players;
901 switch (event->type) {
904 prof.add("MEET_ADDNODE", 1);
905 sendAddNode(event->p, event->n, event->already_known_by_peer,
906 &far_players, disable_single_change_sending ? 5 : 30,
907 event->type == MEET_ADDNODE);
909 case MEET_REMOVENODE:
910 prof.add("MEET_REMOVENODE", 1);
911 sendRemoveNode(event->p, event->already_known_by_peer,
912 &far_players, disable_single_change_sending ? 5 : 30);
914 case MEET_BLOCK_NODE_METADATA_CHANGED:
915 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
916 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
917 setBlockNotSent(event->p);
920 infostream << "Server: MEET_OTHER" << std::endl;
921 prof.add("MEET_OTHER", 1);
922 for(std::set<v3s16>::iterator
923 i = event->modified_blocks.begin();
924 i != event->modified_blocks.end(); ++i) {
929 prof.add("unknown", 1);
930 infostream << "WARNING: Server: Unknown MapEditEvent "
931 << ((u32)event->type) << std::endl;
936 Set blocks not sent to far players
938 if(!far_players.empty()) {
939 // Convert list format to that wanted by SetBlocksNotSent
940 std::map<v3s16, MapBlock*> modified_blocks2;
941 for(std::set<v3s16>::iterator
942 i = event->modified_blocks.begin();
943 i != event->modified_blocks.end(); ++i) {
944 modified_blocks2[*i] =
945 m_env->getMap().getBlockNoCreateNoEx(*i);
948 // Set blocks not sent
949 for(std::vector<u16>::iterator
950 i = far_players.begin();
951 i != far_players.end(); ++i) {
952 if(RemoteClient *client = getClient(*i))
953 client->SetBlocksNotSent(modified_blocks2);
959 /*// Don't send too many at a time
961 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
965 if(event_count >= 5){
966 infostream<<"Server: MapEditEvents:"<<std::endl;
967 prof.print(infostream);
968 } else if(event_count != 0){
969 verbosestream<<"Server: MapEditEvents:"<<std::endl;
970 prof.print(verbosestream);
976 Trigger emergethread (it somehow gets to a non-triggered but
977 bysy state sometimes)
980 float &counter = m_emergethread_trigger_timer;
986 m_emerge->startThreads();
990 // Save map, players and auth stuff
992 float &counter = m_savemap_timer;
994 if(counter >= g_settings->getFloat("server_map_save_interval"))
997 JMutexAutoLock lock(m_env_mutex);
999 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1002 if (m_banmanager->isModified()) {
1003 m_banmanager->save();
1006 // Save changed parts of map
1007 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1010 m_env->saveLoadedPlayers();
1012 // Save environment metadata
1018 void Server::Receive()
1020 DSTACK(__FUNCTION_NAME);
1021 SharedBuffer<u8> data;
1025 m_con.Receive(&pkt);
1026 peer_id = pkt.getPeerId();
1029 catch(con::InvalidIncomingDataException &e) {
1030 infostream<<"Server::Receive(): "
1031 "InvalidIncomingDataException: what()="
1032 <<e.what()<<std::endl;
1034 catch(SerializationError &e) {
1035 infostream<<"Server::Receive(): "
1036 "SerializationError: what()="
1037 <<e.what()<<std::endl;
1039 catch(ClientStateError &e) {
1040 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1041 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1042 L"Try reconnecting or updating your client");
1044 catch(con::PeerNotFoundException &e) {
1049 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1051 std::string playername = "";
1052 PlayerSAO *playersao = NULL;
1055 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1056 if (client != NULL) {
1057 playername = client->getName();
1058 playersao = emergePlayer(playername.c_str(), peer_id);
1060 } catch (std::exception &e) {
1066 RemotePlayer *player =
1067 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1069 // If failed, cancel
1070 if((playersao == NULL) || (player == NULL)) {
1071 if(player && player->peer_id != 0) {
1072 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1073 <<" (player allocated to an another client)"<<std::endl;
1074 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1075 L"name. If your client closed unexpectedly, try again in "
1078 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1080 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1086 Send complete position information
1088 SendMovePlayer(peer_id);
1091 SendPlayerPrivileges(peer_id);
1093 // Send inventory formspec
1094 SendPlayerInventoryFormspec(peer_id);
1097 SendInventory(playersao);
1100 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1103 SendPlayerBreath(peer_id);
1105 // Show death screen if necessary
1106 if(player->isDead())
1107 SendDeathscreen(peer_id, false, v3f(0,0,0));
1109 // Note things in chat if not in simple singleplayer mode
1110 if(!m_simple_singleplayer_mode) {
1111 // Send information about server to player in chat
1112 SendChatMessage(peer_id, getStatusString());
1114 // Send information about joining in chat
1116 std::wstring name = L"unknown";
1117 Player *player = m_env->getPlayer(peer_id);
1119 name = narrow_to_wide(player->getName());
1121 std::wstring message;
1124 message += L" joined the game.";
1125 SendChatMessage(PEER_ID_INEXISTENT,message);
1128 Address addr = getPeerAddress(player->peer_id);
1129 std::string ip_str = addr.serializeString();
1130 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1135 std::vector<std::string> names = m_clients.getPlayerNames();
1137 actionstream<<player->getName() <<" joins game. List of players: ";
1139 for (std::vector<std::string>::iterator i = names.begin();
1140 i != names.end(); i++) {
1141 actionstream << *i << " ";
1144 actionstream << player->getName() <<std::endl;
1149 inline void Server::handleCommand(NetworkPacket* pkt)
1151 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1152 (this->*opHandle.handler)(pkt);
1155 void Server::ProcessData(NetworkPacket *pkt)
1157 DSTACK(__FUNCTION_NAME);
1158 // Environment is locked first.
1159 JMutexAutoLock envlock(m_env_mutex);
1161 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1162 u32 peer_id = pkt->getPeerId();
1165 Address address = getPeerAddress(peer_id);
1166 std::string addr_s = address.serializeString();
1168 if(m_banmanager->isIpBanned(addr_s)) {
1169 std::string ban_name = m_banmanager->getBanName(addr_s);
1170 infostream << "Server: A banned client tried to connect from "
1171 << addr_s << "; banned name was "
1172 << ban_name << std::endl;
1173 // This actually doesn't seem to transfer to the client
1174 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1175 + narrow_to_wide(ban_name));
1179 catch(con::PeerNotFoundException &e) {
1181 * no peer for this packet found
1182 * most common reason is peer timeout, e.g. peer didn't
1183 * respond for some time, your server was overloaded or
1186 infostream << "Server::ProcessData(): Canceling: peer "
1187 << peer_id << " not found" << std::endl;
1192 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1194 // Command must be handled into ToServerCommandHandler
1195 if (command >= TOSERVER_NUM_MSG_TYPES) {
1196 infostream << "Server: Ignoring unknown command "
1197 << command << std::endl;
1200 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1205 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1207 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1208 errorstream << "Server::ProcessData(): Cancelling: Peer"
1209 " serialization format invalid or not initialized."
1210 " Skipping incoming command=" << command << std::endl;
1214 /* Handle commands related to client startup */
1215 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1220 if (m_clients.getClientState(peer_id) < CS_Active) {
1221 if (command == TOSERVER_PLAYERPOS) return;
1223 errorstream << "Got packet command: " << command << " for peer id "
1224 << peer_id << " but client isn't active yet. Dropping packet "
1230 } catch (SendFailedException &e) {
1231 errorstream << "Server::ProcessData(): SendFailedException: "
1232 << "what=" << e.what()
1234 } catch (PacketError &e) {
1235 actionstream << "Server::ProcessData(): PacketError: "
1236 << "what=" << e.what()
1241 void Server::setTimeOfDay(u32 time)
1243 m_env->setTimeOfDay(time);
1244 m_time_of_day_send_timer = 0;
1247 void Server::onMapEditEvent(MapEditEvent *event)
1249 if(m_ignore_map_edit_events)
1251 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1253 MapEditEvent *e = event->clone();
1254 m_unsent_map_edit_queue.push(e);
1257 Inventory* Server::getInventory(const InventoryLocation &loc)
1260 case InventoryLocation::UNDEFINED:
1261 case InventoryLocation::CURRENT_PLAYER:
1263 case InventoryLocation::PLAYER:
1265 Player *player = m_env->getPlayer(loc.name.c_str());
1268 PlayerSAO *playersao = player->getPlayerSAO();
1271 return playersao->getInventory();
1274 case InventoryLocation::NODEMETA:
1276 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1279 return meta->getInventory();
1282 case InventoryLocation::DETACHED:
1284 if(m_detached_inventories.count(loc.name) == 0)
1286 return m_detached_inventories[loc.name];
1290 sanity_check(false); // abort
1295 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1298 case InventoryLocation::UNDEFINED:
1300 case InventoryLocation::PLAYER:
1305 Player *player = m_env->getPlayer(loc.name.c_str());
1308 PlayerSAO *playersao = player->getPlayerSAO();
1312 SendInventory(playersao);
1315 case InventoryLocation::NODEMETA:
1317 v3s16 blockpos = getNodeBlockPos(loc.p);
1319 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1321 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1323 setBlockNotSent(blockpos);
1326 case InventoryLocation::DETACHED:
1328 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1332 sanity_check(false); // abort
1337 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1339 std::vector<u16> clients = m_clients.getClientIDs();
1341 // Set the modified blocks unsent for all the clients
1342 for (std::vector<u16>::iterator i = clients.begin();
1343 i != clients.end(); ++i) {
1344 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1345 client->SetBlocksNotSent(block);
1350 void Server::peerAdded(con::Peer *peer)
1352 DSTACK(__FUNCTION_NAME);
1353 verbosestream<<"Server::peerAdded(): peer->id="
1354 <<peer->id<<std::endl;
1357 c.type = con::PEER_ADDED;
1358 c.peer_id = peer->id;
1360 m_peer_change_queue.push(c);
1363 void Server::deletingPeer(con::Peer *peer, bool timeout)
1365 DSTACK(__FUNCTION_NAME);
1366 verbosestream<<"Server::deletingPeer(): peer->id="
1367 <<peer->id<<", timeout="<<timeout<<std::endl;
1369 m_clients.event(peer->id, CSE_Disconnect);
1371 c.type = con::PEER_REMOVED;
1372 c.peer_id = peer->id;
1373 c.timeout = timeout;
1374 m_peer_change_queue.push(c);
1377 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1379 *retval = m_con.getPeerStat(peer_id,type);
1380 if (*retval == -1) return false;
1384 bool Server::getClientInfo(
1393 std::string* vers_string
1396 *state = m_clients.getClientState(peer_id);
1398 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1400 if (client == NULL) {
1405 *uptime = client->uptime();
1406 *ser_vers = client->serialization_version;
1407 *prot_vers = client->net_proto_version;
1409 *major = client->getMajor();
1410 *minor = client->getMinor();
1411 *patch = client->getPatch();
1412 *vers_string = client->getPatch();
1419 void Server::handlePeerChanges()
1421 while(m_peer_change_queue.size() > 0)
1423 con::PeerChange c = m_peer_change_queue.front();
1424 m_peer_change_queue.pop();
1426 verbosestream<<"Server: Handling peer change: "
1427 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1432 case con::PEER_ADDED:
1433 m_clients.CreateClient(c.peer_id);
1436 case con::PEER_REMOVED:
1437 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1441 FATAL_ERROR("Invalid peer change event received!");
1447 void Server::Send(NetworkPacket* pkt)
1449 m_clients.send(pkt->getPeerId(),
1450 clientCommandFactoryTable[pkt->getCommand()].channel,
1452 clientCommandFactoryTable[pkt->getCommand()].reliable);
1455 void Server::SendMovement(u16 peer_id)
1457 DSTACK(__FUNCTION_NAME);
1458 std::ostringstream os(std::ios_base::binary);
1460 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1462 pkt << g_settings->getFloat("movement_acceleration_default");
1463 pkt << g_settings->getFloat("movement_acceleration_air");
1464 pkt << g_settings->getFloat("movement_acceleration_fast");
1465 pkt << g_settings->getFloat("movement_speed_walk");
1466 pkt << g_settings->getFloat("movement_speed_crouch");
1467 pkt << g_settings->getFloat("movement_speed_fast");
1468 pkt << g_settings->getFloat("movement_speed_climb");
1469 pkt << g_settings->getFloat("movement_speed_jump");
1470 pkt << g_settings->getFloat("movement_liquid_fluidity");
1471 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1472 pkt << g_settings->getFloat("movement_liquid_sink");
1473 pkt << g_settings->getFloat("movement_gravity");
1478 void Server::SendHP(u16 peer_id, u8 hp)
1480 DSTACK(__FUNCTION_NAME);
1482 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1487 void Server::SendBreath(u16 peer_id, u16 breath)
1489 DSTACK(__FUNCTION_NAME);
1491 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1492 pkt << (u16) breath;
1496 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1498 DSTACK(__FUNCTION_NAME);
1500 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1503 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1504 pkt << custom_reason;
1509 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1511 DSTACK(__FUNCTION_NAME);
1513 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1518 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1519 v3f camera_point_target)
1521 DSTACK(__FUNCTION_NAME);
1523 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1524 pkt << set_camera_point_target << camera_point_target;
1528 void Server::SendItemDef(u16 peer_id,
1529 IItemDefManager *itemdef, u16 protocol_version)
1531 DSTACK(__FUNCTION_NAME);
1533 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1537 u32 length of the next item
1538 zlib-compressed serialized ItemDefManager
1540 std::ostringstream tmp_os(std::ios::binary);
1541 itemdef->serialize(tmp_os, protocol_version);
1542 std::ostringstream tmp_os2(std::ios::binary);
1543 compressZlib(tmp_os.str(), tmp_os2);
1544 pkt.putLongString(tmp_os2.str());
1547 verbosestream << "Server: Sending item definitions to id(" << peer_id
1548 << "): size=" << pkt.getSize() << std::endl;
1553 void Server::SendNodeDef(u16 peer_id,
1554 INodeDefManager *nodedef, u16 protocol_version)
1556 DSTACK(__FUNCTION_NAME);
1558 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1562 u32 length of the next item
1563 zlib-compressed serialized NodeDefManager
1565 std::ostringstream tmp_os(std::ios::binary);
1566 nodedef->serialize(tmp_os, protocol_version);
1567 std::ostringstream tmp_os2(std::ios::binary);
1568 compressZlib(tmp_os.str(), tmp_os2);
1570 pkt.putLongString(tmp_os2.str());
1573 verbosestream << "Server: Sending node definitions to id(" << peer_id
1574 << "): size=" << pkt.getSize() << std::endl;
1580 Non-static send methods
1583 void Server::SendInventory(PlayerSAO* playerSAO)
1585 DSTACK(__FUNCTION_NAME);
1587 UpdateCrafting(playerSAO->getPlayer());
1593 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1595 std::ostringstream os;
1596 playerSAO->getInventory()->serialize(os);
1598 std::string s = os.str();
1600 pkt.putRawString(s.c_str(), s.size());
1604 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1606 DSTACK(__FUNCTION_NAME);
1608 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1611 if (peer_id != PEER_ID_INEXISTENT) {
1615 m_clients.sendToAll(0, &pkt, true);
1619 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1620 const std::string &formname)
1622 DSTACK(__FUNCTION_NAME);
1624 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1626 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1632 // Spawns a particle on peer with peer_id
1633 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1634 float expirationtime, float size, bool collisiondetection,
1635 bool vertical, std::string texture)
1637 DSTACK(__FUNCTION_NAME);
1639 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1641 pkt << pos << velocity << acceleration << expirationtime
1642 << size << collisiondetection;
1643 pkt.putLongString(texture);
1646 if (peer_id != PEER_ID_INEXISTENT) {
1650 m_clients.sendToAll(0, &pkt, true);
1654 // Adds a ParticleSpawner on peer with peer_id
1655 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1656 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1657 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1659 DSTACK(__FUNCTION_NAME);
1661 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1663 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1664 << minacc << maxacc << minexptime << maxexptime << minsize
1665 << maxsize << collisiondetection;
1667 pkt.putLongString(texture);
1669 pkt << id << vertical;
1671 if (peer_id != PEER_ID_INEXISTENT) {
1675 m_clients.sendToAll(0, &pkt, true);
1679 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1681 DSTACK(__FUNCTION_NAME);
1683 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1685 // Ugly error in this packet
1688 if (peer_id != PEER_ID_INEXISTENT) {
1692 m_clients.sendToAll(0, &pkt, true);
1697 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1699 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1701 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1702 << form->text << form->number << form->item << form->dir
1703 << form->align << form->offset << form->world_pos << form->size;
1708 void Server::SendHUDRemove(u16 peer_id, u32 id)
1710 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1715 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1717 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1718 pkt << id << (u8) stat;
1722 case HUD_STAT_SCALE:
1723 case HUD_STAT_ALIGN:
1724 case HUD_STAT_OFFSET:
1725 pkt << *(v2f *) value;
1729 pkt << *(std::string *) value;
1731 case HUD_STAT_WORLD_POS:
1732 pkt << *(v3f *) value;
1735 pkt << *(v2s32 *) value;
1737 case HUD_STAT_NUMBER:
1741 pkt << *(u32 *) value;
1748 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1750 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1752 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1754 pkt << flags << mask;
1759 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1761 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1762 pkt << param << value;
1766 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1767 const std::string &type, const std::vector<std::string> ¶ms)
1769 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1770 pkt << bgcolor << type << (u16) params.size();
1772 for(size_t i=0; i<params.size(); i++)
1778 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1781 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1784 pkt << do_override << (u16) (ratio * 65535);
1789 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1791 DSTACK(__FUNCTION_NAME);
1793 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1794 pkt << time << time_speed;
1796 if (peer_id == PEER_ID_INEXISTENT) {
1797 m_clients.sendToAll(0, &pkt, true);
1804 void Server::SendPlayerHP(u16 peer_id)
1806 DSTACK(__FUNCTION_NAME);
1807 PlayerSAO *playersao = getPlayerSAO(peer_id);
1808 // In some rare case, if the player is disconnected
1809 // while Lua call l_punch, for example, this can be NULL
1813 SendHP(peer_id, playersao->getHP());
1814 m_script->player_event(playersao,"health_changed");
1816 // Send to other clients
1817 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1818 ActiveObjectMessage aom(playersao->getId(), true, str);
1819 playersao->m_messages_out.push(aom);
1822 void Server::SendPlayerBreath(u16 peer_id)
1824 DSTACK(__FUNCTION_NAME);
1825 PlayerSAO *playersao = getPlayerSAO(peer_id);
1828 m_script->player_event(playersao, "breath_changed");
1829 SendBreath(peer_id, playersao->getBreath());
1832 void Server::SendMovePlayer(u16 peer_id)
1834 DSTACK(__FUNCTION_NAME);
1835 Player *player = m_env->getPlayer(peer_id);
1838 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1839 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1842 v3f pos = player->getPosition();
1843 f32 pitch = player->getPitch();
1844 f32 yaw = player->getYaw();
1845 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1846 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1847 << " pitch=" << pitch
1855 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1857 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1860 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1861 << animation_frames[3] << animation_speed;
1866 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1868 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1869 pkt << first << third;
1872 void Server::SendPlayerPrivileges(u16 peer_id)
1874 Player *player = m_env->getPlayer(peer_id);
1876 if(player->peer_id == PEER_ID_INEXISTENT)
1879 std::set<std::string> privs;
1880 m_script->getAuth(player->getName(), NULL, &privs);
1882 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1883 pkt << (u16) privs.size();
1885 for(std::set<std::string>::const_iterator i = privs.begin();
1886 i != privs.end(); i++) {
1893 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1895 Player *player = m_env->getPlayer(peer_id);
1897 if(player->peer_id == PEER_ID_INEXISTENT)
1900 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1901 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1905 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1907 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1908 pkt.putRawString(datas.c_str(), datas.size());
1910 return pkt.getSize();
1913 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1915 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1916 datas.size(), peer_id);
1918 pkt.putRawString(datas.c_str(), datas.size());
1920 m_clients.send(pkt.getPeerId(),
1921 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1926 s32 Server::playSound(const SimpleSoundSpec &spec,
1927 const ServerSoundParams ¶ms)
1929 // Find out initial position of sound
1930 bool pos_exists = false;
1931 v3f pos = params.getPos(m_env, &pos_exists);
1932 // If position is not found while it should be, cancel sound
1933 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1936 // Filter destination clients
1937 std::vector<u16> dst_clients;
1938 if(params.to_player != "")
1940 Player *player = m_env->getPlayer(params.to_player.c_str());
1942 infostream<<"Server::playSound: Player \""<<params.to_player
1943 <<"\" not found"<<std::endl;
1946 if(player->peer_id == PEER_ID_INEXISTENT){
1947 infostream<<"Server::playSound: Player \""<<params.to_player
1948 <<"\" not connected"<<std::endl;
1951 dst_clients.push_back(player->peer_id);
1954 std::vector<u16> clients = m_clients.getClientIDs();
1956 for(std::vector<u16>::iterator
1957 i = clients.begin(); i != clients.end(); ++i) {
1958 Player *player = m_env->getPlayer(*i);
1963 if(player->getPosition().getDistanceFrom(pos) >
1964 params.max_hear_distance)
1967 dst_clients.push_back(*i);
1971 if(dst_clients.empty())
1975 s32 id = m_next_sound_id++;
1976 // The sound will exist as a reference in m_playing_sounds
1977 m_playing_sounds[id] = ServerPlayingSound();
1978 ServerPlayingSound &psound = m_playing_sounds[id];
1979 psound.params = params;
1981 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1982 pkt << id << spec.name << (float) (spec.gain * params.gain)
1983 << (u8) params.type << pos << params.object << params.loop;
1985 for(std::vector<u16>::iterator i = dst_clients.begin();
1986 i != dst_clients.end(); i++) {
1987 psound.clients.insert(*i);
1988 m_clients.send(*i, 0, &pkt, true);
1992 void Server::stopSound(s32 handle)
1994 // Get sound reference
1995 std::map<s32, ServerPlayingSound>::iterator i =
1996 m_playing_sounds.find(handle);
1997 if(i == m_playing_sounds.end())
1999 ServerPlayingSound &psound = i->second;
2001 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2004 for(std::set<u16>::iterator i = psound.clients.begin();
2005 i != psound.clients.end(); i++) {
2007 m_clients.send(*i, 0, &pkt, true);
2009 // Remove sound reference
2010 m_playing_sounds.erase(i);
2013 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2014 std::vector<u16> *far_players, float far_d_nodes)
2016 float maxd = far_d_nodes*BS;
2017 v3f p_f = intToFloat(p, BS);
2019 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2022 std::vector<u16> clients = m_clients.getClientIDs();
2023 for(std::vector<u16>::iterator i = clients.begin();
2024 i != clients.end(); ++i) {
2027 if(Player *player = m_env->getPlayer(*i)) {
2028 // If player is far away, only set modified blocks not sent
2029 v3f player_pos = player->getPosition();
2030 if(player_pos.getDistanceFrom(p_f) > maxd) {
2031 far_players->push_back(*i);
2038 m_clients.send(*i, 0, &pkt, true);
2042 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2043 std::vector<u16> *far_players, float far_d_nodes,
2044 bool remove_metadata)
2046 float maxd = far_d_nodes*BS;
2047 v3f p_f = intToFloat(p, BS);
2049 std::vector<u16> clients = m_clients.getClientIDs();
2050 for(std::vector<u16>::iterator i = clients.begin();
2051 i != clients.end(); ++i) {
2055 if(Player *player = m_env->getPlayer(*i)) {
2056 // If player is far away, only set modified blocks not sent
2057 v3f player_pos = player->getPosition();
2058 if(player_pos.getDistanceFrom(p_f) > maxd) {
2059 far_players->push_back(*i);
2065 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2067 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2069 pkt << p << n.param0 << n.param1 << n.param2
2070 << (u8) (remove_metadata ? 0 : 1);
2072 if (!remove_metadata) {
2073 if (client->net_proto_version <= 21) {
2074 // Old clients always clear metadata; fix it
2075 // by sending the full block again.
2076 client->SetBlockNotSent(p);
2083 if (pkt.getSize() > 0)
2084 m_clients.send(*i, 0, &pkt, true);
2088 void Server::setBlockNotSent(v3s16 p)
2090 std::vector<u16> clients = m_clients.getClientIDs();
2092 for(std::vector<u16>::iterator i = clients.begin();
2093 i != clients.end(); ++i) {
2094 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2095 client->SetBlockNotSent(p);
2100 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2102 DSTACK(__FUNCTION_NAME);
2104 v3s16 p = block->getPos();
2107 Create a packet with the block in the right format
2110 std::ostringstream os(std::ios_base::binary);
2111 block->serialize(os, ver, false);
2112 block->serializeNetworkSpecific(os, net_proto_version);
2113 std::string s = os.str();
2115 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2118 pkt.putRawString(s.c_str(), s.size());
2122 void Server::SendBlocks(float dtime)
2124 DSTACK(__FUNCTION_NAME);
2126 JMutexAutoLock envlock(m_env_mutex);
2127 //TODO check if one big lock could be faster then multiple small ones
2129 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2131 std::vector<PrioritySortedBlockTransfer> queue;
2133 s32 total_sending = 0;
2136 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2138 std::vector<u16> clients = m_clients.getClientIDs();
2141 for(std::vector<u16>::iterator i = clients.begin();
2142 i != clients.end(); ++i) {
2143 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2148 total_sending += client->SendingCount();
2149 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2155 // Lowest priority number comes first.
2156 // Lowest is most important.
2157 std::sort(queue.begin(), queue.end());
2160 for(u32 i=0; i<queue.size(); i++)
2162 //TODO: Calculate limit dynamically
2163 if(total_sending >= g_settings->getS32
2164 ("max_simultaneous_block_sends_server_total"))
2167 PrioritySortedBlockTransfer q = queue[i];
2169 MapBlock *block = NULL;
2172 block = m_env->getMap().getBlockNoCreate(q.pos);
2174 catch(InvalidPositionException &e)
2179 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2184 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2186 client->SentBlock(q.pos);
2192 void Server::fillMediaCache()
2194 DSTACK(__FUNCTION_NAME);
2196 infostream<<"Server: Calculating media file checksums"<<std::endl;
2198 // Collect all media file paths
2199 std::vector<std::string> paths;
2200 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2201 i != m_mods.end(); i++) {
2202 const ModSpec &mod = *i;
2203 paths.push_back(mod.path + DIR_DELIM + "textures");
2204 paths.push_back(mod.path + DIR_DELIM + "sounds");
2205 paths.push_back(mod.path + DIR_DELIM + "media");
2206 paths.push_back(mod.path + DIR_DELIM + "models");
2208 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2210 // Collect media file information from paths into cache
2211 for(std::vector<std::string>::iterator i = paths.begin();
2212 i != paths.end(); i++) {
2213 std::string mediapath = *i;
2214 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2215 for (u32 j = 0; j < dirlist.size(); j++) {
2216 if (dirlist[j].dir) // Ignode dirs
2218 std::string filename = dirlist[j].name;
2219 // If name contains illegal characters, ignore the file
2220 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2221 infostream<<"Server: ignoring illegal file name: \""
2222 << filename << "\"" << std::endl;
2225 // If name is not in a supported format, ignore it
2226 const char *supported_ext[] = {
2227 ".png", ".jpg", ".bmp", ".tga",
2228 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2230 ".x", ".b3d", ".md2", ".obj",
2233 if (removeStringEnd(filename, supported_ext) == ""){
2234 infostream << "Server: ignoring unsupported file extension: \""
2235 << filename << "\"" << std::endl;
2238 // Ok, attempt to load the file and add to cache
2239 std::string filepath = mediapath + DIR_DELIM + filename;
2241 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2243 errorstream << "Server::fillMediaCache(): Could not open \""
2244 << filename << "\" for reading" << std::endl;
2247 std::ostringstream tmp_os(std::ios_base::binary);
2251 fis.read(buf, 1024);
2252 std::streamsize len = fis.gcount();
2253 tmp_os.write(buf, len);
2262 errorstream<<"Server::fillMediaCache(): Failed to read \""
2263 << filename << "\"" << std::endl;
2266 if(tmp_os.str().length() == 0) {
2267 errorstream << "Server::fillMediaCache(): Empty file \""
2268 << filepath << "\"" << std::endl;
2273 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2275 unsigned char *digest = sha1.getDigest();
2276 std::string sha1_base64 = base64_encode(digest, 20);
2277 std::string sha1_hex = hex_encode((char*)digest, 20);
2281 m_media[filename] = MediaInfo(filepath, sha1_base64);
2282 verbosestream << "Server: " << sha1_hex << " is " << filename
2288 struct SendableMediaAnnouncement
2291 std::string sha1_digest;
2293 SendableMediaAnnouncement(const std::string &name_="",
2294 const std::string &sha1_digest_=""):
2296 sha1_digest(sha1_digest_)
2300 void Server::sendMediaAnnouncement(u16 peer_id)
2302 DSTACK(__FUNCTION_NAME);
2304 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2307 std::vector<SendableMediaAnnouncement> file_announcements;
2309 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2310 i != m_media.end(); i++){
2312 file_announcements.push_back(
2313 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2317 std::ostringstream os(std::ios_base::binary);
2319 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2320 pkt << (u16) file_announcements.size();
2322 for (std::vector<SendableMediaAnnouncement>::iterator
2323 j = file_announcements.begin();
2324 j != file_announcements.end(); ++j) {
2325 pkt << j->name << j->sha1_digest;
2328 pkt << g_settings->get("remote_media");
2332 struct SendableMedia
2338 SendableMedia(const std::string &name_="", const std::string &path_="",
2339 const std::string &data_=""):
2346 void Server::sendRequestedMedia(u16 peer_id,
2347 const std::vector<std::string> &tosend)
2349 DSTACK(__FUNCTION_NAME);
2351 verbosestream<<"Server::sendRequestedMedia(): "
2352 <<"Sending files to client"<<std::endl;
2356 // Put 5kB in one bunch (this is not accurate)
2357 u32 bytes_per_bunch = 5000;
2359 std::vector< std::vector<SendableMedia> > file_bunches;
2360 file_bunches.push_back(std::vector<SendableMedia>());
2362 u32 file_size_bunch_total = 0;
2364 for(std::vector<std::string>::const_iterator i = tosend.begin();
2365 i != tosend.end(); ++i) {
2366 const std::string &name = *i;
2368 if(m_media.find(name) == m_media.end()) {
2369 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2370 <<"unknown file \""<<(name)<<"\""<<std::endl;
2374 //TODO get path + name
2375 std::string tpath = m_media[name].path;
2378 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2379 if(fis.good() == false){
2380 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2381 <<tpath<<"\" for reading"<<std::endl;
2384 std::ostringstream tmp_os(std::ios_base::binary);
2388 fis.read(buf, 1024);
2389 std::streamsize len = fis.gcount();
2390 tmp_os.write(buf, len);
2391 file_size_bunch_total += len;
2400 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2401 <<name<<"\""<<std::endl;
2404 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2405 <<tname<<"\""<<std::endl;*/
2407 file_bunches[file_bunches.size()-1].push_back(
2408 SendableMedia(name, tpath, tmp_os.str()));
2410 // Start next bunch if got enough data
2411 if(file_size_bunch_total >= bytes_per_bunch) {
2412 file_bunches.push_back(std::vector<SendableMedia>());
2413 file_size_bunch_total = 0;
2418 /* Create and send packets */
2420 u16 num_bunches = file_bunches.size();
2421 for(u16 i = 0; i < num_bunches; i++) {
2424 u16 total number of texture bunches
2425 u16 index of this bunch
2426 u32 number of files in this bunch
2435 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2436 pkt << num_bunches << i << (u32) file_bunches[i].size();
2438 for(std::vector<SendableMedia>::iterator
2439 j = file_bunches[i].begin();
2440 j != file_bunches[i].end(); ++j) {
2442 pkt.putLongString(j->data);
2445 verbosestream << "Server::sendRequestedMedia(): bunch "
2446 << i << "/" << num_bunches
2447 << " files=" << file_bunches[i].size()
2448 << " size=" << pkt.getSize() << std::endl;
2453 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2455 if(m_detached_inventories.count(name) == 0) {
2456 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2459 Inventory *inv = m_detached_inventories[name];
2460 std::ostringstream os(std::ios_base::binary);
2462 os << serializeString(name);
2466 std::string s = os.str();
2468 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2469 pkt.putRawString(s.c_str(), s.size());
2471 if (peer_id != PEER_ID_INEXISTENT) {
2475 m_clients.sendToAll(0, &pkt, true);
2479 void Server::sendDetachedInventories(u16 peer_id)
2481 DSTACK(__FUNCTION_NAME);
2483 for(std::map<std::string, Inventory*>::iterator
2484 i = m_detached_inventories.begin();
2485 i != m_detached_inventories.end(); i++) {
2486 const std::string &name = i->first;
2487 //Inventory *inv = i->second;
2488 sendDetachedInventory(name, peer_id);
2496 void Server::DiePlayer(u16 peer_id)
2498 DSTACK(__FUNCTION_NAME);
2500 PlayerSAO *playersao = getPlayerSAO(peer_id);
2503 infostream << "Server::DiePlayer(): Player "
2504 << playersao->getPlayer()->getName()
2505 << " dies" << std::endl;
2507 playersao->setHP(0);
2509 // Trigger scripted stuff
2510 m_script->on_dieplayer(playersao);
2512 SendPlayerHP(peer_id);
2513 SendDeathscreen(peer_id, false, v3f(0,0,0));
2516 void Server::RespawnPlayer(u16 peer_id)
2518 DSTACK(__FUNCTION_NAME);
2520 PlayerSAO *playersao = getPlayerSAO(peer_id);
2523 infostream << "Server::RespawnPlayer(): Player "
2524 << playersao->getPlayer()->getName()
2525 << " respawns" << std::endl;
2527 playersao->setHP(PLAYER_MAX_HP);
2528 playersao->setBreath(PLAYER_MAX_BREATH);
2530 SendPlayerHP(peer_id);
2531 SendPlayerBreath(peer_id);
2533 bool repositioned = m_script->on_respawnplayer(playersao);
2535 v3f pos = findSpawnPos();
2536 // setPos will send the new position to client
2537 playersao->setPos(pos);
2541 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2543 DSTACK(__FUNCTION_NAME);
2545 SendAccessDenied(peer_id, reason, custom_reason);
2546 m_clients.event(peer_id, CSE_SetDenied);
2547 m_con.DisconnectPeer(peer_id);
2550 // 13/03/15: remove this function when protocol version 25 will become
2551 // the minimum version for MT users, maybe in 1 year
2552 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2554 DSTACK(__FUNCTION_NAME);
2556 SendAccessDenied_Legacy(peer_id, reason);
2557 m_clients.event(peer_id, CSE_SetDenied);
2558 m_con.DisconnectPeer(peer_id);
2561 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2563 DSTACK(__FUNCTION_NAME);
2564 std::wstring message;
2567 Clear references to playing sounds
2569 for(std::map<s32, ServerPlayingSound>::iterator
2570 i = m_playing_sounds.begin();
2571 i != m_playing_sounds.end();)
2573 ServerPlayingSound &psound = i->second;
2574 psound.clients.erase(peer_id);
2575 if(psound.clients.empty())
2576 m_playing_sounds.erase(i++);
2581 Player *player = m_env->getPlayer(peer_id);
2583 // Collect information about leaving in chat
2585 if(player != NULL && reason != CDR_DENY)
2587 std::wstring name = narrow_to_wide(player->getName());
2590 message += L" left the game.";
2591 if(reason == CDR_TIMEOUT)
2592 message += L" (timed out)";
2596 /* Run scripts and remove from environment */
2600 PlayerSAO *playersao = player->getPlayerSAO();
2603 m_script->on_leaveplayer(playersao);
2605 playersao->disconnected();
2613 if(player != NULL && reason != CDR_DENY) {
2614 std::ostringstream os(std::ios_base::binary);
2615 std::vector<u16> clients = m_clients.getClientIDs();
2617 for(std::vector<u16>::iterator i = clients.begin();
2618 i != clients.end(); ++i) {
2620 Player *player = m_env->getPlayer(*i);
2624 // Get name of player
2625 os << player->getName() << " ";
2628 actionstream << player->getName() << " "
2629 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2630 << " List of players: " << os.str() << std::endl;
2634 JMutexAutoLock env_lock(m_env_mutex);
2635 m_clients.DeleteClient(peer_id);
2639 // Send leave chat message to all remaining clients
2640 if(message.length() != 0)
2641 SendChatMessage(PEER_ID_INEXISTENT,message);
2644 void Server::UpdateCrafting(Player* player)
2646 DSTACK(__FUNCTION_NAME);
2648 // Get a preview for crafting
2650 InventoryLocation loc;
2651 loc.setPlayer(player->getName());
2652 getCraftingResult(&player->inventory, preview, false, this);
2653 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2655 // Put the new preview in
2656 InventoryList *plist = player->inventory.getList("craftpreview");
2657 sanity_check(plist);
2658 sanity_check(plist->getSize() >= 1);
2659 plist->changeItem(0, preview);
2662 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2664 RemoteClient *client = getClientNoEx(peer_id,state_min);
2666 throw ClientNotFoundException("Client not found");
2670 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2672 return m_clients.getClientNoEx(peer_id, state_min);
2675 std::string Server::getPlayerName(u16 peer_id)
2677 Player *player = m_env->getPlayer(peer_id);
2679 return "[id="+itos(peer_id)+"]";
2680 return player->getName();
2683 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2685 Player *player = m_env->getPlayer(peer_id);
2688 return player->getPlayerSAO();
2691 std::wstring Server::getStatusString()
2693 std::wostringstream os(std::ios_base::binary);
2696 os<<L"version="<<narrow_to_wide(g_version_string);
2698 os<<L", uptime="<<m_uptime.get();
2700 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2701 // Information about clients
2704 std::vector<u16> clients = m_clients.getClientIDs();
2705 for(std::vector<u16>::iterator i = clients.begin();
2706 i != clients.end(); ++i) {
2708 Player *player = m_env->getPlayer(*i);
2709 // Get name of player
2710 std::wstring name = L"unknown";
2712 name = narrow_to_wide(player->getName());
2713 // Add name to information string
2721 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2722 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2723 if(g_settings->get("motd") != "")
2724 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2728 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2730 std::set<std::string> privs;
2731 m_script->getAuth(name, NULL, &privs);
2735 bool Server::checkPriv(const std::string &name, const std::string &priv)
2737 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2738 return (privs.count(priv) != 0);
2741 void Server::reportPrivsModified(const std::string &name)
2744 std::vector<u16> clients = m_clients.getClientIDs();
2745 for(std::vector<u16>::iterator i = clients.begin();
2746 i != clients.end(); ++i) {
2747 Player *player = m_env->getPlayer(*i);
2748 reportPrivsModified(player->getName());
2751 Player *player = m_env->getPlayer(name.c_str());
2754 SendPlayerPrivileges(player->peer_id);
2755 PlayerSAO *sao = player->getPlayerSAO();
2758 sao->updatePrivileges(
2759 getPlayerEffectivePrivs(name),
2764 void Server::reportInventoryFormspecModified(const std::string &name)
2766 Player *player = m_env->getPlayer(name.c_str());
2769 SendPlayerInventoryFormspec(player->peer_id);
2772 void Server::setIpBanned(const std::string &ip, const std::string &name)
2774 m_banmanager->add(ip, name);
2777 void Server::unsetIpBanned(const std::string &ip_or_name)
2779 m_banmanager->remove(ip_or_name);
2782 std::string Server::getBanDescription(const std::string &ip_or_name)
2784 return m_banmanager->getBanDescription(ip_or_name);
2787 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2789 Player *player = m_env->getPlayer(name);
2793 if (player->peer_id == PEER_ID_INEXISTENT)
2796 SendChatMessage(player->peer_id, msg);
2799 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2801 Player *player = m_env->getPlayer(playername);
2805 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2809 SendShowFormspecMessage(player->peer_id, formspec, formname);
2813 u32 Server::hudAdd(Player *player, HudElement *form) {
2817 u32 id = player->addHud(form);
2819 SendHUDAdd(player->peer_id, id, form);
2824 bool Server::hudRemove(Player *player, u32 id) {
2828 HudElement* todel = player->removeHud(id);
2835 SendHUDRemove(player->peer_id, id);
2839 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2843 SendHUDChange(player->peer_id, id, stat, data);
2847 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2851 SendHUDSetFlags(player->peer_id, flags, mask);
2852 player->hud_flags = flags;
2854 PlayerSAO* playersao = player->getPlayerSAO();
2856 if (playersao == NULL)
2859 m_script->player_event(playersao, "hud_changed");
2863 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2866 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2869 std::ostringstream os(std::ios::binary);
2870 writeS32(os, hotbar_itemcount);
2871 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2875 void Server::hudSetHotbarImage(Player *player, std::string name) {
2879 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2882 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2886 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2889 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2894 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2898 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2903 SendEyeOffset(player->peer_id, first, third);
2907 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2908 const std::string &type, const std::vector<std::string> ¶ms)
2913 SendSetSky(player->peer_id, bgcolor, type, params);
2917 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2923 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2927 void Server::notifyPlayers(const std::wstring &msg)
2929 SendChatMessage(PEER_ID_INEXISTENT,msg);
2932 void Server::spawnParticle(const char *playername, v3f pos,
2933 v3f velocity, v3f acceleration,
2934 float expirationtime, float size, bool
2935 collisiondetection, bool vertical, std::string texture)
2937 Player *player = m_env->getPlayer(playername);
2940 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2941 expirationtime, size, collisiondetection, vertical, texture);
2944 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2945 float expirationtime, float size,
2946 bool collisiondetection, bool vertical, std::string texture)
2948 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2949 expirationtime, size, collisiondetection, vertical, texture);
2952 u32 Server::addParticleSpawner(const char *playername,
2953 u16 amount, float spawntime,
2954 v3f minpos, v3f maxpos,
2955 v3f minvel, v3f maxvel,
2956 v3f minacc, v3f maxacc,
2957 float minexptime, float maxexptime,
2958 float minsize, float maxsize,
2959 bool collisiondetection, bool vertical, std::string texture)
2961 Player *player = m_env->getPlayer(playername);
2966 for(;;) // look for unused particlespawner id
2969 if (std::find(m_particlespawner_ids.begin(),
2970 m_particlespawner_ids.end(), id)
2971 == m_particlespawner_ids.end())
2973 m_particlespawner_ids.push_back(id);
2978 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2979 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2980 minexptime, maxexptime, minsize, maxsize,
2981 collisiondetection, vertical, texture, id);
2986 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2987 v3f minpos, v3f maxpos,
2988 v3f minvel, v3f maxvel,
2989 v3f minacc, v3f maxacc,
2990 float minexptime, float maxexptime,
2991 float minsize, float maxsize,
2992 bool collisiondetection, bool vertical, std::string texture)
2995 for(;;) // look for unused particlespawner id
2998 if (std::find(m_particlespawner_ids.begin(),
2999 m_particlespawner_ids.end(), id)
3000 == m_particlespawner_ids.end())
3002 m_particlespawner_ids.push_back(id);
3007 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3008 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3009 minexptime, maxexptime, minsize, maxsize,
3010 collisiondetection, vertical, texture, id);
3015 void Server::deleteParticleSpawner(const char *playername, u32 id)
3017 Player *player = m_env->getPlayer(playername);
3021 m_particlespawner_ids.erase(
3022 std::remove(m_particlespawner_ids.begin(),
3023 m_particlespawner_ids.end(), id),
3024 m_particlespawner_ids.end());
3025 SendDeleteParticleSpawner(player->peer_id, id);
3028 void Server::deleteParticleSpawnerAll(u32 id)
3030 m_particlespawner_ids.erase(
3031 std::remove(m_particlespawner_ids.begin(),
3032 m_particlespawner_ids.end(), id),
3033 m_particlespawner_ids.end());
3034 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3037 Inventory* Server::createDetachedInventory(const std::string &name)
3039 if(m_detached_inventories.count(name) > 0){
3040 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3041 delete m_detached_inventories[name];
3043 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3045 Inventory *inv = new Inventory(m_itemdef);
3047 m_detached_inventories[name] = inv;
3048 //TODO find a better way to do this
3049 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3056 BoolScopeSet(bool *dst, bool val):
3059 m_orig_state = *m_dst;
3064 *m_dst = m_orig_state;
3071 // actions: time-reversed list
3072 // Return value: success/failure
3073 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3074 std::list<std::string> *log)
3076 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3077 ServerMap *map = (ServerMap*)(&m_env->getMap());
3079 // Fail if no actions to handle
3080 if(actions.empty()){
3081 log->push_back("Nothing to do.");
3088 for(std::list<RollbackAction>::const_iterator
3089 i = actions.begin();
3090 i != actions.end(); i++)
3092 const RollbackAction &action = *i;
3094 bool success = action.applyRevert(map, this, this);
3097 std::ostringstream os;
3098 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3099 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3101 log->push_back(os.str());
3103 std::ostringstream os;
3104 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3105 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3107 log->push_back(os.str());
3111 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3112 <<" failed"<<std::endl;
3114 // Call it done if less than half failed
3115 return num_failed <= num_tried/2;
3118 // IGameDef interface
3120 IItemDefManager* Server::getItemDefManager()
3124 INodeDefManager* Server::getNodeDefManager()
3128 ICraftDefManager* Server::getCraftDefManager()
3132 ITextureSource* Server::getTextureSource()
3136 IShaderSource* Server::getShaderSource()
3140 scene::ISceneManager* Server::getSceneManager()
3145 u16 Server::allocateUnknownNodeId(const std::string &name)
3147 return m_nodedef->allocateDummy(name);
3149 ISoundManager* Server::getSoundManager()
3151 return &dummySoundManager;
3153 MtEventManager* Server::getEventManager()
3158 IWritableItemDefManager* Server::getWritableItemDefManager()
3162 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3166 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3171 const ModSpec* Server::getModSpec(const std::string &modname)
3173 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3174 i != m_mods.end(); i++){
3175 const ModSpec &mod = *i;
3176 if(mod.name == modname)
3181 void Server::getModNames(std::vector<std::string> &modlist)
3183 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3184 modlist.push_back(i->name);
3187 std::string Server::getBuiltinLuaPath()
3189 return porting::path_share + DIR_DELIM + "builtin";
3192 v3f Server::findSpawnPos()
3194 ServerMap &map = m_env->getServerMap();
3196 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3197 return nodeposf * BS;
3200 // Default position is static_spawnpoint
3201 // We will return it if we don't found a good place
3202 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3204 s16 water_level = map.getWaterLevel();
3206 bool is_good = false;
3208 // Try to find a good place a few times
3209 for(s32 i = 0; i < 1000 && !is_good; i++) {
3211 // We're going to try to throw the player to this position
3212 v2s16 nodepos2d = v2s16(
3213 -range + (myrand() % (range * 2)),
3214 -range + (myrand() % (range * 2)));
3216 // Get ground height at point
3217 s16 groundheight = map.findGroundLevel(nodepos2d);
3218 if (groundheight <= water_level) // Don't go underwater
3220 if (groundheight > water_level + 6) // Don't go to high places
3223 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3226 for (s32 i = 0; i < 10; i++) {
3227 v3s16 blockpos = getNodeBlockPos(nodepos);
3228 map.emergeBlock(blockpos, true);
3229 content_t c = map.getNodeNoEx(nodepos).getContent();
3230 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3232 if (air_count >= 2){
3241 return intToFloat(nodepos, BS);
3244 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3246 bool newplayer = false;
3249 Try to get an existing player
3251 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3253 // If player is already connected, cancel
3254 if(player != NULL && player->peer_id != 0)
3256 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3261 If player with the wanted peer_id already exists, cancel.
3263 if(m_env->getPlayer(peer_id) != NULL)
3265 infostream<<"emergePlayer(): Player with wrong name but same"
3266 " peer_id already exists"<<std::endl;
3270 // Load player if it isn't already loaded
3272 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3275 // Create player if it doesn't exist
3278 player = new RemotePlayer(this, name);
3279 // Set player position
3280 infostream<<"Server: Finding spawn place for player \""
3281 <<name<<"\""<<std::endl;
3282 v3f pos = findSpawnPos();
3283 player->setPosition(pos);
3285 // Make sure the player is saved
3286 player->setModified(true);
3288 // Add player to environment
3289 m_env->addPlayer(player);
3292 // Create a new player active object
3293 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3294 getPlayerEffectivePrivs(player->getName()),
3297 /* Clean up old HUD elements from previous sessions */
3300 /* Add object to environment */
3301 m_env->addActiveObject(playersao);
3305 m_script->on_newplayer(playersao);
3311 void dedicated_server_loop(Server &server, bool &kill)
3313 DSTACK(__FUNCTION_NAME);
3315 verbosestream<<"dedicated_server_loop()"<<std::endl;
3317 IntervalLimiter m_profiler_interval;
3321 float steplen = g_settings->getFloat("dedicated_server_step");
3322 // This is kind of a hack but can be done like this
3323 // because server.step() is very light
3325 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3326 sleep_ms((int)(steplen*1000.0));
3328 server.step(steplen);
3330 if(server.getShutdownRequested() || kill)
3332 infostream<<"Dedicated server quitting"<<std::endl;
3334 if(g_settings->getBool("server_announce"))
3335 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3343 float profiler_print_interval =
3344 g_settings->getFloat("profiler_print_interval");
3345 if(profiler_print_interval != 0)
3347 if(m_profiler_interval.step(steplen, profiler_print_interval))
3349 infostream<<"Profiler:"<<std::endl;
3350 g_profiler->print(infostream);
3351 g_profiler->clear();