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"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_game.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_abm.h"
52 #include "content_sao.h"
54 #include "sound.h" // dummySoundManager
55 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "util/thread.h"
62 #include "defaultsettings.h"
63 #include "util/base64.h"
64 #include "util/sha1.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public JThread
81 ServerThread(Server *server):
90 void * ServerThread::Thread()
92 log_register_thread("ServerThread");
94 DSTACK(__FUNCTION_NAME);
95 BEGIN_DEBUG_EXCEPTION_HANDLER
97 m_server->AsyncRunStep(true);
101 porting::setThreadName("ServerThread");
103 while(!StopRequested())
106 //TimeTaker timer("AsyncRunStep() + Receive()");
108 m_server->AsyncRunStep();
113 catch(con::NoIncomingDataException &e)
116 catch(con::PeerNotFoundException &e)
118 infostream<<"Server: PeerNotFoundException"<<std::endl;
120 catch(ClientNotFoundException &e)
123 catch(con::ConnectionBindFailed &e)
125 m_server->setAsyncFatalError(e.what());
129 m_server->setAsyncFatalError(e.what());
133 END_DEBUG_EXCEPTION_HANDLER(errorstream)
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
140 if(pos_exists) *pos_exists = false;
145 if(pos_exists) *pos_exists = true;
150 ServerActiveObject *sao = env->getActiveObject(object);
153 if(pos_exists) *pos_exists = true;
154 return sao->getBasePosition(); }
166 const std::string &path_world,
167 const SubgameSpec &gamespec,
168 bool simple_singleplayer_mode,
171 m_path_world(path_world),
172 m_gamespec(gamespec),
173 m_simple_singleplayer_mode(simple_singleplayer_mode),
174 m_async_fatal_error(""),
183 m_enable_rollback_recording(false),
186 m_itemdef(createItemDefManager()),
187 m_nodedef(createNodeDefManager()),
188 m_craftdef(createCraftDefManager()),
189 m_event(new EventManager()),
191 m_time_of_day_send_timer(0),
194 m_shutdown_requested(false),
195 m_ignore_map_edit_events(false),
196 m_ignore_map_edit_events_peer_id(0),
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 ModConfiguration modconf(m_path_world);
247 m_mods = modconf.getMods();
248 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
249 // complain about mods with unsatisfied dependencies
250 if(!modconf.isConsistent())
252 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
253 it != unsatisfied_mods.end(); ++it)
256 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
257 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
258 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
259 errorstream << " \"" << *dep_it << "\"";
260 errorstream << std::endl;
264 Settings worldmt_settings;
265 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
266 worldmt_settings.readConfigFile(worldmt.c_str());
267 std::vector<std::string> names = worldmt_settings.getNames();
268 std::set<std::string> load_mod_names;
269 for(std::vector<std::string>::iterator it = names.begin();
270 it != names.end(); ++it)
272 std::string name = *it;
273 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
274 load_mod_names.insert(name.substr(9));
276 // complain about mods declared to be loaded, but not found
277 for(std::vector<ModSpec>::iterator it = m_mods.begin();
278 it != m_mods.end(); ++it)
279 load_mod_names.erase((*it).name);
280 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
281 it != unsatisfied_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 if(!load_mod_names.empty())
285 errorstream << "The following mods could not be found:";
286 for(std::set<std::string>::iterator it = load_mod_names.begin();
287 it != load_mod_names.end(); ++it)
288 errorstream << " \"" << (*it) << "\"";
289 errorstream << std::endl;
293 JMutexAutoLock envlock(m_env_mutex);
295 // Load mapgen params from Settings
296 m_emerge->loadMapgenParams();
298 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
299 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
301 // Initialize scripting
302 infostream<<"Server: Initializing Lua"<<std::endl;
304 m_script = new GameScripting(this);
306 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
308 if (!m_script->loadScript(scriptpath))
309 throw ModError("Failed to load and run " + scriptpath);
312 infostream<<"Server: Loading mods: ";
313 for(std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++){
315 const ModSpec &mod = *i;
316 infostream<<mod.name<<" ";
318 infostream<<std::endl;
319 // Load and run "mod" scripts
320 for(std::vector<ModSpec>::iterator i = m_mods.begin();
321 i != m_mods.end(); i++){
322 const ModSpec &mod = *i;
323 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
324 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
325 <<scriptpath<<"\"]"<<std::endl;
326 bool success = m_script->loadMod(scriptpath, mod.name);
328 errorstream<<"Server: Failed to load and run "
329 <<scriptpath<<std::endl;
330 throw ModError("Failed to load and run "+scriptpath);
334 // Read Textures and calculate sha1 sums
337 // Apply item aliases in the node definition manager
338 m_nodedef->updateAliases(m_itemdef);
340 m_nodedef->setNodeRegistrationStatus(true);
342 // Perform pending node name resolutions
343 m_nodedef->runNodeResolverCallbacks();
345 // Initialize Environment
346 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
348 m_clients.setEnv(m_env);
350 // Initialize mapgens
351 m_emerge->initMapgens();
353 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
354 if (m_enable_rollback_recording) {
355 // Create rollback manager
356 m_rollback = new RollbackManager(m_path_world, this);
359 // Give environment reference to scripting api
360 m_script->initializeEnvironment(m_env);
362 // Register us to receive map edit events
363 servermap->addEventReceiver(this);
365 // If file exists, load environment metadata
366 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
368 infostream<<"Server: Loading environment metadata"<<std::endl;
372 // Add some test ActiveBlockModifiers to environment
373 add_legacy_abms(m_env, m_nodedef);
375 m_liquid_transform_every = g_settings->getFloat("liquid_update");
380 infostream<<"Server destructing"<<std::endl;
382 // Send shutdown message
383 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
386 JMutexAutoLock envlock(m_env_mutex);
388 // Execute script shutdown hooks
389 m_script->on_shutdown();
391 infostream<<"Server: Saving players"<<std::endl;
392 m_env->saveLoadedPlayers();
394 infostream<<"Server: Saving environment metadata"<<std::endl;
402 // stop all emerge threads before deleting players that may have
403 // requested blocks to be emerged
404 m_emerge->stopThreads();
406 // Delete things in the reverse order of creation
409 // N.B. the EmergeManager should be deleted after the Environment since Map
410 // depends on EmergeManager to write its current params to the map meta
419 // Deinitialize scripting
420 infostream<<"Server: Deinitializing scripting"<<std::endl;
423 // Delete detached inventories
424 for (std::map<std::string, Inventory*>::iterator
425 i = m_detached_inventories.begin();
426 i != m_detached_inventories.end(); i++) {
431 void Server::start(Address bind_addr)
433 DSTACK(__FUNCTION_NAME);
435 m_bind_addr = bind_addr;
437 infostream<<"Starting server on "
438 << bind_addr.serializeString() <<"..."<<std::endl;
440 // Stop thread if already running
443 // Initialize connection
444 m_con.SetTimeoutMs(30);
445 m_con.Serve(bind_addr);
450 // ASCII art for the win!
452 <<" .__ __ __ "<<std::endl
453 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
454 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
455 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
456 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
457 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
458 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
459 actionstream<<"Server for gameid=\""<<m_gamespec.id
460 <<"\" listening on "<<bind_addr.serializeString()<<":"
461 <<bind_addr.getPort() << "."<<std::endl;
466 DSTACK(__FUNCTION_NAME);
468 infostream<<"Server: Stopping and waiting threads"<<std::endl;
470 // Stop threads (set run=false first so both start stopping)
472 //m_emergethread.setRun(false);
474 //m_emergethread.stop();
476 infostream<<"Server: Threads stopped"<<std::endl;
479 void Server::step(float dtime)
481 DSTACK(__FUNCTION_NAME);
486 JMutexAutoLock lock(m_step_dtime_mutex);
487 m_step_dtime += dtime;
489 // Throw if fatal error occurred in thread
490 std::string async_err = m_async_fatal_error.get();
492 throw ServerError(async_err);
496 void Server::AsyncRunStep(bool initial_step)
498 DSTACK(__FUNCTION_NAME);
500 g_profiler->add("Server::AsyncRunStep (num)", 1);
504 JMutexAutoLock lock1(m_step_dtime_mutex);
505 dtime = m_step_dtime;
509 // Send blocks to clients
513 if((dtime < 0.001) && (initial_step == false))
516 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
518 //infostream<<"Server steps "<<dtime<<std::endl;
519 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
522 JMutexAutoLock lock1(m_step_dtime_mutex);
523 m_step_dtime -= dtime;
530 m_uptime.set(m_uptime.get() + dtime);
536 Update time of day and overall game time
539 JMutexAutoLock envlock(m_env_mutex);
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)
550 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
551 u16 time = m_env->getTimeOfDay();
552 float time_speed = g_settings->getFloat("time_speed");
553 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
558 JMutexAutoLock lock(m_env_mutex);
559 // Figure out and report maximum lag to environment
560 float max_lag = m_env->getMaxLagEstimate();
561 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
563 if(dtime > 0.1 && dtime > max_lag * 2.0)
564 infostream<<"Server: Maximum lag peaked to "<<dtime
568 m_env->reportMaxLagEstimate(max_lag);
570 ScopeProfiler sp(g_profiler, "SEnv step");
571 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
575 static const float map_timer_and_unload_dtime = 2.92;
576 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
578 JMutexAutoLock lock(m_env_mutex);
579 // Run Map's timers and unload unused data
580 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
581 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
582 g_settings->getFloat("server_unload_unused_data_timeout"));
593 JMutexAutoLock lock(m_env_mutex);
595 std::list<u16> clientids = m_clients.getClientIDs();
597 ScopeProfiler sp(g_profiler, "Server: handle players");
599 for(std::list<u16>::iterator
600 i = clientids.begin();
601 i != clientids.end(); ++i)
603 PlayerSAO *playersao = getPlayerSAO(*i);
604 if(playersao == NULL)
608 Send player breath if changed
610 if(playersao->m_breath_not_sent) {
611 SendPlayerBreath(*i);
615 Send player inventories if necessary
617 if(playersao->m_moved) {
619 playersao->m_moved = false;
621 if(playersao->m_inventory_not_sent) {
628 /* Transform liquids */
629 m_liquid_transform_timer += dtime;
630 if(m_liquid_transform_timer >= m_liquid_transform_every)
632 m_liquid_transform_timer -= m_liquid_transform_every;
634 JMutexAutoLock lock(m_env_mutex);
636 ScopeProfiler sp(g_profiler, "Server: liquid transform");
638 std::map<v3s16, MapBlock*> modified_blocks;
639 m_env->getMap().transformLiquids(modified_blocks);
644 core::map<v3s16, MapBlock*> lighting_modified_blocks;
645 ServerMap &map = ((ServerMap&)m_env->getMap());
646 map.updateLighting(modified_blocks, lighting_modified_blocks);
648 // Add blocks modified by lighting to modified_blocks
649 for(core::map<v3s16, MapBlock*>::Iterator
650 i = lighting_modified_blocks.getIterator();
651 i.atEnd() == false; i++)
653 MapBlock *block = i.getNode()->getValue();
654 modified_blocks.insert(block->getPos(), block);
658 Set the modified blocks unsent for all the clients
660 if(!modified_blocks.empty())
662 SetBlocksNotSent(modified_blocks);
665 m_clients.step(dtime);
667 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
669 // send masterserver announce
671 float &counter = m_masterserver_timer;
672 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
673 g_settings->getBool("server_announce"))
675 ServerList::sendAnnounce(counter ? "update" : "start",
676 m_bind_addr.getPort(),
677 m_clients.getPlayerNames(),
679 m_env->getGameTime(),
682 m_emerge->params.mg_name,
691 Check added and deleted active objects
694 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
695 JMutexAutoLock envlock(m_env_mutex);
698 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
699 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
701 // Radius inside which objects are active
702 s16 radius = g_settings->getS16("active_object_send_range_blocks");
703 s16 player_radius = g_settings->getS16("player_transfer_distance");
705 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
706 !g_settings->getBool("unlimited_player_transfer_distance"))
707 player_radius = radius;
709 radius *= MAP_BLOCKSIZE;
710 player_radius *= MAP_BLOCKSIZE;
712 for(std::map<u16, RemoteClient*>::iterator
714 i != clients.end(); ++i)
716 RemoteClient *client = i->second;
718 // If definitions and textures have not been sent, don't
719 // send objects either
720 if (client->getState() < CS_DefinitionsSent)
723 Player *player = m_env->getPlayer(client->peer_id);
726 // This can happen if the client timeouts somehow
727 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
729 <<" has no associated player"<<std::endl;*/
732 v3s16 pos = floatToInt(player->getPosition(), BS);
734 std::set<u16> removed_objects;
735 std::set<u16> added_objects;
736 m_env->getRemovedActiveObjects(pos, radius, player_radius,
737 client->m_known_objects, removed_objects);
738 m_env->getAddedActiveObjects(pos, radius, player_radius,
739 client->m_known_objects, added_objects);
741 // Ignore if nothing happened
742 if(removed_objects.empty() && added_objects.empty())
744 //infostream<<"active objects: none changed"<<std::endl;
748 std::string data_buffer;
752 // Handle removed objects
753 writeU16((u8*)buf, removed_objects.size());
754 data_buffer.append(buf, 2);
755 for(std::set<u16>::iterator
756 i = removed_objects.begin();
757 i != removed_objects.end(); ++i)
761 ServerActiveObject* obj = m_env->getActiveObject(id);
763 // Add to data buffer for sending
764 writeU16((u8*)buf, id);
765 data_buffer.append(buf, 2);
767 // Remove from known objects
768 client->m_known_objects.erase(id);
770 if(obj && obj->m_known_by_count > 0)
771 obj->m_known_by_count--;
774 // Handle added objects
775 writeU16((u8*)buf, added_objects.size());
776 data_buffer.append(buf, 2);
777 for(std::set<u16>::iterator
778 i = added_objects.begin();
779 i != added_objects.end(); ++i)
783 ServerActiveObject* obj = m_env->getActiveObject(id);
786 u8 type = ACTIVEOBJECT_TYPE_INVALID;
788 infostream<<"WARNING: "<<__FUNCTION_NAME
789 <<": NULL object"<<std::endl;
791 type = obj->getSendType();
793 // Add to data buffer for sending
794 writeU16((u8*)buf, id);
795 data_buffer.append(buf, 2);
796 writeU8((u8*)buf, type);
797 data_buffer.append(buf, 1);
800 data_buffer.append(serializeLongString(
801 obj->getClientInitializationData(client->net_proto_version)));
803 data_buffer.append(serializeLongString(""));
805 // Add to known objects
806 client->m_known_objects.insert(id);
809 obj->m_known_by_count++;
812 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
813 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
816 verbosestream << "Server: Sent object remove/add: "
817 << removed_objects.size() << " removed, "
818 << added_objects.size() << " added, "
819 << "packet size is " << pkt->getSize() << std::endl;
830 JMutexAutoLock envlock(m_env_mutex);
831 ScopeProfiler sp(g_profiler, "Server: sending object messages");
834 // Value = data sent by object
835 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
837 // Get active object messages from environment
840 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
844 std::list<ActiveObjectMessage>* message_list = NULL;
845 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
846 n = buffered_messages.find(aom.id);
847 if(n == buffered_messages.end())
849 message_list = new std::list<ActiveObjectMessage>;
850 buffered_messages[aom.id] = message_list;
854 message_list = n->second;
856 message_list->push_back(aom);
860 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
861 // Route data to every client
862 for(std::map<u16, RemoteClient*>::iterator
864 i != clients.end(); ++i)
866 RemoteClient *client = i->second;
867 std::string reliable_data;
868 std::string unreliable_data;
869 // Go through all objects in message buffer
870 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
871 j = buffered_messages.begin();
872 j != buffered_messages.end(); ++j)
874 // If object is not known by client, skip it
876 if(client->m_known_objects.find(id) == client->m_known_objects.end())
878 // Get message list of object
879 std::list<ActiveObjectMessage>* list = j->second;
880 // Go through every message
881 for(std::list<ActiveObjectMessage>::iterator
882 k = list->begin(); k != list->end(); ++k)
884 // Compose the full new data with header
885 ActiveObjectMessage aom = *k;
886 std::string new_data;
889 writeU16((u8*)&buf[0], aom.id);
890 new_data.append(buf, 2);
892 new_data += serializeString(aom.datastring);
893 // Add data to buffer
895 reliable_data += new_data;
897 unreliable_data += new_data;
901 reliable_data and unreliable_data are now ready.
904 if(reliable_data.size() > 0) {
905 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
908 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
912 if(unreliable_data.size() > 0) {
913 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
916 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
922 // Clear buffered_messages
923 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
924 i = buffered_messages.begin();
925 i != buffered_messages.end(); ++i)
932 Send queued-for-sending map edit events.
935 // We will be accessing the environment
936 JMutexAutoLock lock(m_env_mutex);
938 // Don't send too many at a time
941 // Single change sending is disabled if queue size is not small
942 bool disable_single_change_sending = false;
943 if(m_unsent_map_edit_queue.size() >= 4)
944 disable_single_change_sending = true;
946 int event_count = m_unsent_map_edit_queue.size();
948 // We'll log the amount of each
951 while(m_unsent_map_edit_queue.size() != 0)
953 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
955 // Players far away from the change are stored here.
956 // Instead of sending the changes, MapBlocks are set not sent
958 std::list<u16> far_players;
960 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
962 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
963 prof.add("MEET_ADDNODE", 1);
964 if(disable_single_change_sending)
965 sendAddNode(event->p, event->n, event->already_known_by_peer,
966 &far_players, 5, event->type == MEET_ADDNODE);
968 sendAddNode(event->p, event->n, event->already_known_by_peer,
969 &far_players, 30, event->type == MEET_ADDNODE);
971 else if(event->type == MEET_REMOVENODE)
973 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
974 prof.add("MEET_REMOVENODE", 1);
975 if(disable_single_change_sending)
976 sendRemoveNode(event->p, event->already_known_by_peer,
979 sendRemoveNode(event->p, event->already_known_by_peer,
982 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
984 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
985 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
986 setBlockNotSent(event->p);
988 else if(event->type == MEET_OTHER)
990 infostream<<"Server: MEET_OTHER"<<std::endl;
991 prof.add("MEET_OTHER", 1);
992 for(std::set<v3s16>::iterator
993 i = event->modified_blocks.begin();
994 i != event->modified_blocks.end(); ++i)
1001 prof.add("unknown", 1);
1002 infostream<<"WARNING: Server: Unknown MapEditEvent "
1003 <<((u32)event->type)<<std::endl;
1007 Set blocks not sent to far players
1009 if(!far_players.empty())
1011 // Convert list format to that wanted by SetBlocksNotSent
1012 std::map<v3s16, MapBlock*> modified_blocks2;
1013 for(std::set<v3s16>::iterator
1014 i = event->modified_blocks.begin();
1015 i != event->modified_blocks.end(); ++i)
1017 modified_blocks2[*i] =
1018 m_env->getMap().getBlockNoCreateNoEx(*i);
1020 // Set blocks not sent
1021 for(std::list<u16>::iterator
1022 i = far_players.begin();
1023 i != far_players.end(); ++i)
1026 RemoteClient *client = getClient(peer_id);
1029 client->SetBlocksNotSent(modified_blocks2);
1035 /*// Don't send too many at a time
1037 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1041 if(event_count >= 5){
1042 infostream<<"Server: MapEditEvents:"<<std::endl;
1043 prof.print(infostream);
1044 } else if(event_count != 0){
1045 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1046 prof.print(verbosestream);
1052 Trigger emergethread (it somehow gets to a non-triggered but
1053 bysy state sometimes)
1056 float &counter = m_emergethread_trigger_timer;
1062 m_emerge->startThreads();
1066 // Save map, players and auth stuff
1068 float &counter = m_savemap_timer;
1070 if(counter >= g_settings->getFloat("server_map_save_interval"))
1073 JMutexAutoLock lock(m_env_mutex);
1075 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1078 if (m_banmanager->isModified()) {
1079 m_banmanager->save();
1082 // Save changed parts of map
1083 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1086 m_env->saveLoadedPlayers();
1088 // Save environment metadata
1094 void Server::Receive()
1096 DSTACK(__FUNCTION_NAME);
1097 SharedBuffer<u8> data;
1101 datasize = m_con.Receive(peer_id,data);
1102 ProcessData(*data, datasize, peer_id);
1104 catch(con::InvalidIncomingDataException &e) {
1105 infostream<<"Server::Receive(): "
1106 "InvalidIncomingDataException: what()="
1107 <<e.what()<<std::endl;
1109 catch(SerializationError &e) {
1110 infostream<<"Server::Receive(): "
1111 "SerializationError: what()="
1112 <<e.what()<<std::endl;
1114 catch(ClientStateError &e) {
1115 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1116 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1117 L"Try reconnecting or updating your client");
1119 catch(con::PeerNotFoundException &e) {
1124 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1126 std::string playername = "";
1127 PlayerSAO *playersao = NULL;
1130 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1131 if (client != NULL) {
1132 playername = client->getName();
1133 playersao = emergePlayer(playername.c_str(), peer_id);
1135 } catch (std::exception &e) {
1141 RemotePlayer *player =
1142 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1144 // If failed, cancel
1145 if((playersao == NULL) || (player == NULL)) {
1146 if(player && player->peer_id != 0) {
1147 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1148 <<" (player allocated to an another client)"<<std::endl;
1149 DenyAccess(peer_id, L"Another client is connected with this "
1150 L"name. If your client closed unexpectedly, try again in "
1153 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1155 DenyAccess(peer_id, L"Could not allocate player.");
1161 Send complete position information
1163 SendMovePlayer(peer_id);
1166 SendPlayerPrivileges(peer_id);
1168 // Send inventory formspec
1169 SendPlayerInventoryFormspec(peer_id);
1172 UpdateCrafting(peer_id);
1173 SendInventory(peer_id);
1176 if(g_settings->getBool("enable_damage"))
1177 SendPlayerHP(peer_id);
1180 SendPlayerBreath(peer_id);
1182 // Show death screen if necessary
1184 SendDeathscreen(peer_id, false, v3f(0,0,0));
1186 // Note things in chat if not in simple singleplayer mode
1187 if(!m_simple_singleplayer_mode) {
1188 // Send information about server to player in chat
1189 SendChatMessage(peer_id, getStatusString());
1191 // Send information about joining in chat
1193 std::wstring name = L"unknown";
1194 Player *player = m_env->getPlayer(peer_id);
1196 name = narrow_to_wide(player->getName());
1198 std::wstring message;
1201 message += L" joined the game.";
1202 SendChatMessage(PEER_ID_INEXISTENT,message);
1205 Address addr = getPeerAddress(player->peer_id);
1206 std::string ip_str = addr.serializeString();
1207 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1212 std::vector<std::string> names = m_clients.getPlayerNames();
1214 actionstream<<player->getName() <<" joins game. List of players: ";
1216 for (std::vector<std::string>::iterator i = names.begin();
1217 i != names.end(); i++) {
1218 actionstream << *i << " ";
1221 actionstream << player->getName() <<std::endl;
1226 inline void Server::handleCommand(NetworkPacket* pkt)
1228 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1229 (this->*opHandle.handler)(pkt);
1232 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1234 DSTACK(__FUNCTION_NAME);
1235 // Environment is locked first.
1236 JMutexAutoLock envlock(m_env_mutex);
1238 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1241 Address address = getPeerAddress(peer_id);
1242 std::string addr_s = address.serializeString();
1244 if(m_banmanager->isIpBanned(addr_s)) {
1245 std::string ban_name = m_banmanager->getBanName(addr_s);
1246 infostream << "Server: A banned client tried to connect from "
1247 << addr_s << "; banned name was "
1248 << ban_name << std::endl;
1249 // This actually doesn't seem to transfer to the client
1250 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1251 + narrow_to_wide(ban_name));
1255 catch(con::PeerNotFoundException &e) {
1257 * no peer for this packet found
1258 * most common reason is peer timeout, e.g. peer didn't
1259 * respond for some time, your server was overloaded or
1262 infostream << "Server::ProcessData(): Cancelling: peer "
1263 << peer_id << " not found" << std::endl;
1271 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1273 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1275 // Command must be handled into ToServerCommandHandler
1276 if (command >= TOSERVER_NUM_MSG_TYPES) {
1277 infostream << "Server: Ignoring unknown command "
1278 << command << std::endl;
1281 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1287 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1289 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1290 errorstream << "Server::ProcessData(): Cancelling: Peer"
1291 " serialization format invalid or not initialized."
1292 " Skipping incoming command=" << command << std::endl;
1298 /* Handle commands related to client startup */
1299 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1305 if (m_clients.getClientState(peer_id) < CS_Active) {
1306 if (command == TOSERVER_PLAYERPOS) return;
1308 errorstream << "Got packet command: " << command << " for peer id "
1309 << peer_id << " but client isn't active yet. Dropping packet "
1320 catch(SendFailedException &e) {
1321 errorstream << "Server::ProcessData(): SendFailedException: "
1322 << "what=" << e.what()
1327 void Server::setTimeOfDay(u32 time)
1329 m_env->setTimeOfDay(time);
1330 m_time_of_day_send_timer = 0;
1333 void Server::onMapEditEvent(MapEditEvent *event)
1335 if(m_ignore_map_edit_events)
1337 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1339 MapEditEvent *e = event->clone();
1340 m_unsent_map_edit_queue.push_back(e);
1343 Inventory* Server::getInventory(const InventoryLocation &loc)
1346 case InventoryLocation::UNDEFINED:
1347 case InventoryLocation::CURRENT_PLAYER:
1349 case InventoryLocation::PLAYER:
1351 Player *player = m_env->getPlayer(loc.name.c_str());
1354 PlayerSAO *playersao = player->getPlayerSAO();
1357 return playersao->getInventory();
1360 case InventoryLocation::NODEMETA:
1362 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1365 return meta->getInventory();
1368 case InventoryLocation::DETACHED:
1370 if(m_detached_inventories.count(loc.name) == 0)
1372 return m_detached_inventories[loc.name];
1380 void Server::setInventoryModified(const InventoryLocation &loc)
1383 case InventoryLocation::UNDEFINED:
1385 case InventoryLocation::PLAYER:
1387 Player *player = m_env->getPlayer(loc.name.c_str());
1390 PlayerSAO *playersao = player->getPlayerSAO();
1393 playersao->m_inventory_not_sent = true;
1394 playersao->m_wielded_item_not_sent = true;
1397 case InventoryLocation::NODEMETA:
1399 v3s16 blockpos = getNodeBlockPos(loc.p);
1401 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1403 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1405 setBlockNotSent(blockpos);
1408 case InventoryLocation::DETACHED:
1410 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1418 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1420 std::list<u16> clients = m_clients.getClientIDs();
1422 // Set the modified blocks unsent for all the clients
1423 for (std::list<u16>::iterator
1424 i = clients.begin();
1425 i != clients.end(); ++i) {
1426 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
1428 client->SetBlocksNotSent(block);
1433 void Server::peerAdded(con::Peer *peer)
1435 DSTACK(__FUNCTION_NAME);
1436 verbosestream<<"Server::peerAdded(): peer->id="
1437 <<peer->id<<std::endl;
1440 c.type = con::PEER_ADDED;
1441 c.peer_id = peer->id;
1443 m_peer_change_queue.push_back(c);
1446 void Server::deletingPeer(con::Peer *peer, bool timeout)
1448 DSTACK(__FUNCTION_NAME);
1449 verbosestream<<"Server::deletingPeer(): peer->id="
1450 <<peer->id<<", timeout="<<timeout<<std::endl;
1452 m_clients.event(peer->id, CSE_Disconnect);
1454 c.type = con::PEER_REMOVED;
1455 c.peer_id = peer->id;
1456 c.timeout = timeout;
1457 m_peer_change_queue.push_back(c);
1460 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1462 *retval = m_con.getPeerStat(peer_id,type);
1463 if (*retval == -1) return false;
1467 bool Server::getClientInfo(
1476 std::string* vers_string
1479 *state = m_clients.getClientState(peer_id);
1481 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1483 if (client == NULL) {
1488 *uptime = client->uptime();
1489 *ser_vers = client->serialization_version;
1490 *prot_vers = client->net_proto_version;
1492 *major = client->getMajor();
1493 *minor = client->getMinor();
1494 *patch = client->getPatch();
1495 *vers_string = client->getPatch();
1502 void Server::handlePeerChanges()
1504 while(m_peer_change_queue.size() > 0)
1506 con::PeerChange c = m_peer_change_queue.pop_front();
1508 verbosestream<<"Server: Handling peer change: "
1509 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1514 case con::PEER_ADDED:
1515 m_clients.CreateClient(c.peer_id);
1518 case con::PEER_REMOVED:
1519 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1523 assert("Invalid peer change event received!" == 0);
1529 void Server::Send(NetworkPacket* pkt)
1531 m_clients.send(pkt->getPeerId(),
1532 clientCommandFactoryTable[pkt->getCommand()].channel,
1534 clientCommandFactoryTable[pkt->getCommand()].reliable);
1537 void Server::SendMovement(u16 peer_id)
1539 DSTACK(__FUNCTION_NAME);
1540 std::ostringstream os(std::ios_base::binary);
1542 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1544 *pkt << g_settings->getFloat("movement_acceleration_default");
1545 *pkt << g_settings->getFloat("movement_acceleration_air");
1546 *pkt << g_settings->getFloat("movement_acceleration_fast");
1547 *pkt << g_settings->getFloat("movement_speed_walk");
1548 *pkt << g_settings->getFloat("movement_speed_crouch");
1549 *pkt << g_settings->getFloat("movement_speed_fast");
1550 *pkt << g_settings->getFloat("movement_speed_climb");
1551 *pkt << g_settings->getFloat("movement_speed_jump");
1552 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1553 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1554 *pkt << g_settings->getFloat("movement_liquid_sink");
1555 *pkt << g_settings->getFloat("movement_gravity");
1560 void Server::SendHP(u16 peer_id, u8 hp)
1562 DSTACK(__FUNCTION_NAME);
1564 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1569 void Server::SendBreath(u16 peer_id, u16 breath)
1571 DSTACK(__FUNCTION_NAME);
1573 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1574 *pkt << (u16) breath;
1578 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1580 DSTACK(__FUNCTION_NAME);
1582 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1587 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1588 v3f camera_point_target)
1590 DSTACK(__FUNCTION_NAME);
1592 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1593 *pkt << set_camera_point_target << camera_point_target;
1597 void Server::SendItemDef(u16 peer_id,
1598 IItemDefManager *itemdef, u16 protocol_version)
1600 DSTACK(__FUNCTION_NAME);
1602 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1606 u32 length of the next item
1607 zlib-compressed serialized ItemDefManager
1609 std::ostringstream tmp_os(std::ios::binary);
1610 itemdef->serialize(tmp_os, protocol_version);
1611 std::ostringstream tmp_os2(std::ios::binary);
1612 compressZlib(tmp_os.str(), tmp_os2);
1613 pkt->putLongString(tmp_os2.str());
1616 verbosestream << "Server: Sending item definitions to id(" << peer_id
1617 << "): size=" << pkt->getSize() << std::endl;
1622 void Server::SendNodeDef(u16 peer_id,
1623 INodeDefManager *nodedef, u16 protocol_version)
1625 DSTACK(__FUNCTION_NAME);
1627 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1631 u32 length of the next item
1632 zlib-compressed serialized NodeDefManager
1634 std::ostringstream tmp_os(std::ios::binary);
1635 nodedef->serialize(tmp_os, protocol_version);
1636 std::ostringstream tmp_os2(std::ios::binary);
1637 compressZlib(tmp_os.str(), tmp_os2);
1639 pkt->putLongString(tmp_os2.str());
1642 verbosestream << "Server: Sending node definitions to id(" << peer_id
1643 << "): size=" << pkt->getSize() << std::endl;
1649 Non-static send methods
1652 void Server::SendInventory(u16 peer_id)
1654 DSTACK(__FUNCTION_NAME);
1656 PlayerSAO *playersao = getPlayerSAO(peer_id);
1659 playersao->m_inventory_not_sent = false;
1665 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0, peer_id);
1667 std::ostringstream os;
1668 playersao->getInventory()->serialize(os);
1670 std::string s = os.str();
1672 pkt->putRawString(s.c_str(), s.size());
1676 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1678 DSTACK(__FUNCTION_NAME);
1680 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1683 if (peer_id != PEER_ID_INEXISTENT) {
1687 m_clients.sendToAll(0,pkt,true);
1691 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1692 const std::string &formname)
1694 DSTACK(__FUNCTION_NAME);
1696 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1698 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1704 // Spawns a particle on peer with peer_id
1705 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1706 float expirationtime, float size, bool collisiondetection,
1707 bool vertical, std::string texture)
1709 DSTACK(__FUNCTION_NAME);
1711 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1713 *pkt << pos << velocity << acceleration << expirationtime
1714 << size << collisiondetection;
1715 pkt->putLongString(texture);
1718 if (peer_id != PEER_ID_INEXISTENT) {
1722 m_clients.sendToAll(0,pkt,true);
1726 // Adds a ParticleSpawner on peer with peer_id
1727 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1728 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1729 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1731 DSTACK(__FUNCTION_NAME);
1733 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1735 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1736 << minacc << maxacc << minexptime << maxexptime << minsize
1737 << maxsize << collisiondetection;
1739 pkt->putLongString(texture);
1741 *pkt << id << vertical;
1743 if (peer_id != PEER_ID_INEXISTENT) {
1747 m_clients.sendToAll(0, pkt, true);
1751 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1753 DSTACK(__FUNCTION_NAME);
1755 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1757 // Ugly error in this packet
1760 if (peer_id != PEER_ID_INEXISTENT) {
1764 m_clients.sendToAll(0, pkt, true);
1769 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1771 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1773 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1774 << form->text << form->number << form->item << form->dir
1775 << form->align << form->offset << form->world_pos << form->size;
1780 void Server::SendHUDRemove(u16 peer_id, u32 id)
1782 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1787 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1789 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1790 *pkt << id << (u8) stat;
1794 case HUD_STAT_SCALE:
1795 case HUD_STAT_ALIGN:
1796 case HUD_STAT_OFFSET:
1797 *pkt << *(v2f *) value;
1801 *pkt << *(std::string *) value;
1803 case HUD_STAT_WORLD_POS:
1804 *pkt << *(v3f *) value;
1807 *pkt << *(v2s32 *) value;
1809 case HUD_STAT_NUMBER:
1813 *pkt << *(u32 *) value;
1820 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1822 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1824 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1826 *pkt << flags << mask;
1831 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1833 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1834 *pkt << param << value;
1838 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1839 const std::string &type, const std::vector<std::string> ¶ms)
1841 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1842 *pkt << bgcolor << type << (u16) params.size();
1844 for(size_t i=0; i<params.size(); i++)
1850 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1853 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1856 *pkt << do_override << (u16) (ratio * 65535);
1861 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1863 DSTACK(__FUNCTION_NAME);
1865 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1866 *pkt << time << time_speed;
1868 if (peer_id == PEER_ID_INEXISTENT) {
1869 m_clients.sendToAll(0, pkt, true);
1876 void Server::SendPlayerHP(u16 peer_id)
1878 DSTACK(__FUNCTION_NAME);
1879 PlayerSAO *playersao = getPlayerSAO(peer_id);
1881 SendHP(peer_id, playersao->getHP());
1882 m_script->player_event(playersao,"health_changed");
1884 // Send to other clients
1885 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1886 ActiveObjectMessage aom(playersao->getId(), true, str);
1887 playersao->m_messages_out.push_back(aom);
1890 void Server::SendPlayerBreath(u16 peer_id)
1892 DSTACK(__FUNCTION_NAME);
1893 PlayerSAO *playersao = getPlayerSAO(peer_id);
1895 playersao->m_breath_not_sent = false;
1896 m_script->player_event(playersao,"breath_changed");
1897 SendBreath(peer_id, playersao->getBreath());
1900 void Server::SendMovePlayer(u16 peer_id)
1902 DSTACK(__FUNCTION_NAME);
1903 Player *player = m_env->getPlayer(peer_id);
1906 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1907 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1910 v3f pos = player->getPosition();
1911 f32 pitch = player->getPitch();
1912 f32 yaw = player->getYaw();
1913 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1914 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1923 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1925 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1928 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1929 << animation_frames[3] << animation_speed;
1934 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1936 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1937 *pkt << first << third;
1940 void Server::SendPlayerPrivileges(u16 peer_id)
1942 Player *player = m_env->getPlayer(peer_id);
1944 if(player->peer_id == PEER_ID_INEXISTENT)
1947 std::set<std::string> privs;
1948 m_script->getAuth(player->getName(), NULL, &privs);
1950 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1951 *pkt << (u16) privs.size();
1953 for(std::set<std::string>::const_iterator i = privs.begin();
1954 i != privs.end(); i++) {
1961 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1963 Player *player = m_env->getPlayer(peer_id);
1965 if(player->peer_id == PEER_ID_INEXISTENT)
1968 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1969 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1973 s32 Server::playSound(const SimpleSoundSpec &spec,
1974 const ServerSoundParams ¶ms)
1976 // Find out initial position of sound
1977 bool pos_exists = false;
1978 v3f pos = params.getPos(m_env, &pos_exists);
1979 // If position is not found while it should be, cancel sound
1980 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1983 // Filter destination clients
1984 std::list<u16> dst_clients;
1985 if(params.to_player != "")
1987 Player *player = m_env->getPlayer(params.to_player.c_str());
1989 infostream<<"Server::playSound: Player \""<<params.to_player
1990 <<"\" not found"<<std::endl;
1993 if(player->peer_id == PEER_ID_INEXISTENT){
1994 infostream<<"Server::playSound: Player \""<<params.to_player
1995 <<"\" not connected"<<std::endl;
1998 dst_clients.push_back(player->peer_id);
2002 std::list<u16> clients = m_clients.getClientIDs();
2004 for(std::list<u16>::iterator
2005 i = clients.begin(); i != clients.end(); ++i)
2007 Player *player = m_env->getPlayer(*i);
2011 if(player->getPosition().getDistanceFrom(pos) >
2012 params.max_hear_distance)
2015 dst_clients.push_back(*i);
2018 if(dst_clients.empty())
2022 s32 id = m_next_sound_id++;
2023 // The sound will exist as a reference in m_playing_sounds
2024 m_playing_sounds[id] = ServerPlayingSound();
2025 ServerPlayingSound &psound = m_playing_sounds[id];
2026 psound.params = params;
2027 for(std::list<u16>::iterator i = dst_clients.begin();
2028 i != dst_clients.end(); i++)
2029 psound.clients.insert(*i);
2031 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
2032 *pkt << id << spec.name << (float) (spec.gain * params.gain)
2033 << (u8) params.type << pos << params.object << params.loop;
2034 for(std::list<u16>::iterator i = dst_clients.begin();
2035 i != dst_clients.end(); i++) {
2037 m_clients.send(*i, 0, pkt, true, false);
2042 void Server::stopSound(s32 handle)
2044 // Get sound reference
2045 std::map<s32, ServerPlayingSound>::iterator i =
2046 m_playing_sounds.find(handle);
2047 if(i == m_playing_sounds.end())
2049 ServerPlayingSound &psound = i->second;
2051 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2054 for(std::set<u16>::iterator i = psound.clients.begin();
2055 i != psound.clients.end(); i++) {
2057 m_clients.send(*i, 0, pkt, true, false);
2060 // Remove sound reference
2061 m_playing_sounds.erase(i);
2064 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2065 std::list<u16> *far_players, float far_d_nodes)
2067 float maxd = far_d_nodes*BS;
2068 v3f p_f = intToFloat(p, BS);
2070 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2073 std::list<u16> clients = m_clients.getClientIDs();
2074 for(std::list<u16>::iterator
2075 i = clients.begin();
2076 i != clients.end(); ++i) {
2079 if(Player *player = m_env->getPlayer(*i)) {
2080 // If player is far away, only set modified blocks not sent
2081 v3f player_pos = player->getPosition();
2082 if(player_pos.getDistanceFrom(p_f) > maxd) {
2083 far_players->push_back(*i);
2090 m_clients.send(*i, 0, pkt, true, false);
2092 // This loop needs the deletion of the packet here
2096 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2097 std::list<u16> *far_players, float far_d_nodes,
2098 bool remove_metadata)
2100 float maxd = far_d_nodes*BS;
2101 v3f p_f = intToFloat(p, BS);
2103 std::list<u16> clients = m_clients.getClientIDs();
2104 for(std::list<u16>::iterator
2105 i = clients.begin();
2106 i != clients.end(); ++i)
2112 Player *player = m_env->getPlayer(*i);
2115 // If player is far away, only set modified blocks not sent
2116 v3f player_pos = player->getPosition();
2117 if(player_pos.getDistanceFrom(p_f) > maxd)
2119 far_players->push_back(*i);
2125 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2127 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2129 *pkt << p << n.param0 << n.param1 << n.param2
2130 << (u8) (remove_metadata ? 0 : 1);
2132 if (!remove_metadata) {
2133 if (client->net_proto_version <= 21) {
2134 // Old clients always clear metadata; fix it
2135 // by sending the full block again.
2136 client->SetBlockNotSent(p);
2143 if (pkt->getSize() > 0)
2144 m_clients.send(*i, 0, pkt, true);
2148 void Server::setBlockNotSent(v3s16 p)
2150 std::list<u16> clients = m_clients.getClientIDs();
2152 for(std::list<u16>::iterator
2153 i = clients.begin();
2154 i != clients.end(); ++i)
2156 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2157 client->SetBlockNotSent(p);
2162 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2164 DSTACK(__FUNCTION_NAME);
2166 v3s16 p = block->getPos();
2169 Create a packet with the block in the right format
2172 std::ostringstream os(std::ios_base::binary);
2173 block->serialize(os, ver, false);
2174 block->serializeNetworkSpecific(os, net_proto_version);
2175 std::string s = os.str();
2177 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2178 2 + 2 + 2 + 2 + s.size(), peer_id);
2181 pkt->putRawString(s.c_str(), s.size());
2185 void Server::SendBlocks(float dtime)
2187 DSTACK(__FUNCTION_NAME);
2189 JMutexAutoLock envlock(m_env_mutex);
2190 //TODO check if one big lock could be faster then multiple small ones
2192 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2194 std::vector<PrioritySortedBlockTransfer> queue;
2196 s32 total_sending = 0;
2199 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2201 std::list<u16> clients = m_clients.getClientIDs();
2204 for(std::list<u16>::iterator
2205 i = clients.begin();
2206 i != clients.end(); ++i)
2208 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2213 total_sending += client->SendingCount();
2214 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2220 // Lowest priority number comes first.
2221 // Lowest is most important.
2222 std::sort(queue.begin(), queue.end());
2225 for(u32 i=0; i<queue.size(); i++)
2227 //TODO: Calculate limit dynamically
2228 if(total_sending >= g_settings->getS32
2229 ("max_simultaneous_block_sends_server_total"))
2232 PrioritySortedBlockTransfer q = queue[i];
2234 MapBlock *block = NULL;
2237 block = m_env->getMap().getBlockNoCreate(q.pos);
2239 catch(InvalidPositionException &e)
2244 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2249 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2251 client->SentBlock(q.pos);
2257 void Server::fillMediaCache()
2259 DSTACK(__FUNCTION_NAME);
2261 infostream<<"Server: Calculating media file checksums"<<std::endl;
2263 // Collect all media file paths
2264 std::list<std::string> paths;
2265 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2266 i != m_mods.end(); i++){
2267 const ModSpec &mod = *i;
2268 paths.push_back(mod.path + DIR_DELIM + "textures");
2269 paths.push_back(mod.path + DIR_DELIM + "sounds");
2270 paths.push_back(mod.path + DIR_DELIM + "media");
2271 paths.push_back(mod.path + DIR_DELIM + "models");
2273 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2275 // Collect media file information from paths into cache
2276 for(std::list<std::string>::iterator i = paths.begin();
2277 i != paths.end(); i++)
2279 std::string mediapath = *i;
2280 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2281 for(u32 j=0; j<dirlist.size(); j++){
2282 if(dirlist[j].dir) // Ignode dirs
2284 std::string filename = dirlist[j].name;
2285 // If name contains illegal characters, ignore the file
2286 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2287 infostream<<"Server: ignoring illegal file name: \""
2288 <<filename<<"\""<<std::endl;
2291 // If name is not in a supported format, ignore it
2292 const char *supported_ext[] = {
2293 ".png", ".jpg", ".bmp", ".tga",
2294 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2296 ".x", ".b3d", ".md2", ".obj",
2299 if(removeStringEnd(filename, supported_ext) == ""){
2300 infostream<<"Server: ignoring unsupported file extension: \""
2301 <<filename<<"\""<<std::endl;
2304 // Ok, attempt to load the file and add to cache
2305 std::string filepath = mediapath + DIR_DELIM + filename;
2307 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2308 if(fis.good() == false){
2309 errorstream<<"Server::fillMediaCache(): Could not open \""
2310 <<filename<<"\" for reading"<<std::endl;
2313 std::ostringstream tmp_os(std::ios_base::binary);
2317 fis.read(buf, 1024);
2318 std::streamsize len = fis.gcount();
2319 tmp_os.write(buf, len);
2328 errorstream<<"Server::fillMediaCache(): Failed to read \""
2329 <<filename<<"\""<<std::endl;
2332 if(tmp_os.str().length() == 0){
2333 errorstream<<"Server::fillMediaCache(): Empty file \""
2334 <<filepath<<"\""<<std::endl;
2339 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2341 unsigned char *digest = sha1.getDigest();
2342 std::string sha1_base64 = base64_encode(digest, 20);
2343 std::string sha1_hex = hex_encode((char*)digest, 20);
2347 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2348 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2353 struct SendableMediaAnnouncement
2356 std::string sha1_digest;
2358 SendableMediaAnnouncement(const std::string &name_="",
2359 const std::string &sha1_digest_=""):
2361 sha1_digest(sha1_digest_)
2365 void Server::sendMediaAnnouncement(u16 peer_id)
2367 DSTACK(__FUNCTION_NAME);
2369 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2372 std::list<SendableMediaAnnouncement> file_announcements;
2374 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2375 i != m_media.end(); i++){
2377 file_announcements.push_back(
2378 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2382 std::ostringstream os(std::ios_base::binary);
2389 u16 length of sha1_digest
2394 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2395 *pkt << (u16) file_announcements.size();
2397 for(std::list<SendableMediaAnnouncement>::iterator
2398 j = file_announcements.begin();
2399 j != file_announcements.end(); ++j) {
2400 *pkt << j->name << j->sha1_digest;
2403 *pkt << g_settings->get("remote_media");
2407 struct SendableMedia
2413 SendableMedia(const std::string &name_="", const std::string &path_="",
2414 const std::string &data_=""):
2421 void Server::sendRequestedMedia(u16 peer_id,
2422 const std::list<std::string> &tosend)
2424 DSTACK(__FUNCTION_NAME);
2426 verbosestream<<"Server::sendRequestedMedia(): "
2427 <<"Sending files to client"<<std::endl;
2431 // Put 5kB in one bunch (this is not accurate)
2432 u32 bytes_per_bunch = 5000;
2434 std::vector< std::list<SendableMedia> > file_bunches;
2435 file_bunches.push_back(std::list<SendableMedia>());
2437 u32 file_size_bunch_total = 0;
2439 for(std::list<std::string>::const_iterator i = tosend.begin();
2440 i != tosend.end(); ++i)
2442 const std::string &name = *i;
2444 if(m_media.find(name) == m_media.end()) {
2445 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2446 <<"unknown file \""<<(name)<<"\""<<std::endl;
2450 //TODO get path + name
2451 std::string tpath = m_media[name].path;
2454 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2455 if(fis.good() == false){
2456 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2457 <<tpath<<"\" for reading"<<std::endl;
2460 std::ostringstream tmp_os(std::ios_base::binary);
2464 fis.read(buf, 1024);
2465 std::streamsize len = fis.gcount();
2466 tmp_os.write(buf, len);
2467 file_size_bunch_total += len;
2476 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2477 <<name<<"\""<<std::endl;
2480 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2481 <<tname<<"\""<<std::endl;*/
2483 file_bunches[file_bunches.size()-1].push_back(
2484 SendableMedia(name, tpath, tmp_os.str()));
2486 // Start next bunch if got enough data
2487 if(file_size_bunch_total >= bytes_per_bunch) {
2488 file_bunches.push_back(std::list<SendableMedia>());
2489 file_size_bunch_total = 0;
2494 /* Create and send packets */
2496 u16 num_bunches = file_bunches.size();
2497 for(u16 i = 0; i < num_bunches; i++) {
2500 u16 total number of texture bunches
2501 u16 index of this bunch
2502 u32 number of files in this bunch
2511 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2512 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2514 for(std::list<SendableMedia>::iterator
2515 j = file_bunches[i].begin();
2516 j != file_bunches[i].end(); ++j) {
2518 pkt->putLongString(j->data);
2521 verbosestream << "Server::sendRequestedMedia(): bunch "
2522 << i << "/" << num_bunches
2523 << " files=" << file_bunches[i].size()
2524 << " size=" << pkt->getSize() << std::endl;
2529 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2531 if(m_detached_inventories.count(name) == 0) {
2532 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2535 Inventory *inv = m_detached_inventories[name];
2536 std::ostringstream os(std::ios_base::binary);
2538 os << serializeString(name);
2542 std::string s = os.str();
2544 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2545 pkt->putRawString(s.c_str(), s.size());
2547 if (peer_id != PEER_ID_INEXISTENT) {
2551 m_clients.sendToAll(0, pkt, true);
2555 void Server::sendDetachedInventories(u16 peer_id)
2557 DSTACK(__FUNCTION_NAME);
2559 for(std::map<std::string, Inventory*>::iterator
2560 i = m_detached_inventories.begin();
2561 i != m_detached_inventories.end(); i++) {
2562 const std::string &name = i->first;
2563 //Inventory *inv = i->second;
2564 sendDetachedInventory(name, peer_id);
2572 void Server::DiePlayer(u16 peer_id)
2574 DSTACK(__FUNCTION_NAME);
2576 PlayerSAO *playersao = getPlayerSAO(peer_id);
2579 infostream << "Server::DiePlayer(): Player "
2580 << playersao->getPlayer()->getName()
2581 << " dies" << std::endl;
2583 playersao->setHP(0);
2585 // Trigger scripted stuff
2586 m_script->on_dieplayer(playersao);
2588 SendPlayerHP(peer_id);
2589 SendDeathscreen(peer_id, false, v3f(0,0,0));
2592 void Server::RespawnPlayer(u16 peer_id)
2594 DSTACK(__FUNCTION_NAME);
2596 PlayerSAO *playersao = getPlayerSAO(peer_id);
2599 infostream << "Server::RespawnPlayer(): Player "
2600 << playersao->getPlayer()->getName()
2601 << " respawns" << std::endl;
2603 playersao->setHP(PLAYER_MAX_HP);
2604 playersao->setBreath(PLAYER_MAX_BREATH);
2606 SendPlayerHP(peer_id);
2608 bool repositioned = m_script->on_respawnplayer(playersao);
2610 v3f pos = findSpawnPos(m_env->getServerMap());
2611 playersao->setPos(pos);
2615 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2617 DSTACK(__FUNCTION_NAME);
2619 SendAccessDenied(peer_id, reason);
2620 m_clients.event(peer_id, CSE_SetDenied);
2621 m_con.DisconnectPeer(peer_id);
2624 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2626 DSTACK(__FUNCTION_NAME);
2627 std::wstring message;
2630 Clear references to playing sounds
2632 for(std::map<s32, ServerPlayingSound>::iterator
2633 i = m_playing_sounds.begin();
2634 i != m_playing_sounds.end();)
2636 ServerPlayingSound &psound = i->second;
2637 psound.clients.erase(peer_id);
2638 if(psound.clients.empty())
2639 m_playing_sounds.erase(i++);
2644 Player *player = m_env->getPlayer(peer_id);
2646 // Collect information about leaving in chat
2648 if(player != NULL && reason != CDR_DENY)
2650 std::wstring name = narrow_to_wide(player->getName());
2653 message += L" left the game.";
2654 if(reason == CDR_TIMEOUT)
2655 message += L" (timed out)";
2659 /* Run scripts and remove from environment */
2663 PlayerSAO *playersao = player->getPlayerSAO();
2666 m_script->on_leaveplayer(playersao);
2668 playersao->disconnected();
2676 if(player != NULL && reason != CDR_DENY)
2678 std::ostringstream os(std::ios_base::binary);
2679 std::list<u16> clients = m_clients.getClientIDs();
2681 for(std::list<u16>::iterator
2682 i = clients.begin();
2683 i != clients.end(); ++i)
2686 Player *player = m_env->getPlayer(*i);
2689 // Get name of player
2690 os<<player->getName()<<" ";
2693 actionstream<<player->getName()<<" "
2694 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2695 <<" List of players: "<<os.str()<<std::endl;
2699 JMutexAutoLock env_lock(m_env_mutex);
2700 m_clients.DeleteClient(peer_id);
2704 // Send leave chat message to all remaining clients
2705 if(message.length() != 0)
2706 SendChatMessage(PEER_ID_INEXISTENT,message);
2709 void Server::UpdateCrafting(u16 peer_id)
2711 DSTACK(__FUNCTION_NAME);
2713 Player* player = m_env->getPlayer(peer_id);
2716 // Get a preview for crafting
2718 InventoryLocation loc;
2719 loc.setPlayer(player->getName());
2720 getCraftingResult(&player->inventory, preview, false, this);
2721 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2723 // Put the new preview in
2724 InventoryList *plist = player->inventory.getList("craftpreview");
2726 assert(plist->getSize() >= 1);
2727 plist->changeItem(0, preview);
2730 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2732 RemoteClient *client = getClientNoEx(peer_id,state_min);
2734 throw ClientNotFoundException("Client not found");
2738 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2740 return m_clients.getClientNoEx(peer_id, state_min);
2743 std::string Server::getPlayerName(u16 peer_id)
2745 Player *player = m_env->getPlayer(peer_id);
2747 return "[id="+itos(peer_id)+"]";
2748 return player->getName();
2751 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2753 Player *player = m_env->getPlayer(peer_id);
2756 return player->getPlayerSAO();
2759 std::wstring Server::getStatusString()
2761 std::wostringstream os(std::ios_base::binary);
2764 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2766 os<<L", uptime="<<m_uptime.get();
2768 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2769 // Information about clients
2772 std::list<u16> clients = m_clients.getClientIDs();
2773 for(std::list<u16>::iterator i = clients.begin();
2774 i != clients.end(); ++i)
2777 Player *player = m_env->getPlayer(*i);
2778 // Get name of player
2779 std::wstring name = L"unknown";
2781 name = narrow_to_wide(player->getName());
2782 // Add name to information string
2790 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2791 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2792 if(g_settings->get("motd") != "")
2793 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2797 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2799 std::set<std::string> privs;
2800 m_script->getAuth(name, NULL, &privs);
2804 bool Server::checkPriv(const std::string &name, const std::string &priv)
2806 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2807 return (privs.count(priv) != 0);
2810 void Server::reportPrivsModified(const std::string &name)
2813 std::list<u16> clients = m_clients.getClientIDs();
2814 for(std::list<u16>::iterator
2815 i = clients.begin();
2816 i != clients.end(); ++i){
2817 Player *player = m_env->getPlayer(*i);
2818 reportPrivsModified(player->getName());
2821 Player *player = m_env->getPlayer(name.c_str());
2824 SendPlayerPrivileges(player->peer_id);
2825 PlayerSAO *sao = player->getPlayerSAO();
2828 sao->updatePrivileges(
2829 getPlayerEffectivePrivs(name),
2834 void Server::reportInventoryFormspecModified(const std::string &name)
2836 Player *player = m_env->getPlayer(name.c_str());
2839 SendPlayerInventoryFormspec(player->peer_id);
2842 void Server::setIpBanned(const std::string &ip, const std::string &name)
2844 m_banmanager->add(ip, name);
2847 void Server::unsetIpBanned(const std::string &ip_or_name)
2849 m_banmanager->remove(ip_or_name);
2852 std::string Server::getBanDescription(const std::string &ip_or_name)
2854 return m_banmanager->getBanDescription(ip_or_name);
2857 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2859 Player *player = m_env->getPlayer(name);
2863 if (player->peer_id == PEER_ID_INEXISTENT)
2866 SendChatMessage(player->peer_id, msg);
2869 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2871 Player *player = m_env->getPlayer(playername);
2875 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2879 SendShowFormspecMessage(player->peer_id, formspec, formname);
2883 u32 Server::hudAdd(Player *player, HudElement *form) {
2887 u32 id = player->addHud(form);
2889 SendHUDAdd(player->peer_id, id, form);
2894 bool Server::hudRemove(Player *player, u32 id) {
2898 HudElement* todel = player->removeHud(id);
2905 SendHUDRemove(player->peer_id, id);
2909 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2913 SendHUDChange(player->peer_id, id, stat, data);
2917 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2921 SendHUDSetFlags(player->peer_id, flags, mask);
2922 player->hud_flags = flags;
2924 PlayerSAO* playersao = player->getPlayerSAO();
2926 if (playersao == NULL)
2929 m_script->player_event(playersao, "hud_changed");
2933 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2936 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2939 std::ostringstream os(std::ios::binary);
2940 writeS32(os, hotbar_itemcount);
2941 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2945 void Server::hudSetHotbarImage(Player *player, std::string name) {
2949 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2952 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2956 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2959 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2964 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2968 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2973 SendEyeOffset(player->peer_id, first, third);
2977 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2978 const std::string &type, const std::vector<std::string> ¶ms)
2983 SendSetSky(player->peer_id, bgcolor, type, params);
2987 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2993 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2997 void Server::notifyPlayers(const std::wstring &msg)
2999 SendChatMessage(PEER_ID_INEXISTENT,msg);
3002 void Server::spawnParticle(const char *playername, v3f pos,
3003 v3f velocity, v3f acceleration,
3004 float expirationtime, float size, bool
3005 collisiondetection, bool vertical, std::string texture)
3007 Player *player = m_env->getPlayer(playername);
3010 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3011 expirationtime, size, collisiondetection, vertical, texture);
3014 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3015 float expirationtime, float size,
3016 bool collisiondetection, bool vertical, std::string texture)
3018 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3019 expirationtime, size, collisiondetection, vertical, texture);
3022 u32 Server::addParticleSpawner(const char *playername,
3023 u16 amount, float spawntime,
3024 v3f minpos, v3f maxpos,
3025 v3f minvel, v3f maxvel,
3026 v3f minacc, v3f maxacc,
3027 float minexptime, float maxexptime,
3028 float minsize, float maxsize,
3029 bool collisiondetection, bool vertical, std::string texture)
3031 Player *player = m_env->getPlayer(playername);
3036 for(;;) // look for unused particlespawner id
3039 if (std::find(m_particlespawner_ids.begin(),
3040 m_particlespawner_ids.end(), id)
3041 == m_particlespawner_ids.end())
3043 m_particlespawner_ids.push_back(id);
3048 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3049 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3050 minexptime, maxexptime, minsize, maxsize,
3051 collisiondetection, vertical, texture, id);
3056 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3057 v3f minpos, v3f maxpos,
3058 v3f minvel, v3f maxvel,
3059 v3f minacc, v3f maxacc,
3060 float minexptime, float maxexptime,
3061 float minsize, float maxsize,
3062 bool collisiondetection, bool vertical, std::string texture)
3065 for(;;) // look for unused particlespawner id
3068 if (std::find(m_particlespawner_ids.begin(),
3069 m_particlespawner_ids.end(), id)
3070 == m_particlespawner_ids.end())
3072 m_particlespawner_ids.push_back(id);
3077 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3078 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3079 minexptime, maxexptime, minsize, maxsize,
3080 collisiondetection, vertical, texture, id);
3085 void Server::deleteParticleSpawner(const char *playername, u32 id)
3087 Player *player = m_env->getPlayer(playername);
3091 m_particlespawner_ids.erase(
3092 std::remove(m_particlespawner_ids.begin(),
3093 m_particlespawner_ids.end(), id),
3094 m_particlespawner_ids.end());
3095 SendDeleteParticleSpawner(player->peer_id, id);
3098 void Server::deleteParticleSpawnerAll(u32 id)
3100 m_particlespawner_ids.erase(
3101 std::remove(m_particlespawner_ids.begin(),
3102 m_particlespawner_ids.end(), id),
3103 m_particlespawner_ids.end());
3104 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3107 Inventory* Server::createDetachedInventory(const std::string &name)
3109 if(m_detached_inventories.count(name) > 0){
3110 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3111 delete m_detached_inventories[name];
3113 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3115 Inventory *inv = new Inventory(m_itemdef);
3117 m_detached_inventories[name] = inv;
3118 //TODO find a better way to do this
3119 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3126 BoolScopeSet(bool *dst, bool val):
3129 m_orig_state = *m_dst;
3134 *m_dst = m_orig_state;
3141 // actions: time-reversed list
3142 // Return value: success/failure
3143 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3144 std::list<std::string> *log)
3146 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3147 ServerMap *map = (ServerMap*)(&m_env->getMap());
3149 // Fail if no actions to handle
3150 if(actions.empty()){
3151 log->push_back("Nothing to do.");
3158 for(std::list<RollbackAction>::const_iterator
3159 i = actions.begin();
3160 i != actions.end(); i++)
3162 const RollbackAction &action = *i;
3164 bool success = action.applyRevert(map, this, this);
3167 std::ostringstream os;
3168 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3169 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3171 log->push_back(os.str());
3173 std::ostringstream os;
3174 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3175 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3177 log->push_back(os.str());
3181 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3182 <<" failed"<<std::endl;
3184 // Call it done if less than half failed
3185 return num_failed <= num_tried/2;
3188 // IGameDef interface
3190 IItemDefManager* Server::getItemDefManager()
3194 INodeDefManager* Server::getNodeDefManager()
3198 ICraftDefManager* Server::getCraftDefManager()
3202 ITextureSource* Server::getTextureSource()
3206 IShaderSource* Server::getShaderSource()
3210 scene::ISceneManager* Server::getSceneManager()
3215 u16 Server::allocateUnknownNodeId(const std::string &name)
3217 return m_nodedef->allocateDummy(name);
3219 ISoundManager* Server::getSoundManager()
3221 return &dummySoundManager;
3223 MtEventManager* Server::getEventManager()
3228 IWritableItemDefManager* Server::getWritableItemDefManager()
3232 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3236 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3241 const ModSpec* Server::getModSpec(const std::string &modname)
3243 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3244 i != m_mods.end(); i++){
3245 const ModSpec &mod = *i;
3246 if(mod.name == modname)
3251 void Server::getModNames(std::list<std::string> &modlist)
3253 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3255 modlist.push_back(i->name);
3258 std::string Server::getBuiltinLuaPath()
3260 return porting::path_share + DIR_DELIM + "builtin";
3263 v3f findSpawnPos(ServerMap &map)
3265 //return v3f(50,50,50)*BS;
3270 nodepos = v2s16(0,0);
3275 s16 water_level = map.getWaterLevel();
3277 // Try to find a good place a few times
3278 for(s32 i=0; i<1000; i++)
3281 // We're going to try to throw the player to this position
3282 v2s16 nodepos2d = v2s16(
3283 -range + (myrand() % (range * 2)),
3284 -range + (myrand() % (range * 2)));
3286 // Get ground height at point
3287 s16 groundheight = map.findGroundLevel(nodepos2d);
3288 if (groundheight <= water_level) // Don't go underwater
3290 if (groundheight > water_level + 6) // Don't go to high places
3293 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3294 bool is_good = false;
3296 for (s32 i = 0; i < 10; i++) {
3297 v3s16 blockpos = getNodeBlockPos(nodepos);
3298 map.emergeBlock(blockpos, true);
3299 content_t c = map.getNodeNoEx(nodepos).getContent();
3300 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3302 if (air_count >= 2){
3310 // Found a good place
3311 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3317 return intToFloat(nodepos, BS);
3320 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3322 bool newplayer = false;
3325 Try to get an existing player
3327 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3329 // If player is already connected, cancel
3330 if(player != NULL && player->peer_id != 0)
3332 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3337 If player with the wanted peer_id already exists, cancel.
3339 if(m_env->getPlayer(peer_id) != NULL)
3341 infostream<<"emergePlayer(): Player with wrong name but same"
3342 " peer_id already exists"<<std::endl;
3346 // Load player if it isn't already loaded
3348 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3351 // Create player if it doesn't exist
3354 player = new RemotePlayer(this, name);
3355 // Set player position
3356 infostream<<"Server: Finding spawn place for player \""
3357 <<name<<"\""<<std::endl;
3358 v3f pos = findSpawnPos(m_env->getServerMap());
3359 player->setPosition(pos);
3361 // Make sure the player is saved
3362 player->setModified(true);
3364 // Add player to environment
3365 m_env->addPlayer(player);
3368 // Create a new player active object
3369 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3370 getPlayerEffectivePrivs(player->getName()),
3373 /* Clean up old HUD elements from previous sessions */
3376 /* Add object to environment */
3377 m_env->addActiveObject(playersao);
3381 m_script->on_newplayer(playersao);
3387 void dedicated_server_loop(Server &server, bool &kill)
3389 DSTACK(__FUNCTION_NAME);
3391 verbosestream<<"dedicated_server_loop()"<<std::endl;
3393 IntervalLimiter m_profiler_interval;
3397 float steplen = g_settings->getFloat("dedicated_server_step");
3398 // This is kind of a hack but can be done like this
3399 // because server.step() is very light
3401 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3402 sleep_ms((int)(steplen*1000.0));
3404 server.step(steplen);
3406 if(server.getShutdownRequested() || kill)
3408 infostream<<"Dedicated server quitting"<<std::endl;
3410 if(g_settings->getBool("server_announce"))
3411 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3419 float profiler_print_interval =
3420 g_settings->getFloat("profiler_print_interval");
3421 if(profiler_print_interval != 0)
3423 if(m_profiler_interval.step(steplen, profiler_print_interval))
3425 infostream<<"Profiler:"<<std::endl;
3426 g_profiler->print(infostream);
3427 g_profiler->clear();