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->runNodeResolverCallbacks();
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::wstring &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);
1806 SendHP(peer_id, playersao->getHP());
1807 m_script->player_event(playersao,"health_changed");
1809 // Send to other clients
1810 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1811 ActiveObjectMessage aom(playersao->getId(), true, str);
1812 playersao->m_messages_out.push(aom);
1815 void Server::SendPlayerBreath(u16 peer_id)
1817 DSTACK(__FUNCTION_NAME);
1818 PlayerSAO *playersao = getPlayerSAO(peer_id);
1821 m_script->player_event(playersao, "breath_changed");
1822 SendBreath(peer_id, playersao->getBreath());
1825 void Server::SendMovePlayer(u16 peer_id)
1827 DSTACK(__FUNCTION_NAME);
1828 Player *player = m_env->getPlayer(peer_id);
1831 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1832 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1835 v3f pos = player->getPosition();
1836 f32 pitch = player->getPitch();
1837 f32 yaw = player->getYaw();
1838 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1839 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1840 << " pitch=" << pitch
1848 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1850 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1853 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1854 << animation_frames[3] << animation_speed;
1859 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1861 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1862 pkt << first << third;
1865 void Server::SendPlayerPrivileges(u16 peer_id)
1867 Player *player = m_env->getPlayer(peer_id);
1869 if(player->peer_id == PEER_ID_INEXISTENT)
1872 std::set<std::string> privs;
1873 m_script->getAuth(player->getName(), NULL, &privs);
1875 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1876 pkt << (u16) privs.size();
1878 for(std::set<std::string>::const_iterator i = privs.begin();
1879 i != privs.end(); i++) {
1886 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1888 Player *player = m_env->getPlayer(peer_id);
1890 if(player->peer_id == PEER_ID_INEXISTENT)
1893 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1894 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1898 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1900 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, peer_id);
1901 pkt.putRawString(datas.c_str(), datas.size());
1903 return pkt.getSize();
1906 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1908 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1911 pkt.putRawString(datas.c_str(), datas.size());
1913 m_clients.send(pkt.getPeerId(),
1914 clientCommandFactoryTable[pkt.getCommand()].channel,
1919 s32 Server::playSound(const SimpleSoundSpec &spec,
1920 const ServerSoundParams ¶ms)
1922 // Find out initial position of sound
1923 bool pos_exists = false;
1924 v3f pos = params.getPos(m_env, &pos_exists);
1925 // If position is not found while it should be, cancel sound
1926 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1929 // Filter destination clients
1930 std::vector<u16> dst_clients;
1931 if(params.to_player != "")
1933 Player *player = m_env->getPlayer(params.to_player.c_str());
1935 infostream<<"Server::playSound: Player \""<<params.to_player
1936 <<"\" not found"<<std::endl;
1939 if(player->peer_id == PEER_ID_INEXISTENT){
1940 infostream<<"Server::playSound: Player \""<<params.to_player
1941 <<"\" not connected"<<std::endl;
1944 dst_clients.push_back(player->peer_id);
1947 std::vector<u16> clients = m_clients.getClientIDs();
1949 for(std::vector<u16>::iterator
1950 i = clients.begin(); i != clients.end(); ++i) {
1951 Player *player = m_env->getPlayer(*i);
1956 if(player->getPosition().getDistanceFrom(pos) >
1957 params.max_hear_distance)
1960 dst_clients.push_back(*i);
1964 if(dst_clients.empty())
1968 s32 id = m_next_sound_id++;
1969 // The sound will exist as a reference in m_playing_sounds
1970 m_playing_sounds[id] = ServerPlayingSound();
1971 ServerPlayingSound &psound = m_playing_sounds[id];
1972 psound.params = params;
1974 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1975 pkt << id << spec.name << (float) (spec.gain * params.gain)
1976 << (u8) params.type << pos << params.object << params.loop;
1978 for(std::vector<u16>::iterator i = dst_clients.begin();
1979 i != dst_clients.end(); i++) {
1980 psound.clients.insert(*i);
1981 m_clients.send(*i, 0, &pkt, true);
1985 void Server::stopSound(s32 handle)
1987 // Get sound reference
1988 std::map<s32, ServerPlayingSound>::iterator i =
1989 m_playing_sounds.find(handle);
1990 if(i == m_playing_sounds.end())
1992 ServerPlayingSound &psound = i->second;
1994 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
1997 for(std::set<u16>::iterator i = psound.clients.begin();
1998 i != psound.clients.end(); i++) {
2000 m_clients.send(*i, 0, &pkt, true);
2002 // Remove sound reference
2003 m_playing_sounds.erase(i);
2006 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2007 std::vector<u16> *far_players, float far_d_nodes)
2009 float maxd = far_d_nodes*BS;
2010 v3f p_f = intToFloat(p, BS);
2012 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2015 std::vector<u16> clients = m_clients.getClientIDs();
2016 for(std::vector<u16>::iterator i = clients.begin();
2017 i != clients.end(); ++i) {
2020 if(Player *player = m_env->getPlayer(*i)) {
2021 // If player is far away, only set modified blocks not sent
2022 v3f player_pos = player->getPosition();
2023 if(player_pos.getDistanceFrom(p_f) > maxd) {
2024 far_players->push_back(*i);
2031 m_clients.send(*i, 0, &pkt, true);
2035 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2036 std::vector<u16> *far_players, float far_d_nodes,
2037 bool remove_metadata)
2039 float maxd = far_d_nodes*BS;
2040 v3f p_f = intToFloat(p, BS);
2042 std::vector<u16> clients = m_clients.getClientIDs();
2043 for(std::vector<u16>::iterator i = clients.begin();
2044 i != clients.end(); ++i) {
2048 if(Player *player = m_env->getPlayer(*i)) {
2049 // If player is far away, only set modified blocks not sent
2050 v3f player_pos = player->getPosition();
2051 if(player_pos.getDistanceFrom(p_f) > maxd) {
2052 far_players->push_back(*i);
2058 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2060 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2062 pkt << p << n.param0 << n.param1 << n.param2
2063 << (u8) (remove_metadata ? 0 : 1);
2065 if (!remove_metadata) {
2066 if (client->net_proto_version <= 21) {
2067 // Old clients always clear metadata; fix it
2068 // by sending the full block again.
2069 client->SetBlockNotSent(p);
2076 if (pkt.getSize() > 0)
2077 m_clients.send(*i, 0, &pkt, true);
2081 void Server::setBlockNotSent(v3s16 p)
2083 std::vector<u16> clients = m_clients.getClientIDs();
2085 for(std::vector<u16>::iterator i = clients.begin();
2086 i != clients.end(); ++i) {
2087 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2088 client->SetBlockNotSent(p);
2093 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2095 DSTACK(__FUNCTION_NAME);
2097 v3s16 p = block->getPos();
2100 Create a packet with the block in the right format
2103 std::ostringstream os(std::ios_base::binary);
2104 block->serialize(os, ver, false);
2105 block->serializeNetworkSpecific(os, net_proto_version);
2106 std::string s = os.str();
2108 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2111 pkt.putRawString(s.c_str(), s.size());
2115 void Server::SendBlocks(float dtime)
2117 DSTACK(__FUNCTION_NAME);
2119 JMutexAutoLock envlock(m_env_mutex);
2120 //TODO check if one big lock could be faster then multiple small ones
2122 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2124 std::vector<PrioritySortedBlockTransfer> queue;
2126 s32 total_sending = 0;
2129 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2131 std::vector<u16> clients = m_clients.getClientIDs();
2134 for(std::vector<u16>::iterator i = clients.begin();
2135 i != clients.end(); ++i) {
2136 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2141 total_sending += client->SendingCount();
2142 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2148 // Lowest priority number comes first.
2149 // Lowest is most important.
2150 std::sort(queue.begin(), queue.end());
2153 for(u32 i=0; i<queue.size(); i++)
2155 //TODO: Calculate limit dynamically
2156 if(total_sending >= g_settings->getS32
2157 ("max_simultaneous_block_sends_server_total"))
2160 PrioritySortedBlockTransfer q = queue[i];
2162 MapBlock *block = NULL;
2165 block = m_env->getMap().getBlockNoCreate(q.pos);
2167 catch(InvalidPositionException &e)
2172 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2177 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2179 client->SentBlock(q.pos);
2185 void Server::fillMediaCache()
2187 DSTACK(__FUNCTION_NAME);
2189 infostream<<"Server: Calculating media file checksums"<<std::endl;
2191 // Collect all media file paths
2192 std::vector<std::string> paths;
2193 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2194 i != m_mods.end(); i++) {
2195 const ModSpec &mod = *i;
2196 paths.push_back(mod.path + DIR_DELIM + "textures");
2197 paths.push_back(mod.path + DIR_DELIM + "sounds");
2198 paths.push_back(mod.path + DIR_DELIM + "media");
2199 paths.push_back(mod.path + DIR_DELIM + "models");
2201 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2203 // Collect media file information from paths into cache
2204 for(std::vector<std::string>::iterator i = paths.begin();
2205 i != paths.end(); i++) {
2206 std::string mediapath = *i;
2207 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2208 for (u32 j = 0; j < dirlist.size(); j++) {
2209 if (dirlist[j].dir) // Ignode dirs
2211 std::string filename = dirlist[j].name;
2212 // If name contains illegal characters, ignore the file
2213 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2214 infostream<<"Server: ignoring illegal file name: \""
2215 << filename << "\"" << std::endl;
2218 // If name is not in a supported format, ignore it
2219 const char *supported_ext[] = {
2220 ".png", ".jpg", ".bmp", ".tga",
2221 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2223 ".x", ".b3d", ".md2", ".obj",
2226 if (removeStringEnd(filename, supported_ext) == ""){
2227 infostream << "Server: ignoring unsupported file extension: \""
2228 << filename << "\"" << std::endl;
2231 // Ok, attempt to load the file and add to cache
2232 std::string filepath = mediapath + DIR_DELIM + filename;
2234 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2236 errorstream << "Server::fillMediaCache(): Could not open \""
2237 << filename << "\" for reading" << std::endl;
2240 std::ostringstream tmp_os(std::ios_base::binary);
2244 fis.read(buf, 1024);
2245 std::streamsize len = fis.gcount();
2246 tmp_os.write(buf, len);
2255 errorstream<<"Server::fillMediaCache(): Failed to read \""
2256 << filename << "\"" << std::endl;
2259 if(tmp_os.str().length() == 0) {
2260 errorstream << "Server::fillMediaCache(): Empty file \""
2261 << filepath << "\"" << std::endl;
2266 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2268 unsigned char *digest = sha1.getDigest();
2269 std::string sha1_base64 = base64_encode(digest, 20);
2270 std::string sha1_hex = hex_encode((char*)digest, 20);
2274 m_media[filename] = MediaInfo(filepath, sha1_base64);
2275 verbosestream << "Server: " << sha1_hex << " is " << filename
2281 struct SendableMediaAnnouncement
2284 std::string sha1_digest;
2286 SendableMediaAnnouncement(const std::string &name_="",
2287 const std::string &sha1_digest_=""):
2289 sha1_digest(sha1_digest_)
2293 void Server::sendMediaAnnouncement(u16 peer_id)
2295 DSTACK(__FUNCTION_NAME);
2297 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2300 std::vector<SendableMediaAnnouncement> file_announcements;
2302 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2303 i != m_media.end(); i++){
2305 file_announcements.push_back(
2306 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2310 std::ostringstream os(std::ios_base::binary);
2312 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2313 pkt << (u16) file_announcements.size();
2315 for (std::vector<SendableMediaAnnouncement>::iterator
2316 j = file_announcements.begin();
2317 j != file_announcements.end(); ++j) {
2318 pkt << j->name << j->sha1_digest;
2321 pkt << g_settings->get("remote_media");
2325 struct SendableMedia
2331 SendableMedia(const std::string &name_="", const std::string &path_="",
2332 const std::string &data_=""):
2339 void Server::sendRequestedMedia(u16 peer_id,
2340 const std::vector<std::string> &tosend)
2342 DSTACK(__FUNCTION_NAME);
2344 verbosestream<<"Server::sendRequestedMedia(): "
2345 <<"Sending files to client"<<std::endl;
2349 // Put 5kB in one bunch (this is not accurate)
2350 u32 bytes_per_bunch = 5000;
2352 std::vector< std::vector<SendableMedia> > file_bunches;
2353 file_bunches.push_back(std::vector<SendableMedia>());
2355 u32 file_size_bunch_total = 0;
2357 for(std::vector<std::string>::const_iterator i = tosend.begin();
2358 i != tosend.end(); ++i) {
2359 const std::string &name = *i;
2361 if(m_media.find(name) == m_media.end()) {
2362 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2363 <<"unknown file \""<<(name)<<"\""<<std::endl;
2367 //TODO get path + name
2368 std::string tpath = m_media[name].path;
2371 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2372 if(fis.good() == false){
2373 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2374 <<tpath<<"\" for reading"<<std::endl;
2377 std::ostringstream tmp_os(std::ios_base::binary);
2381 fis.read(buf, 1024);
2382 std::streamsize len = fis.gcount();
2383 tmp_os.write(buf, len);
2384 file_size_bunch_total += len;
2393 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2394 <<name<<"\""<<std::endl;
2397 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2398 <<tname<<"\""<<std::endl;*/
2400 file_bunches[file_bunches.size()-1].push_back(
2401 SendableMedia(name, tpath, tmp_os.str()));
2403 // Start next bunch if got enough data
2404 if(file_size_bunch_total >= bytes_per_bunch) {
2405 file_bunches.push_back(std::vector<SendableMedia>());
2406 file_size_bunch_total = 0;
2411 /* Create and send packets */
2413 u16 num_bunches = file_bunches.size();
2414 for(u16 i = 0; i < num_bunches; i++) {
2417 u16 total number of texture bunches
2418 u16 index of this bunch
2419 u32 number of files in this bunch
2428 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2429 pkt << num_bunches << i << (u32) file_bunches[i].size();
2431 for(std::vector<SendableMedia>::iterator
2432 j = file_bunches[i].begin();
2433 j != file_bunches[i].end(); ++j) {
2435 pkt.putLongString(j->data);
2438 verbosestream << "Server::sendRequestedMedia(): bunch "
2439 << i << "/" << num_bunches
2440 << " files=" << file_bunches[i].size()
2441 << " size=" << pkt.getSize() << std::endl;
2446 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2448 if(m_detached_inventories.count(name) == 0) {
2449 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2452 Inventory *inv = m_detached_inventories[name];
2453 std::ostringstream os(std::ios_base::binary);
2455 os << serializeString(name);
2459 std::string s = os.str();
2461 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2462 pkt.putRawString(s.c_str(), s.size());
2464 if (peer_id != PEER_ID_INEXISTENT) {
2468 m_clients.sendToAll(0, &pkt, true);
2472 void Server::sendDetachedInventories(u16 peer_id)
2474 DSTACK(__FUNCTION_NAME);
2476 for(std::map<std::string, Inventory*>::iterator
2477 i = m_detached_inventories.begin();
2478 i != m_detached_inventories.end(); i++) {
2479 const std::string &name = i->first;
2480 //Inventory *inv = i->second;
2481 sendDetachedInventory(name, peer_id);
2489 void Server::DiePlayer(u16 peer_id)
2491 DSTACK(__FUNCTION_NAME);
2493 PlayerSAO *playersao = getPlayerSAO(peer_id);
2496 infostream << "Server::DiePlayer(): Player "
2497 << playersao->getPlayer()->getName()
2498 << " dies" << std::endl;
2500 playersao->setHP(0);
2502 // Trigger scripted stuff
2503 m_script->on_dieplayer(playersao);
2505 SendPlayerHP(peer_id);
2506 SendDeathscreen(peer_id, false, v3f(0,0,0));
2509 void Server::RespawnPlayer(u16 peer_id)
2511 DSTACK(__FUNCTION_NAME);
2513 PlayerSAO *playersao = getPlayerSAO(peer_id);
2516 infostream << "Server::RespawnPlayer(): Player "
2517 << playersao->getPlayer()->getName()
2518 << " respawns" << std::endl;
2520 playersao->setHP(PLAYER_MAX_HP);
2521 playersao->setBreath(PLAYER_MAX_BREATH);
2523 SendPlayerHP(peer_id);
2524 SendPlayerBreath(peer_id);
2526 bool repositioned = m_script->on_respawnplayer(playersao);
2528 v3f pos = findSpawnPos();
2529 // setPos will send the new position to client
2530 playersao->setPos(pos);
2534 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2536 DSTACK(__FUNCTION_NAME);
2538 SendAccessDenied(peer_id, reason, custom_reason);
2539 m_clients.event(peer_id, CSE_SetDenied);
2540 m_con.DisconnectPeer(peer_id);
2543 // 13/03/15: remove this function when protocol version 25 will become
2544 // the minimum version for MT users, maybe in 1 year
2545 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2547 DSTACK(__FUNCTION_NAME);
2549 SendAccessDenied_Legacy(peer_id, reason);
2550 m_clients.event(peer_id, CSE_SetDenied);
2551 m_con.DisconnectPeer(peer_id);
2554 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2556 DSTACK(__FUNCTION_NAME);
2557 std::wstring message;
2560 Clear references to playing sounds
2562 for(std::map<s32, ServerPlayingSound>::iterator
2563 i = m_playing_sounds.begin();
2564 i != m_playing_sounds.end();)
2566 ServerPlayingSound &psound = i->second;
2567 psound.clients.erase(peer_id);
2568 if(psound.clients.empty())
2569 m_playing_sounds.erase(i++);
2574 Player *player = m_env->getPlayer(peer_id);
2576 // Collect information about leaving in chat
2578 if(player != NULL && reason != CDR_DENY)
2580 std::wstring name = narrow_to_wide(player->getName());
2583 message += L" left the game.";
2584 if(reason == CDR_TIMEOUT)
2585 message += L" (timed out)";
2589 /* Run scripts and remove from environment */
2593 PlayerSAO *playersao = player->getPlayerSAO();
2596 m_script->on_leaveplayer(playersao);
2598 playersao->disconnected();
2606 if(player != NULL && reason != CDR_DENY) {
2607 std::ostringstream os(std::ios_base::binary);
2608 std::vector<u16> clients = m_clients.getClientIDs();
2610 for(std::vector<u16>::iterator i = clients.begin();
2611 i != clients.end(); ++i) {
2613 Player *player = m_env->getPlayer(*i);
2617 // Get name of player
2618 os << player->getName() << " ";
2621 actionstream << player->getName() << " "
2622 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2623 << " List of players: " << os.str() << std::endl;
2627 JMutexAutoLock env_lock(m_env_mutex);
2628 m_clients.DeleteClient(peer_id);
2632 // Send leave chat message to all remaining clients
2633 if(message.length() != 0)
2634 SendChatMessage(PEER_ID_INEXISTENT,message);
2637 void Server::UpdateCrafting(Player* player)
2639 DSTACK(__FUNCTION_NAME);
2641 // Get a preview for crafting
2643 InventoryLocation loc;
2644 loc.setPlayer(player->getName());
2645 getCraftingResult(&player->inventory, preview, false, this);
2646 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2648 // Put the new preview in
2649 InventoryList *plist = player->inventory.getList("craftpreview");
2650 sanity_check(plist);
2651 sanity_check(plist->getSize() >= 1);
2652 plist->changeItem(0, preview);
2655 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2657 RemoteClient *client = getClientNoEx(peer_id,state_min);
2659 throw ClientNotFoundException("Client not found");
2663 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2665 return m_clients.getClientNoEx(peer_id, state_min);
2668 std::string Server::getPlayerName(u16 peer_id)
2670 Player *player = m_env->getPlayer(peer_id);
2672 return "[id="+itos(peer_id)+"]";
2673 return player->getName();
2676 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2678 Player *player = m_env->getPlayer(peer_id);
2681 return player->getPlayerSAO();
2684 std::wstring Server::getStatusString()
2686 std::wostringstream os(std::ios_base::binary);
2689 os<<L"version="<<narrow_to_wide(g_version_string);
2691 os<<L", uptime="<<m_uptime.get();
2693 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2694 // Information about clients
2697 std::vector<u16> clients = m_clients.getClientIDs();
2698 for(std::vector<u16>::iterator i = clients.begin();
2699 i != clients.end(); ++i) {
2701 Player *player = m_env->getPlayer(*i);
2702 // Get name of player
2703 std::wstring name = L"unknown";
2705 name = narrow_to_wide(player->getName());
2706 // Add name to information string
2714 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2715 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2716 if(g_settings->get("motd") != "")
2717 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2721 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2723 std::set<std::string> privs;
2724 m_script->getAuth(name, NULL, &privs);
2728 bool Server::checkPriv(const std::string &name, const std::string &priv)
2730 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2731 return (privs.count(priv) != 0);
2734 void Server::reportPrivsModified(const std::string &name)
2737 std::vector<u16> clients = m_clients.getClientIDs();
2738 for(std::vector<u16>::iterator i = clients.begin();
2739 i != clients.end(); ++i) {
2740 Player *player = m_env->getPlayer(*i);
2741 reportPrivsModified(player->getName());
2744 Player *player = m_env->getPlayer(name.c_str());
2747 SendPlayerPrivileges(player->peer_id);
2748 PlayerSAO *sao = player->getPlayerSAO();
2751 sao->updatePrivileges(
2752 getPlayerEffectivePrivs(name),
2757 void Server::reportInventoryFormspecModified(const std::string &name)
2759 Player *player = m_env->getPlayer(name.c_str());
2762 SendPlayerInventoryFormspec(player->peer_id);
2765 void Server::setIpBanned(const std::string &ip, const std::string &name)
2767 m_banmanager->add(ip, name);
2770 void Server::unsetIpBanned(const std::string &ip_or_name)
2772 m_banmanager->remove(ip_or_name);
2775 std::string Server::getBanDescription(const std::string &ip_or_name)
2777 return m_banmanager->getBanDescription(ip_or_name);
2780 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2782 Player *player = m_env->getPlayer(name);
2786 if (player->peer_id == PEER_ID_INEXISTENT)
2789 SendChatMessage(player->peer_id, msg);
2792 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2794 Player *player = m_env->getPlayer(playername);
2798 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2802 SendShowFormspecMessage(player->peer_id, formspec, formname);
2806 u32 Server::hudAdd(Player *player, HudElement *form) {
2810 u32 id = player->addHud(form);
2812 SendHUDAdd(player->peer_id, id, form);
2817 bool Server::hudRemove(Player *player, u32 id) {
2821 HudElement* todel = player->removeHud(id);
2828 SendHUDRemove(player->peer_id, id);
2832 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2836 SendHUDChange(player->peer_id, id, stat, data);
2840 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2844 SendHUDSetFlags(player->peer_id, flags, mask);
2845 player->hud_flags = flags;
2847 PlayerSAO* playersao = player->getPlayerSAO();
2849 if (playersao == NULL)
2852 m_script->player_event(playersao, "hud_changed");
2856 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2859 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2862 std::ostringstream os(std::ios::binary);
2863 writeS32(os, hotbar_itemcount);
2864 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2868 void Server::hudSetHotbarImage(Player *player, std::string name) {
2872 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2875 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2879 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2882 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2887 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2891 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2896 SendEyeOffset(player->peer_id, first, third);
2900 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2901 const std::string &type, const std::vector<std::string> ¶ms)
2906 SendSetSky(player->peer_id, bgcolor, type, params);
2910 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2916 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2920 void Server::notifyPlayers(const std::wstring &msg)
2922 SendChatMessage(PEER_ID_INEXISTENT,msg);
2925 void Server::spawnParticle(const char *playername, v3f pos,
2926 v3f velocity, v3f acceleration,
2927 float expirationtime, float size, bool
2928 collisiondetection, bool vertical, std::string texture)
2930 Player *player = m_env->getPlayer(playername);
2933 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2934 expirationtime, size, collisiondetection, vertical, texture);
2937 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2938 float expirationtime, float size,
2939 bool collisiondetection, bool vertical, std::string texture)
2941 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2942 expirationtime, size, collisiondetection, vertical, texture);
2945 u32 Server::addParticleSpawner(const char *playername,
2946 u16 amount, float spawntime,
2947 v3f minpos, v3f maxpos,
2948 v3f minvel, v3f maxvel,
2949 v3f minacc, v3f maxacc,
2950 float minexptime, float maxexptime,
2951 float minsize, float maxsize,
2952 bool collisiondetection, bool vertical, std::string texture)
2954 Player *player = m_env->getPlayer(playername);
2959 for(;;) // look for unused particlespawner id
2962 if (std::find(m_particlespawner_ids.begin(),
2963 m_particlespawner_ids.end(), id)
2964 == m_particlespawner_ids.end())
2966 m_particlespawner_ids.push_back(id);
2971 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2972 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2973 minexptime, maxexptime, minsize, maxsize,
2974 collisiondetection, vertical, texture, id);
2979 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2980 v3f minpos, v3f maxpos,
2981 v3f minvel, v3f maxvel,
2982 v3f minacc, v3f maxacc,
2983 float minexptime, float maxexptime,
2984 float minsize, float maxsize,
2985 bool collisiondetection, bool vertical, std::string texture)
2988 for(;;) // look for unused particlespawner id
2991 if (std::find(m_particlespawner_ids.begin(),
2992 m_particlespawner_ids.end(), id)
2993 == m_particlespawner_ids.end())
2995 m_particlespawner_ids.push_back(id);
3000 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3001 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3002 minexptime, maxexptime, minsize, maxsize,
3003 collisiondetection, vertical, texture, id);
3008 void Server::deleteParticleSpawner(const char *playername, u32 id)
3010 Player *player = m_env->getPlayer(playername);
3014 m_particlespawner_ids.erase(
3015 std::remove(m_particlespawner_ids.begin(),
3016 m_particlespawner_ids.end(), id),
3017 m_particlespawner_ids.end());
3018 SendDeleteParticleSpawner(player->peer_id, id);
3021 void Server::deleteParticleSpawnerAll(u32 id)
3023 m_particlespawner_ids.erase(
3024 std::remove(m_particlespawner_ids.begin(),
3025 m_particlespawner_ids.end(), id),
3026 m_particlespawner_ids.end());
3027 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3030 Inventory* Server::createDetachedInventory(const std::string &name)
3032 if(m_detached_inventories.count(name) > 0){
3033 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3034 delete m_detached_inventories[name];
3036 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3038 Inventory *inv = new Inventory(m_itemdef);
3040 m_detached_inventories[name] = inv;
3041 //TODO find a better way to do this
3042 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3049 BoolScopeSet(bool *dst, bool val):
3052 m_orig_state = *m_dst;
3057 *m_dst = m_orig_state;
3064 // actions: time-reversed list
3065 // Return value: success/failure
3066 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3067 std::list<std::string> *log)
3069 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3070 ServerMap *map = (ServerMap*)(&m_env->getMap());
3072 // Fail if no actions to handle
3073 if(actions.empty()){
3074 log->push_back("Nothing to do.");
3081 for(std::list<RollbackAction>::const_iterator
3082 i = actions.begin();
3083 i != actions.end(); i++)
3085 const RollbackAction &action = *i;
3087 bool success = action.applyRevert(map, this, this);
3090 std::ostringstream os;
3091 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3092 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3094 log->push_back(os.str());
3096 std::ostringstream os;
3097 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3098 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3100 log->push_back(os.str());
3104 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3105 <<" failed"<<std::endl;
3107 // Call it done if less than half failed
3108 return num_failed <= num_tried/2;
3111 // IGameDef interface
3113 IItemDefManager* Server::getItemDefManager()
3117 INodeDefManager* Server::getNodeDefManager()
3121 ICraftDefManager* Server::getCraftDefManager()
3125 ITextureSource* Server::getTextureSource()
3129 IShaderSource* Server::getShaderSource()
3133 scene::ISceneManager* Server::getSceneManager()
3138 u16 Server::allocateUnknownNodeId(const std::string &name)
3140 return m_nodedef->allocateDummy(name);
3142 ISoundManager* Server::getSoundManager()
3144 return &dummySoundManager;
3146 MtEventManager* Server::getEventManager()
3151 IWritableItemDefManager* Server::getWritableItemDefManager()
3155 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3159 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3164 const ModSpec* Server::getModSpec(const std::string &modname)
3166 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3167 i != m_mods.end(); i++){
3168 const ModSpec &mod = *i;
3169 if(mod.name == modname)
3174 void Server::getModNames(std::vector<std::string> &modlist)
3176 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3177 modlist.push_back(i->name);
3180 std::string Server::getBuiltinLuaPath()
3182 return porting::path_share + DIR_DELIM + "builtin";
3185 v3f Server::findSpawnPos()
3187 ServerMap &map = m_env->getServerMap();
3189 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3190 return nodeposf * BS;
3193 // Default position is static_spawnpoint
3194 // We will return it if we don't found a good place
3195 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3197 s16 water_level = map.getWaterLevel();
3199 bool is_good = false;
3201 // Try to find a good place a few times
3202 for(s32 i = 0; i < 1000 && !is_good; i++) {
3204 // We're going to try to throw the player to this position
3205 v2s16 nodepos2d = v2s16(
3206 -range + (myrand() % (range * 2)),
3207 -range + (myrand() % (range * 2)));
3209 // Get ground height at point
3210 s16 groundheight = map.findGroundLevel(nodepos2d);
3211 if (groundheight <= water_level) // Don't go underwater
3213 if (groundheight > water_level + 6) // Don't go to high places
3216 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3219 for (s32 i = 0; i < 10; i++) {
3220 v3s16 blockpos = getNodeBlockPos(nodepos);
3221 map.emergeBlock(blockpos, true);
3222 content_t c = map.getNodeNoEx(nodepos).getContent();
3223 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3225 if (air_count >= 2){
3234 return intToFloat(nodepos, BS);
3237 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3239 bool newplayer = false;
3242 Try to get an existing player
3244 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3246 // If player is already connected, cancel
3247 if(player != NULL && player->peer_id != 0)
3249 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3254 If player with the wanted peer_id already exists, cancel.
3256 if(m_env->getPlayer(peer_id) != NULL)
3258 infostream<<"emergePlayer(): Player with wrong name but same"
3259 " peer_id already exists"<<std::endl;
3263 // Load player if it isn't already loaded
3265 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3268 // Create player if it doesn't exist
3271 player = new RemotePlayer(this, name);
3272 // Set player position
3273 infostream<<"Server: Finding spawn place for player \""
3274 <<name<<"\""<<std::endl;
3275 v3f pos = findSpawnPos();
3276 player->setPosition(pos);
3278 // Make sure the player is saved
3279 player->setModified(true);
3281 // Add player to environment
3282 m_env->addPlayer(player);
3285 // Create a new player active object
3286 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3287 getPlayerEffectivePrivs(player->getName()),
3290 /* Clean up old HUD elements from previous sessions */
3293 /* Add object to environment */
3294 m_env->addActiveObject(playersao);
3298 m_script->on_newplayer(playersao);
3304 void dedicated_server_loop(Server &server, bool &kill)
3306 DSTACK(__FUNCTION_NAME);
3308 verbosestream<<"dedicated_server_loop()"<<std::endl;
3310 IntervalLimiter m_profiler_interval;
3314 float steplen = g_settings->getFloat("dedicated_server_step");
3315 // This is kind of a hack but can be done like this
3316 // because server.step() is very light
3318 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3319 sleep_ms((int)(steplen*1000.0));
3321 server.step(steplen);
3323 if(server.getShutdownRequested() || kill)
3325 infostream<<"Dedicated server quitting"<<std::endl;
3327 if(g_settings->getBool("server_announce"))
3328 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3336 float profiler_print_interval =
3337 g_settings->getFloat("profiler_print_interval");
3338 if(profiler_print_interval != 0)
3340 if(m_profiler_interval.step(steplen, profiler_print_interval))
3342 infostream<<"Profiler:"<<std::endl;
3343 g_profiler->print(infostream);
3344 g_profiler->clear();