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 "
1231 catch(SendFailedException &e) {
1232 errorstream << "Server::ProcessData(): SendFailedException: "
1233 << "what=" << e.what()
1238 void Server::setTimeOfDay(u32 time)
1240 m_env->setTimeOfDay(time);
1241 m_time_of_day_send_timer = 0;
1244 void Server::onMapEditEvent(MapEditEvent *event)
1246 if(m_ignore_map_edit_events)
1248 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1250 MapEditEvent *e = event->clone();
1251 m_unsent_map_edit_queue.push(e);
1254 Inventory* Server::getInventory(const InventoryLocation &loc)
1257 case InventoryLocation::UNDEFINED:
1258 case InventoryLocation::CURRENT_PLAYER:
1260 case InventoryLocation::PLAYER:
1262 Player *player = m_env->getPlayer(loc.name.c_str());
1265 PlayerSAO *playersao = player->getPlayerSAO();
1268 return playersao->getInventory();
1271 case InventoryLocation::NODEMETA:
1273 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1276 return meta->getInventory();
1279 case InventoryLocation::DETACHED:
1281 if(m_detached_inventories.count(loc.name) == 0)
1283 return m_detached_inventories[loc.name];
1287 sanity_check(false); // abort
1292 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1295 case InventoryLocation::UNDEFINED:
1297 case InventoryLocation::PLAYER:
1302 Player *player = m_env->getPlayer(loc.name.c_str());
1305 PlayerSAO *playersao = player->getPlayerSAO();
1309 SendInventory(playersao);
1312 case InventoryLocation::NODEMETA:
1314 v3s16 blockpos = getNodeBlockPos(loc.p);
1316 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1318 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1320 setBlockNotSent(blockpos);
1323 case InventoryLocation::DETACHED:
1325 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1329 sanity_check(false); // abort
1334 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1336 std::vector<u16> clients = m_clients.getClientIDs();
1338 // Set the modified blocks unsent for all the clients
1339 for (std::vector<u16>::iterator i = clients.begin();
1340 i != clients.end(); ++i) {
1341 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1342 client->SetBlocksNotSent(block);
1347 void Server::peerAdded(con::Peer *peer)
1349 DSTACK(__FUNCTION_NAME);
1350 verbosestream<<"Server::peerAdded(): peer->id="
1351 <<peer->id<<std::endl;
1354 c.type = con::PEER_ADDED;
1355 c.peer_id = peer->id;
1357 m_peer_change_queue.push(c);
1360 void Server::deletingPeer(con::Peer *peer, bool timeout)
1362 DSTACK(__FUNCTION_NAME);
1363 verbosestream<<"Server::deletingPeer(): peer->id="
1364 <<peer->id<<", timeout="<<timeout<<std::endl;
1366 m_clients.event(peer->id, CSE_Disconnect);
1368 c.type = con::PEER_REMOVED;
1369 c.peer_id = peer->id;
1370 c.timeout = timeout;
1371 m_peer_change_queue.push(c);
1374 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1376 *retval = m_con.getPeerStat(peer_id,type);
1377 if (*retval == -1) return false;
1381 bool Server::getClientInfo(
1390 std::string* vers_string
1393 *state = m_clients.getClientState(peer_id);
1395 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1397 if (client == NULL) {
1402 *uptime = client->uptime();
1403 *ser_vers = client->serialization_version;
1404 *prot_vers = client->net_proto_version;
1406 *major = client->getMajor();
1407 *minor = client->getMinor();
1408 *patch = client->getPatch();
1409 *vers_string = client->getPatch();
1416 void Server::handlePeerChanges()
1418 while(m_peer_change_queue.size() > 0)
1420 con::PeerChange c = m_peer_change_queue.front();
1421 m_peer_change_queue.pop();
1423 verbosestream<<"Server: Handling peer change: "
1424 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1429 case con::PEER_ADDED:
1430 m_clients.CreateClient(c.peer_id);
1433 case con::PEER_REMOVED:
1434 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1438 FATAL_ERROR("Invalid peer change event received!");
1444 void Server::Send(NetworkPacket* pkt)
1446 m_clients.send(pkt->getPeerId(),
1447 clientCommandFactoryTable[pkt->getCommand()].channel,
1449 clientCommandFactoryTable[pkt->getCommand()].reliable);
1452 void Server::SendMovement(u16 peer_id)
1454 DSTACK(__FUNCTION_NAME);
1455 std::ostringstream os(std::ios_base::binary);
1457 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1459 pkt << g_settings->getFloat("movement_acceleration_default");
1460 pkt << g_settings->getFloat("movement_acceleration_air");
1461 pkt << g_settings->getFloat("movement_acceleration_fast");
1462 pkt << g_settings->getFloat("movement_speed_walk");
1463 pkt << g_settings->getFloat("movement_speed_crouch");
1464 pkt << g_settings->getFloat("movement_speed_fast");
1465 pkt << g_settings->getFloat("movement_speed_climb");
1466 pkt << g_settings->getFloat("movement_speed_jump");
1467 pkt << g_settings->getFloat("movement_liquid_fluidity");
1468 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1469 pkt << g_settings->getFloat("movement_liquid_sink");
1470 pkt << g_settings->getFloat("movement_gravity");
1475 void Server::SendHP(u16 peer_id, u8 hp)
1477 DSTACK(__FUNCTION_NAME);
1479 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1484 void Server::SendBreath(u16 peer_id, u16 breath)
1486 DSTACK(__FUNCTION_NAME);
1488 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1489 pkt << (u16) breath;
1493 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1495 DSTACK(__FUNCTION_NAME);
1497 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1500 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1501 pkt << custom_reason;
1506 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1508 DSTACK(__FUNCTION_NAME);
1510 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1515 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1516 v3f camera_point_target)
1518 DSTACK(__FUNCTION_NAME);
1520 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1521 pkt << set_camera_point_target << camera_point_target;
1525 void Server::SendItemDef(u16 peer_id,
1526 IItemDefManager *itemdef, u16 protocol_version)
1528 DSTACK(__FUNCTION_NAME);
1530 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1534 u32 length of the next item
1535 zlib-compressed serialized ItemDefManager
1537 std::ostringstream tmp_os(std::ios::binary);
1538 itemdef->serialize(tmp_os, protocol_version);
1539 std::ostringstream tmp_os2(std::ios::binary);
1540 compressZlib(tmp_os.str(), tmp_os2);
1541 pkt.putLongString(tmp_os2.str());
1544 verbosestream << "Server: Sending item definitions to id(" << peer_id
1545 << "): size=" << pkt.getSize() << std::endl;
1550 void Server::SendNodeDef(u16 peer_id,
1551 INodeDefManager *nodedef, u16 protocol_version)
1553 DSTACK(__FUNCTION_NAME);
1555 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1559 u32 length of the next item
1560 zlib-compressed serialized NodeDefManager
1562 std::ostringstream tmp_os(std::ios::binary);
1563 nodedef->serialize(tmp_os, protocol_version);
1564 std::ostringstream tmp_os2(std::ios::binary);
1565 compressZlib(tmp_os.str(), tmp_os2);
1567 pkt.putLongString(tmp_os2.str());
1570 verbosestream << "Server: Sending node definitions to id(" << peer_id
1571 << "): size=" << pkt.getSize() << std::endl;
1577 Non-static send methods
1580 void Server::SendInventory(PlayerSAO* playerSAO)
1582 DSTACK(__FUNCTION_NAME);
1584 UpdateCrafting(playerSAO->getPlayer());
1590 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1592 std::ostringstream os;
1593 playerSAO->getInventory()->serialize(os);
1595 std::string s = os.str();
1597 pkt.putRawString(s.c_str(), s.size());
1601 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1603 DSTACK(__FUNCTION_NAME);
1605 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1608 if (peer_id != PEER_ID_INEXISTENT) {
1612 m_clients.sendToAll(0, &pkt, true);
1616 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1617 const std::string &formname)
1619 DSTACK(__FUNCTION_NAME);
1621 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1623 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1629 // Spawns a particle on peer with peer_id
1630 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1631 float expirationtime, float size, bool collisiondetection,
1632 bool vertical, std::string texture)
1634 DSTACK(__FUNCTION_NAME);
1636 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1638 pkt << pos << velocity << acceleration << expirationtime
1639 << size << collisiondetection;
1640 pkt.putLongString(texture);
1643 if (peer_id != PEER_ID_INEXISTENT) {
1647 m_clients.sendToAll(0, &pkt, true);
1651 // Adds a ParticleSpawner on peer with peer_id
1652 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1653 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1654 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1656 DSTACK(__FUNCTION_NAME);
1658 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1660 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1661 << minacc << maxacc << minexptime << maxexptime << minsize
1662 << maxsize << collisiondetection;
1664 pkt.putLongString(texture);
1666 pkt << id << vertical;
1668 if (peer_id != PEER_ID_INEXISTENT) {
1672 m_clients.sendToAll(0, &pkt, true);
1676 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1678 DSTACK(__FUNCTION_NAME);
1680 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1682 // Ugly error in this packet
1685 if (peer_id != PEER_ID_INEXISTENT) {
1689 m_clients.sendToAll(0, &pkt, true);
1694 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1696 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1698 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1699 << form->text << form->number << form->item << form->dir
1700 << form->align << form->offset << form->world_pos << form->size;
1705 void Server::SendHUDRemove(u16 peer_id, u32 id)
1707 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1712 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1714 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1715 pkt << id << (u8) stat;
1719 case HUD_STAT_SCALE:
1720 case HUD_STAT_ALIGN:
1721 case HUD_STAT_OFFSET:
1722 pkt << *(v2f *) value;
1726 pkt << *(std::string *) value;
1728 case HUD_STAT_WORLD_POS:
1729 pkt << *(v3f *) value;
1732 pkt << *(v2s32 *) value;
1734 case HUD_STAT_NUMBER:
1738 pkt << *(u32 *) value;
1745 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1747 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1749 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1751 pkt << flags << mask;
1756 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1758 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1759 pkt << param << value;
1763 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1764 const std::string &type, const std::vector<std::string> ¶ms)
1766 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1767 pkt << bgcolor << type << (u16) params.size();
1769 for(size_t i=0; i<params.size(); i++)
1775 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1778 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1781 pkt << do_override << (u16) (ratio * 65535);
1786 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1788 DSTACK(__FUNCTION_NAME);
1790 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1791 pkt << time << time_speed;
1793 if (peer_id == PEER_ID_INEXISTENT) {
1794 m_clients.sendToAll(0, &pkt, true);
1801 void Server::SendPlayerHP(u16 peer_id)
1803 DSTACK(__FUNCTION_NAME);
1804 PlayerSAO *playersao = getPlayerSAO(peer_id);
1805 // In some rare case, if the player is disconnected
1806 // while Lua call l_punch, for example, this can be NULL
1810 SendHP(peer_id, playersao->getHP());
1811 m_script->player_event(playersao,"health_changed");
1813 // Send to other clients
1814 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1815 ActiveObjectMessage aom(playersao->getId(), true, str);
1816 playersao->m_messages_out.push(aom);
1819 void Server::SendPlayerBreath(u16 peer_id)
1821 DSTACK(__FUNCTION_NAME);
1822 PlayerSAO *playersao = getPlayerSAO(peer_id);
1825 m_script->player_event(playersao, "breath_changed");
1826 SendBreath(peer_id, playersao->getBreath());
1829 void Server::SendMovePlayer(u16 peer_id)
1831 DSTACK(__FUNCTION_NAME);
1832 Player *player = m_env->getPlayer(peer_id);
1835 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1836 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1839 v3f pos = player->getPosition();
1840 f32 pitch = player->getPitch();
1841 f32 yaw = player->getYaw();
1842 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1843 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1844 << " pitch=" << pitch
1852 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1854 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1857 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1858 << animation_frames[3] << animation_speed;
1863 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1865 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1866 pkt << first << third;
1869 void Server::SendPlayerPrivileges(u16 peer_id)
1871 Player *player = m_env->getPlayer(peer_id);
1873 if(player->peer_id == PEER_ID_INEXISTENT)
1876 std::set<std::string> privs;
1877 m_script->getAuth(player->getName(), NULL, &privs);
1879 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1880 pkt << (u16) privs.size();
1882 for(std::set<std::string>::const_iterator i = privs.begin();
1883 i != privs.end(); i++) {
1890 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1892 Player *player = m_env->getPlayer(peer_id);
1894 if(player->peer_id == PEER_ID_INEXISTENT)
1897 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1898 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1902 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1904 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1905 pkt.putRawString(datas.c_str(), datas.size());
1907 return pkt.getSize();
1910 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1912 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1913 datas.size(), peer_id);
1915 pkt.putRawString(datas.c_str(), datas.size());
1917 m_clients.send(pkt.getPeerId(),
1918 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1923 s32 Server::playSound(const SimpleSoundSpec &spec,
1924 const ServerSoundParams ¶ms)
1926 // Find out initial position of sound
1927 bool pos_exists = false;
1928 v3f pos = params.getPos(m_env, &pos_exists);
1929 // If position is not found while it should be, cancel sound
1930 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1933 // Filter destination clients
1934 std::vector<u16> dst_clients;
1935 if(params.to_player != "")
1937 Player *player = m_env->getPlayer(params.to_player.c_str());
1939 infostream<<"Server::playSound: Player \""<<params.to_player
1940 <<"\" not found"<<std::endl;
1943 if(player->peer_id == PEER_ID_INEXISTENT){
1944 infostream<<"Server::playSound: Player \""<<params.to_player
1945 <<"\" not connected"<<std::endl;
1948 dst_clients.push_back(player->peer_id);
1951 std::vector<u16> clients = m_clients.getClientIDs();
1953 for(std::vector<u16>::iterator
1954 i = clients.begin(); i != clients.end(); ++i) {
1955 Player *player = m_env->getPlayer(*i);
1960 if(player->getPosition().getDistanceFrom(pos) >
1961 params.max_hear_distance)
1964 dst_clients.push_back(*i);
1968 if(dst_clients.empty())
1972 s32 id = m_next_sound_id++;
1973 // The sound will exist as a reference in m_playing_sounds
1974 m_playing_sounds[id] = ServerPlayingSound();
1975 ServerPlayingSound &psound = m_playing_sounds[id];
1976 psound.params = params;
1978 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1979 pkt << id << spec.name << (float) (spec.gain * params.gain)
1980 << (u8) params.type << pos << params.object << params.loop;
1982 for(std::vector<u16>::iterator i = dst_clients.begin();
1983 i != dst_clients.end(); i++) {
1984 psound.clients.insert(*i);
1985 m_clients.send(*i, 0, &pkt, true);
1989 void Server::stopSound(s32 handle)
1991 // Get sound reference
1992 std::map<s32, ServerPlayingSound>::iterator i =
1993 m_playing_sounds.find(handle);
1994 if(i == m_playing_sounds.end())
1996 ServerPlayingSound &psound = i->second;
1998 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2001 for(std::set<u16>::iterator i = psound.clients.begin();
2002 i != psound.clients.end(); i++) {
2004 m_clients.send(*i, 0, &pkt, true);
2006 // Remove sound reference
2007 m_playing_sounds.erase(i);
2010 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2011 std::vector<u16> *far_players, float far_d_nodes)
2013 float maxd = far_d_nodes*BS;
2014 v3f p_f = intToFloat(p, BS);
2016 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2019 std::vector<u16> clients = m_clients.getClientIDs();
2020 for(std::vector<u16>::iterator i = clients.begin();
2021 i != clients.end(); ++i) {
2024 if(Player *player = m_env->getPlayer(*i)) {
2025 // If player is far away, only set modified blocks not sent
2026 v3f player_pos = player->getPosition();
2027 if(player_pos.getDistanceFrom(p_f) > maxd) {
2028 far_players->push_back(*i);
2035 m_clients.send(*i, 0, &pkt, true);
2039 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2040 std::vector<u16> *far_players, float far_d_nodes,
2041 bool remove_metadata)
2043 float maxd = far_d_nodes*BS;
2044 v3f p_f = intToFloat(p, BS);
2046 std::vector<u16> clients = m_clients.getClientIDs();
2047 for(std::vector<u16>::iterator i = clients.begin();
2048 i != clients.end(); ++i) {
2052 if(Player *player = m_env->getPlayer(*i)) {
2053 // If player is far away, only set modified blocks not sent
2054 v3f player_pos = player->getPosition();
2055 if(player_pos.getDistanceFrom(p_f) > maxd) {
2056 far_players->push_back(*i);
2062 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2064 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2066 pkt << p << n.param0 << n.param1 << n.param2
2067 << (u8) (remove_metadata ? 0 : 1);
2069 if (!remove_metadata) {
2070 if (client->net_proto_version <= 21) {
2071 // Old clients always clear metadata; fix it
2072 // by sending the full block again.
2073 client->SetBlockNotSent(p);
2080 if (pkt.getSize() > 0)
2081 m_clients.send(*i, 0, &pkt, true);
2085 void Server::setBlockNotSent(v3s16 p)
2087 std::vector<u16> clients = m_clients.getClientIDs();
2089 for(std::vector<u16>::iterator i = clients.begin();
2090 i != clients.end(); ++i) {
2091 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2092 client->SetBlockNotSent(p);
2097 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2099 DSTACK(__FUNCTION_NAME);
2101 v3s16 p = block->getPos();
2104 Create a packet with the block in the right format
2107 std::ostringstream os(std::ios_base::binary);
2108 block->serialize(os, ver, false);
2109 block->serializeNetworkSpecific(os, net_proto_version);
2110 std::string s = os.str();
2112 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2115 pkt.putRawString(s.c_str(), s.size());
2119 void Server::SendBlocks(float dtime)
2121 DSTACK(__FUNCTION_NAME);
2123 JMutexAutoLock envlock(m_env_mutex);
2124 //TODO check if one big lock could be faster then multiple small ones
2126 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2128 std::vector<PrioritySortedBlockTransfer> queue;
2130 s32 total_sending = 0;
2133 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2135 std::vector<u16> clients = m_clients.getClientIDs();
2138 for(std::vector<u16>::iterator i = clients.begin();
2139 i != clients.end(); ++i) {
2140 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2145 total_sending += client->SendingCount();
2146 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2152 // Lowest priority number comes first.
2153 // Lowest is most important.
2154 std::sort(queue.begin(), queue.end());
2157 for(u32 i=0; i<queue.size(); i++)
2159 //TODO: Calculate limit dynamically
2160 if(total_sending >= g_settings->getS32
2161 ("max_simultaneous_block_sends_server_total"))
2164 PrioritySortedBlockTransfer q = queue[i];
2166 MapBlock *block = NULL;
2169 block = m_env->getMap().getBlockNoCreate(q.pos);
2171 catch(InvalidPositionException &e)
2176 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2181 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2183 client->SentBlock(q.pos);
2189 void Server::fillMediaCache()
2191 DSTACK(__FUNCTION_NAME);
2193 infostream<<"Server: Calculating media file checksums"<<std::endl;
2195 // Collect all media file paths
2196 std::vector<std::string> paths;
2197 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2198 i != m_mods.end(); i++) {
2199 const ModSpec &mod = *i;
2200 paths.push_back(mod.path + DIR_DELIM + "textures");
2201 paths.push_back(mod.path + DIR_DELIM + "sounds");
2202 paths.push_back(mod.path + DIR_DELIM + "media");
2203 paths.push_back(mod.path + DIR_DELIM + "models");
2205 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2207 // Collect media file information from paths into cache
2208 for(std::vector<std::string>::iterator i = paths.begin();
2209 i != paths.end(); i++) {
2210 std::string mediapath = *i;
2211 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2212 for (u32 j = 0; j < dirlist.size(); j++) {
2213 if (dirlist[j].dir) // Ignode dirs
2215 std::string filename = dirlist[j].name;
2216 // If name contains illegal characters, ignore the file
2217 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2218 infostream<<"Server: ignoring illegal file name: \""
2219 << filename << "\"" << std::endl;
2222 // If name is not in a supported format, ignore it
2223 const char *supported_ext[] = {
2224 ".png", ".jpg", ".bmp", ".tga",
2225 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2227 ".x", ".b3d", ".md2", ".obj",
2230 if (removeStringEnd(filename, supported_ext) == ""){
2231 infostream << "Server: ignoring unsupported file extension: \""
2232 << filename << "\"" << std::endl;
2235 // Ok, attempt to load the file and add to cache
2236 std::string filepath = mediapath + DIR_DELIM + filename;
2238 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2240 errorstream << "Server::fillMediaCache(): Could not open \""
2241 << filename << "\" for reading" << std::endl;
2244 std::ostringstream tmp_os(std::ios_base::binary);
2248 fis.read(buf, 1024);
2249 std::streamsize len = fis.gcount();
2250 tmp_os.write(buf, len);
2259 errorstream<<"Server::fillMediaCache(): Failed to read \""
2260 << filename << "\"" << std::endl;
2263 if(tmp_os.str().length() == 0) {
2264 errorstream << "Server::fillMediaCache(): Empty file \""
2265 << filepath << "\"" << std::endl;
2270 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2272 unsigned char *digest = sha1.getDigest();
2273 std::string sha1_base64 = base64_encode(digest, 20);
2274 std::string sha1_hex = hex_encode((char*)digest, 20);
2278 m_media[filename] = MediaInfo(filepath, sha1_base64);
2279 verbosestream << "Server: " << sha1_hex << " is " << filename
2285 struct SendableMediaAnnouncement
2288 std::string sha1_digest;
2290 SendableMediaAnnouncement(const std::string &name_="",
2291 const std::string &sha1_digest_=""):
2293 sha1_digest(sha1_digest_)
2297 void Server::sendMediaAnnouncement(u16 peer_id)
2299 DSTACK(__FUNCTION_NAME);
2301 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2304 std::vector<SendableMediaAnnouncement> file_announcements;
2306 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2307 i != m_media.end(); i++){
2309 file_announcements.push_back(
2310 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2314 std::ostringstream os(std::ios_base::binary);
2316 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2317 pkt << (u16) file_announcements.size();
2319 for (std::vector<SendableMediaAnnouncement>::iterator
2320 j = file_announcements.begin();
2321 j != file_announcements.end(); ++j) {
2322 pkt << j->name << j->sha1_digest;
2325 pkt << g_settings->get("remote_media");
2329 struct SendableMedia
2335 SendableMedia(const std::string &name_="", const std::string &path_="",
2336 const std::string &data_=""):
2343 void Server::sendRequestedMedia(u16 peer_id,
2344 const std::vector<std::string> &tosend)
2346 DSTACK(__FUNCTION_NAME);
2348 verbosestream<<"Server::sendRequestedMedia(): "
2349 <<"Sending files to client"<<std::endl;
2353 // Put 5kB in one bunch (this is not accurate)
2354 u32 bytes_per_bunch = 5000;
2356 std::vector< std::vector<SendableMedia> > file_bunches;
2357 file_bunches.push_back(std::vector<SendableMedia>());
2359 u32 file_size_bunch_total = 0;
2361 for(std::vector<std::string>::const_iterator i = tosend.begin();
2362 i != tosend.end(); ++i) {
2363 const std::string &name = *i;
2365 if(m_media.find(name) == m_media.end()) {
2366 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2367 <<"unknown file \""<<(name)<<"\""<<std::endl;
2371 //TODO get path + name
2372 std::string tpath = m_media[name].path;
2375 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2376 if(fis.good() == false){
2377 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2378 <<tpath<<"\" for reading"<<std::endl;
2381 std::ostringstream tmp_os(std::ios_base::binary);
2385 fis.read(buf, 1024);
2386 std::streamsize len = fis.gcount();
2387 tmp_os.write(buf, len);
2388 file_size_bunch_total += len;
2397 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2398 <<name<<"\""<<std::endl;
2401 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2402 <<tname<<"\""<<std::endl;*/
2404 file_bunches[file_bunches.size()-1].push_back(
2405 SendableMedia(name, tpath, tmp_os.str()));
2407 // Start next bunch if got enough data
2408 if(file_size_bunch_total >= bytes_per_bunch) {
2409 file_bunches.push_back(std::vector<SendableMedia>());
2410 file_size_bunch_total = 0;
2415 /* Create and send packets */
2417 u16 num_bunches = file_bunches.size();
2418 for(u16 i = 0; i < num_bunches; i++) {
2421 u16 total number of texture bunches
2422 u16 index of this bunch
2423 u32 number of files in this bunch
2432 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2433 pkt << num_bunches << i << (u32) file_bunches[i].size();
2435 for(std::vector<SendableMedia>::iterator
2436 j = file_bunches[i].begin();
2437 j != file_bunches[i].end(); ++j) {
2439 pkt.putLongString(j->data);
2442 verbosestream << "Server::sendRequestedMedia(): bunch "
2443 << i << "/" << num_bunches
2444 << " files=" << file_bunches[i].size()
2445 << " size=" << pkt.getSize() << std::endl;
2450 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2452 if(m_detached_inventories.count(name) == 0) {
2453 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2456 Inventory *inv = m_detached_inventories[name];
2457 std::ostringstream os(std::ios_base::binary);
2459 os << serializeString(name);
2463 std::string s = os.str();
2465 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2466 pkt.putRawString(s.c_str(), s.size());
2468 if (peer_id != PEER_ID_INEXISTENT) {
2472 m_clients.sendToAll(0, &pkt, true);
2476 void Server::sendDetachedInventories(u16 peer_id)
2478 DSTACK(__FUNCTION_NAME);
2480 for(std::map<std::string, Inventory*>::iterator
2481 i = m_detached_inventories.begin();
2482 i != m_detached_inventories.end(); i++) {
2483 const std::string &name = i->first;
2484 //Inventory *inv = i->second;
2485 sendDetachedInventory(name, peer_id);
2493 void Server::DiePlayer(u16 peer_id)
2495 DSTACK(__FUNCTION_NAME);
2497 PlayerSAO *playersao = getPlayerSAO(peer_id);
2500 infostream << "Server::DiePlayer(): Player "
2501 << playersao->getPlayer()->getName()
2502 << " dies" << std::endl;
2504 playersao->setHP(0);
2506 // Trigger scripted stuff
2507 m_script->on_dieplayer(playersao);
2509 SendPlayerHP(peer_id);
2510 SendDeathscreen(peer_id, false, v3f(0,0,0));
2513 void Server::RespawnPlayer(u16 peer_id)
2515 DSTACK(__FUNCTION_NAME);
2517 PlayerSAO *playersao = getPlayerSAO(peer_id);
2520 infostream << "Server::RespawnPlayer(): Player "
2521 << playersao->getPlayer()->getName()
2522 << " respawns" << std::endl;
2524 playersao->setHP(PLAYER_MAX_HP);
2525 playersao->setBreath(PLAYER_MAX_BREATH);
2527 SendPlayerHP(peer_id);
2528 SendPlayerBreath(peer_id);
2530 bool repositioned = m_script->on_respawnplayer(playersao);
2532 v3f pos = findSpawnPos();
2533 // setPos will send the new position to client
2534 playersao->setPos(pos);
2538 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2540 DSTACK(__FUNCTION_NAME);
2542 SendAccessDenied(peer_id, reason, custom_reason);
2543 m_clients.event(peer_id, CSE_SetDenied);
2544 m_con.DisconnectPeer(peer_id);
2547 // 13/03/15: remove this function when protocol version 25 will become
2548 // the minimum version for MT users, maybe in 1 year
2549 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2551 DSTACK(__FUNCTION_NAME);
2553 SendAccessDenied_Legacy(peer_id, reason);
2554 m_clients.event(peer_id, CSE_SetDenied);
2555 m_con.DisconnectPeer(peer_id);
2558 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2560 DSTACK(__FUNCTION_NAME);
2561 std::wstring message;
2564 Clear references to playing sounds
2566 for(std::map<s32, ServerPlayingSound>::iterator
2567 i = m_playing_sounds.begin();
2568 i != m_playing_sounds.end();)
2570 ServerPlayingSound &psound = i->second;
2571 psound.clients.erase(peer_id);
2572 if(psound.clients.empty())
2573 m_playing_sounds.erase(i++);
2578 Player *player = m_env->getPlayer(peer_id);
2580 // Collect information about leaving in chat
2582 if(player != NULL && reason != CDR_DENY)
2584 std::wstring name = narrow_to_wide(player->getName());
2587 message += L" left the game.";
2588 if(reason == CDR_TIMEOUT)
2589 message += L" (timed out)";
2593 /* Run scripts and remove from environment */
2597 PlayerSAO *playersao = player->getPlayerSAO();
2600 m_script->on_leaveplayer(playersao);
2602 playersao->disconnected();
2610 if(player != NULL && reason != CDR_DENY) {
2611 std::ostringstream os(std::ios_base::binary);
2612 std::vector<u16> clients = m_clients.getClientIDs();
2614 for(std::vector<u16>::iterator i = clients.begin();
2615 i != clients.end(); ++i) {
2617 Player *player = m_env->getPlayer(*i);
2621 // Get name of player
2622 os << player->getName() << " ";
2625 actionstream << player->getName() << " "
2626 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2627 << " List of players: " << os.str() << std::endl;
2631 JMutexAutoLock env_lock(m_env_mutex);
2632 m_clients.DeleteClient(peer_id);
2636 // Send leave chat message to all remaining clients
2637 if(message.length() != 0)
2638 SendChatMessage(PEER_ID_INEXISTENT,message);
2641 void Server::UpdateCrafting(Player* player)
2643 DSTACK(__FUNCTION_NAME);
2645 // Get a preview for crafting
2647 InventoryLocation loc;
2648 loc.setPlayer(player->getName());
2649 getCraftingResult(&player->inventory, preview, false, this);
2650 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2652 // Put the new preview in
2653 InventoryList *plist = player->inventory.getList("craftpreview");
2654 sanity_check(plist);
2655 sanity_check(plist->getSize() >= 1);
2656 plist->changeItem(0, preview);
2659 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2661 RemoteClient *client = getClientNoEx(peer_id,state_min);
2663 throw ClientNotFoundException("Client not found");
2667 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2669 return m_clients.getClientNoEx(peer_id, state_min);
2672 std::string Server::getPlayerName(u16 peer_id)
2674 Player *player = m_env->getPlayer(peer_id);
2676 return "[id="+itos(peer_id)+"]";
2677 return player->getName();
2680 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2682 Player *player = m_env->getPlayer(peer_id);
2685 return player->getPlayerSAO();
2688 std::wstring Server::getStatusString()
2690 std::wostringstream os(std::ios_base::binary);
2693 os<<L"version="<<narrow_to_wide(g_version_string);
2695 os<<L", uptime="<<m_uptime.get();
2697 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2698 // Information about clients
2701 std::vector<u16> clients = m_clients.getClientIDs();
2702 for(std::vector<u16>::iterator i = clients.begin();
2703 i != clients.end(); ++i) {
2705 Player *player = m_env->getPlayer(*i);
2706 // Get name of player
2707 std::wstring name = L"unknown";
2709 name = narrow_to_wide(player->getName());
2710 // Add name to information string
2718 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2719 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2720 if(g_settings->get("motd") != "")
2721 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2725 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2727 std::set<std::string> privs;
2728 m_script->getAuth(name, NULL, &privs);
2732 bool Server::checkPriv(const std::string &name, const std::string &priv)
2734 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2735 return (privs.count(priv) != 0);
2738 void Server::reportPrivsModified(const std::string &name)
2741 std::vector<u16> clients = m_clients.getClientIDs();
2742 for(std::vector<u16>::iterator i = clients.begin();
2743 i != clients.end(); ++i) {
2744 Player *player = m_env->getPlayer(*i);
2745 reportPrivsModified(player->getName());
2748 Player *player = m_env->getPlayer(name.c_str());
2751 SendPlayerPrivileges(player->peer_id);
2752 PlayerSAO *sao = player->getPlayerSAO();
2755 sao->updatePrivileges(
2756 getPlayerEffectivePrivs(name),
2761 void Server::reportInventoryFormspecModified(const std::string &name)
2763 Player *player = m_env->getPlayer(name.c_str());
2766 SendPlayerInventoryFormspec(player->peer_id);
2769 void Server::setIpBanned(const std::string &ip, const std::string &name)
2771 m_banmanager->add(ip, name);
2774 void Server::unsetIpBanned(const std::string &ip_or_name)
2776 m_banmanager->remove(ip_or_name);
2779 std::string Server::getBanDescription(const std::string &ip_or_name)
2781 return m_banmanager->getBanDescription(ip_or_name);
2784 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2786 Player *player = m_env->getPlayer(name);
2790 if (player->peer_id == PEER_ID_INEXISTENT)
2793 SendChatMessage(player->peer_id, msg);
2796 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2798 Player *player = m_env->getPlayer(playername);
2802 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2806 SendShowFormspecMessage(player->peer_id, formspec, formname);
2810 u32 Server::hudAdd(Player *player, HudElement *form) {
2814 u32 id = player->addHud(form);
2816 SendHUDAdd(player->peer_id, id, form);
2821 bool Server::hudRemove(Player *player, u32 id) {
2825 HudElement* todel = player->removeHud(id);
2832 SendHUDRemove(player->peer_id, id);
2836 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2840 SendHUDChange(player->peer_id, id, stat, data);
2844 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2848 SendHUDSetFlags(player->peer_id, flags, mask);
2849 player->hud_flags = flags;
2851 PlayerSAO* playersao = player->getPlayerSAO();
2853 if (playersao == NULL)
2856 m_script->player_event(playersao, "hud_changed");
2860 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2863 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2866 std::ostringstream os(std::ios::binary);
2867 writeS32(os, hotbar_itemcount);
2868 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2872 void Server::hudSetHotbarImage(Player *player, std::string name) {
2876 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2879 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2883 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2886 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2891 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2895 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2900 SendEyeOffset(player->peer_id, first, third);
2904 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2905 const std::string &type, const std::vector<std::string> ¶ms)
2910 SendSetSky(player->peer_id, bgcolor, type, params);
2914 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2920 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2924 void Server::notifyPlayers(const std::wstring &msg)
2926 SendChatMessage(PEER_ID_INEXISTENT,msg);
2929 void Server::spawnParticle(const char *playername, v3f pos,
2930 v3f velocity, v3f acceleration,
2931 float expirationtime, float size, bool
2932 collisiondetection, bool vertical, std::string texture)
2934 Player *player = m_env->getPlayer(playername);
2937 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2938 expirationtime, size, collisiondetection, vertical, texture);
2941 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2942 float expirationtime, float size,
2943 bool collisiondetection, bool vertical, std::string texture)
2945 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2946 expirationtime, size, collisiondetection, vertical, texture);
2949 u32 Server::addParticleSpawner(const char *playername,
2950 u16 amount, float spawntime,
2951 v3f minpos, v3f maxpos,
2952 v3f minvel, v3f maxvel,
2953 v3f minacc, v3f maxacc,
2954 float minexptime, float maxexptime,
2955 float minsize, float maxsize,
2956 bool collisiondetection, bool vertical, std::string texture)
2958 Player *player = m_env->getPlayer(playername);
2963 for(;;) // look for unused particlespawner id
2966 if (std::find(m_particlespawner_ids.begin(),
2967 m_particlespawner_ids.end(), id)
2968 == m_particlespawner_ids.end())
2970 m_particlespawner_ids.push_back(id);
2975 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2976 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2977 minexptime, maxexptime, minsize, maxsize,
2978 collisiondetection, vertical, texture, id);
2983 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2984 v3f minpos, v3f maxpos,
2985 v3f minvel, v3f maxvel,
2986 v3f minacc, v3f maxacc,
2987 float minexptime, float maxexptime,
2988 float minsize, float maxsize,
2989 bool collisiondetection, bool vertical, std::string texture)
2992 for(;;) // look for unused particlespawner id
2995 if (std::find(m_particlespawner_ids.begin(),
2996 m_particlespawner_ids.end(), id)
2997 == m_particlespawner_ids.end())
2999 m_particlespawner_ids.push_back(id);
3004 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3005 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3006 minexptime, maxexptime, minsize, maxsize,
3007 collisiondetection, vertical, texture, id);
3012 void Server::deleteParticleSpawner(const char *playername, u32 id)
3014 Player *player = m_env->getPlayer(playername);
3018 m_particlespawner_ids.erase(
3019 std::remove(m_particlespawner_ids.begin(),
3020 m_particlespawner_ids.end(), id),
3021 m_particlespawner_ids.end());
3022 SendDeleteParticleSpawner(player->peer_id, id);
3025 void Server::deleteParticleSpawnerAll(u32 id)
3027 m_particlespawner_ids.erase(
3028 std::remove(m_particlespawner_ids.begin(),
3029 m_particlespawner_ids.end(), id),
3030 m_particlespawner_ids.end());
3031 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3034 Inventory* Server::createDetachedInventory(const std::string &name)
3036 if(m_detached_inventories.count(name) > 0){
3037 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3038 delete m_detached_inventories[name];
3040 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3042 Inventory *inv = new Inventory(m_itemdef);
3044 m_detached_inventories[name] = inv;
3045 //TODO find a better way to do this
3046 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3053 BoolScopeSet(bool *dst, bool val):
3056 m_orig_state = *m_dst;
3061 *m_dst = m_orig_state;
3068 // actions: time-reversed list
3069 // Return value: success/failure
3070 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3071 std::list<std::string> *log)
3073 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3074 ServerMap *map = (ServerMap*)(&m_env->getMap());
3076 // Fail if no actions to handle
3077 if(actions.empty()){
3078 log->push_back("Nothing to do.");
3085 for(std::list<RollbackAction>::const_iterator
3086 i = actions.begin();
3087 i != actions.end(); i++)
3089 const RollbackAction &action = *i;
3091 bool success = action.applyRevert(map, this, this);
3094 std::ostringstream os;
3095 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3096 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3098 log->push_back(os.str());
3100 std::ostringstream os;
3101 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3102 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3104 log->push_back(os.str());
3108 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3109 <<" failed"<<std::endl;
3111 // Call it done if less than half failed
3112 return num_failed <= num_tried/2;
3115 // IGameDef interface
3117 IItemDefManager* Server::getItemDefManager()
3121 INodeDefManager* Server::getNodeDefManager()
3125 ICraftDefManager* Server::getCraftDefManager()
3129 ITextureSource* Server::getTextureSource()
3133 IShaderSource* Server::getShaderSource()
3137 scene::ISceneManager* Server::getSceneManager()
3142 u16 Server::allocateUnknownNodeId(const std::string &name)
3144 return m_nodedef->allocateDummy(name);
3146 ISoundManager* Server::getSoundManager()
3148 return &dummySoundManager;
3150 MtEventManager* Server::getEventManager()
3155 IWritableItemDefManager* Server::getWritableItemDefManager()
3159 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3163 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3168 const ModSpec* Server::getModSpec(const std::string &modname)
3170 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3171 i != m_mods.end(); i++){
3172 const ModSpec &mod = *i;
3173 if(mod.name == modname)
3178 void Server::getModNames(std::vector<std::string> &modlist)
3180 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3181 modlist.push_back(i->name);
3184 std::string Server::getBuiltinLuaPath()
3186 return porting::path_share + DIR_DELIM + "builtin";
3189 v3f Server::findSpawnPos()
3191 ServerMap &map = m_env->getServerMap();
3193 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3194 return nodeposf * BS;
3197 // Default position is static_spawnpoint
3198 // We will return it if we don't found a good place
3199 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3201 s16 water_level = map.getWaterLevel();
3203 bool is_good = false;
3205 // Try to find a good place a few times
3206 for(s32 i = 0; i < 1000 && !is_good; i++) {
3208 // We're going to try to throw the player to this position
3209 v2s16 nodepos2d = v2s16(
3210 -range + (myrand() % (range * 2)),
3211 -range + (myrand() % (range * 2)));
3213 // Get ground height at point
3214 s16 groundheight = map.findGroundLevel(nodepos2d);
3215 if (groundheight <= water_level) // Don't go underwater
3217 if (groundheight > water_level + 6) // Don't go to high places
3220 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3223 for (s32 i = 0; i < 10; i++) {
3224 v3s16 blockpos = getNodeBlockPos(nodepos);
3225 map.emergeBlock(blockpos, true);
3226 content_t c = map.getNodeNoEx(nodepos).getContent();
3227 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3229 if (air_count >= 2){
3238 return intToFloat(nodepos, BS);
3241 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3243 bool newplayer = false;
3246 Try to get an existing player
3248 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3250 // If player is already connected, cancel
3251 if(player != NULL && player->peer_id != 0)
3253 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3258 If player with the wanted peer_id already exists, cancel.
3260 if(m_env->getPlayer(peer_id) != NULL)
3262 infostream<<"emergePlayer(): Player with wrong name but same"
3263 " peer_id already exists"<<std::endl;
3267 // Load player if it isn't already loaded
3269 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3272 // Create player if it doesn't exist
3275 player = new RemotePlayer(this, name);
3276 // Set player position
3277 infostream<<"Server: Finding spawn place for player \""
3278 <<name<<"\""<<std::endl;
3279 v3f pos = findSpawnPos();
3280 player->setPosition(pos);
3282 // Make sure the player is saved
3283 player->setModified(true);
3285 // Add player to environment
3286 m_env->addPlayer(player);
3289 // Create a new player active object
3290 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3291 getPlayerEffectivePrivs(player->getName()),
3294 /* Clean up old HUD elements from previous sessions */
3297 /* Add object to environment */
3298 m_env->addActiveObject(playersao);
3302 m_script->on_newplayer(playersao);
3308 void dedicated_server_loop(Server &server, bool &kill)
3310 DSTACK(__FUNCTION_NAME);
3312 verbosestream<<"dedicated_server_loop()"<<std::endl;
3314 IntervalLimiter m_profiler_interval;
3318 float steplen = g_settings->getFloat("dedicated_server_step");
3319 // This is kind of a hack but can be done like this
3320 // because server.step() is very light
3322 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3323 sleep_ms((int)(steplen*1000.0));
3325 server.step(steplen);
3327 if(server.getShutdownRequested() || kill)
3329 infostream<<"Dedicated server quitting"<<std::endl;
3331 if(g_settings->getBool("server_announce"))
3332 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3340 float profiler_print_interval =
3341 g_settings->getFloat("profiler_print_interval");
3342 if(profiler_print_interval != 0)
3344 if(m_profiler_interval.step(steplen, profiler_print_interval))
3346 infostream<<"Profiler:"<<std::endl;
3347 g_profiler->print(infostream);
3348 g_profiler->clear();