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 // Create world if it doesn't exist
226 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
227 throw ServerError("Failed to initialize world");
229 // Create server thread
230 m_thread = new ServerThread(this);
232 // Create emerge manager
233 m_emerge = new EmergeManager(this);
235 // Create ban manager
236 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
237 m_banmanager = new BanManager(ban_path);
239 ModConfiguration modconf(m_path_world);
240 m_mods = modconf.getMods();
241 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
242 // complain about mods with unsatisfied dependencies
243 if(!modconf.isConsistent())
245 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
246 it != unsatisfied_mods.end(); ++it)
249 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
250 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
251 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
252 errorstream << " \"" << *dep_it << "\"";
253 errorstream << std::endl;
257 Settings worldmt_settings;
258 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
259 worldmt_settings.readConfigFile(worldmt.c_str());
260 std::vector<std::string> names = worldmt_settings.getNames();
261 std::set<std::string> load_mod_names;
262 for(std::vector<std::string>::iterator it = names.begin();
263 it != names.end(); ++it)
265 std::string name = *it;
266 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
267 load_mod_names.insert(name.substr(9));
269 // complain about mods declared to be loaded, but not found
270 for(std::vector<ModSpec>::iterator it = m_mods.begin();
271 it != m_mods.end(); ++it)
272 load_mod_names.erase((*it).name);
273 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
274 it != unsatisfied_mods.end(); ++it)
275 load_mod_names.erase((*it).name);
276 if(!load_mod_names.empty())
278 errorstream << "The following mods could not be found:";
279 for(std::set<std::string>::iterator it = load_mod_names.begin();
280 it != load_mod_names.end(); ++it)
281 errorstream << " \"" << (*it) << "\"";
282 errorstream << std::endl;
286 JMutexAutoLock envlock(m_env_mutex);
288 // Load mapgen params from Settings
289 m_emerge->loadMapgenParams();
291 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
292 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
294 // Initialize scripting
295 infostream<<"Server: Initializing Lua"<<std::endl;
297 m_script = new GameScripting(this);
299 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
301 if (!m_script->loadScript(scriptpath))
302 throw ModError("Failed to load and run " + scriptpath);
305 infostream<<"Server: Loading mods: ";
306 for(std::vector<ModSpec>::iterator i = m_mods.begin();
307 i != m_mods.end(); i++){
308 const ModSpec &mod = *i;
309 infostream<<mod.name<<" ";
311 infostream<<std::endl;
312 // Load and run "mod" scripts
313 for(std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++){
315 const ModSpec &mod = *i;
316 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
317 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
318 <<scriptpath<<"\"]"<<std::endl;
319 bool success = m_script->loadMod(scriptpath, mod.name);
321 errorstream<<"Server: Failed to load and run "
322 <<scriptpath<<std::endl;
323 throw ModError("Failed to load and run "+scriptpath);
327 // Read Textures and calculate sha1 sums
330 // Apply item aliases in the node definition manager
331 m_nodedef->updateAliases(m_itemdef);
333 m_nodedef->setNodeRegistrationStatus(true);
335 // Perform pending node name resolutions
336 m_nodedef->runNodeResolverCallbacks();
338 // Initialize Environment
339 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
341 m_clients.setEnv(m_env);
343 // Initialize mapgens
344 m_emerge->initMapgens();
346 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
347 if (m_enable_rollback_recording) {
348 // Create rollback manager
349 m_rollback = new RollbackManager(m_path_world, this);
352 // Give environment reference to scripting api
353 m_script->initializeEnvironment(m_env);
355 // Register us to receive map edit events
356 servermap->addEventReceiver(this);
358 // If file exists, load environment metadata
359 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
361 infostream<<"Server: Loading environment metadata"<<std::endl;
365 // Add some test ActiveBlockModifiers to environment
366 add_legacy_abms(m_env, m_nodedef);
368 m_liquid_transform_every = g_settings->getFloat("liquid_update");
373 infostream<<"Server destructing"<<std::endl;
375 // Send shutdown message
376 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
379 JMutexAutoLock envlock(m_env_mutex);
381 // Execute script shutdown hooks
382 m_script->on_shutdown();
384 infostream<<"Server: Saving players"<<std::endl;
385 m_env->saveLoadedPlayers();
387 infostream<<"Server: Saving environment metadata"<<std::endl;
395 // stop all emerge threads before deleting players that may have
396 // requested blocks to be emerged
397 m_emerge->stopThreads();
399 // Delete things in the reverse order of creation
402 // N.B. the EmergeManager should be deleted after the Environment since Map
403 // depends on EmergeManager to write its current params to the map meta
412 // Deinitialize scripting
413 infostream<<"Server: Deinitializing scripting"<<std::endl;
416 // Delete detached inventories
417 for (std::map<std::string, Inventory*>::iterator
418 i = m_detached_inventories.begin();
419 i != m_detached_inventories.end(); i++) {
424 void Server::start(Address bind_addr)
426 DSTACK(__FUNCTION_NAME);
428 m_bind_addr = bind_addr;
430 infostream<<"Starting server on "
431 << bind_addr.serializeString() <<"..."<<std::endl;
433 // Stop thread if already running
436 // Initialize connection
437 m_con.SetTimeoutMs(30);
438 m_con.Serve(bind_addr);
443 // ASCII art for the win!
445 <<" .__ __ __ "<<std::endl
446 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
447 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
448 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
449 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
450 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
451 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
452 actionstream<<"Server for gameid=\""<<m_gamespec.id
453 <<"\" listening on "<<bind_addr.serializeString()<<":"
454 <<bind_addr.getPort() << "."<<std::endl;
459 DSTACK(__FUNCTION_NAME);
461 infostream<<"Server: Stopping and waiting threads"<<std::endl;
463 // Stop threads (set run=false first so both start stopping)
465 //m_emergethread.setRun(false);
467 //m_emergethread.stop();
469 infostream<<"Server: Threads stopped"<<std::endl;
472 void Server::step(float dtime)
474 DSTACK(__FUNCTION_NAME);
479 JMutexAutoLock lock(m_step_dtime_mutex);
480 m_step_dtime += dtime;
482 // Throw if fatal error occurred in thread
483 std::string async_err = m_async_fatal_error.get();
484 if(async_err != "") {
485 if (m_simple_singleplayer_mode) {
486 throw ServerError(async_err);
489 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
490 << "Please fix the following error:" << std::endl
491 << async_err << std::endl;
492 FATAL_ERROR(async_err.c_str());
497 void Server::AsyncRunStep(bool initial_step)
499 DSTACK(__FUNCTION_NAME);
501 g_profiler->add("Server::AsyncRunStep (num)", 1);
505 JMutexAutoLock lock1(m_step_dtime_mutex);
506 dtime = m_step_dtime;
510 // Send blocks to clients
514 if((dtime < 0.001) && (initial_step == false))
517 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
519 //infostream<<"Server steps "<<dtime<<std::endl;
520 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
523 JMutexAutoLock lock1(m_step_dtime_mutex);
524 m_step_dtime -= dtime;
531 m_uptime.set(m_uptime.get() + dtime);
537 Update time of day and overall game time
539 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
542 Send to clients at constant intervals
545 m_time_of_day_send_timer -= dtime;
546 if(m_time_of_day_send_timer < 0.0) {
547 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
548 u16 time = m_env->getTimeOfDay();
549 float time_speed = g_settings->getFloat("time_speed");
550 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
554 JMutexAutoLock lock(m_env_mutex);
555 // Figure out and report maximum lag to environment
556 float max_lag = m_env->getMaxLagEstimate();
557 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
559 if(dtime > 0.1 && dtime > max_lag * 2.0)
560 infostream<<"Server: Maximum lag peaked to "<<dtime
564 m_env->reportMaxLagEstimate(max_lag);
566 ScopeProfiler sp(g_profiler, "SEnv step");
567 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
571 static const float map_timer_and_unload_dtime = 2.92;
572 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
574 JMutexAutoLock lock(m_env_mutex);
575 // Run Map's timers and unload unused data
576 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
577 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
578 g_settings->getFloat("server_unload_unused_data_timeout"));
585 /* Transform liquids */
586 m_liquid_transform_timer += dtime;
587 if(m_liquid_transform_timer >= m_liquid_transform_every)
589 m_liquid_transform_timer -= m_liquid_transform_every;
591 JMutexAutoLock lock(m_env_mutex);
593 ScopeProfiler sp(g_profiler, "Server: liquid transform");
595 std::map<v3s16, MapBlock*> modified_blocks;
596 m_env->getMap().transformLiquids(modified_blocks);
601 core::map<v3s16, MapBlock*> lighting_modified_blocks;
602 ServerMap &map = ((ServerMap&)m_env->getMap());
603 map.updateLighting(modified_blocks, lighting_modified_blocks);
605 // Add blocks modified by lighting to modified_blocks
606 for(core::map<v3s16, MapBlock*>::Iterator
607 i = lighting_modified_blocks.getIterator();
608 i.atEnd() == false; i++)
610 MapBlock *block = i.getNode()->getValue();
611 modified_blocks.insert(block->getPos(), block);
615 Set the modified blocks unsent for all the clients
617 if(!modified_blocks.empty())
619 SetBlocksNotSent(modified_blocks);
622 m_clients.step(dtime);
624 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
626 // send masterserver announce
628 float &counter = m_masterserver_timer;
629 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
630 g_settings->getBool("server_announce"))
632 ServerList::sendAnnounce(counter ? "update" : "start",
633 m_bind_addr.getPort(),
634 m_clients.getPlayerNames(),
636 m_env->getGameTime(),
639 m_emerge->params.mg_name,
648 Check added and deleted active objects
651 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
652 JMutexAutoLock envlock(m_env_mutex);
655 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
656 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
658 // Radius inside which objects are active
659 s16 radius = g_settings->getS16("active_object_send_range_blocks");
660 s16 player_radius = g_settings->getS16("player_transfer_distance");
662 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
663 !g_settings->getBool("unlimited_player_transfer_distance"))
664 player_radius = radius;
666 radius *= MAP_BLOCKSIZE;
667 player_radius *= MAP_BLOCKSIZE;
669 for(std::map<u16, RemoteClient*>::iterator
671 i != clients.end(); ++i)
673 RemoteClient *client = i->second;
675 // If definitions and textures have not been sent, don't
676 // send objects either
677 if (client->getState() < CS_DefinitionsSent)
680 Player *player = m_env->getPlayer(client->peer_id);
683 // This can happen if the client timeouts somehow
684 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
686 <<" has no associated player"<<std::endl;*/
689 v3s16 pos = floatToInt(player->getPosition(), BS);
691 std::set<u16> removed_objects;
692 std::set<u16> added_objects;
693 m_env->getRemovedActiveObjects(pos, radius, player_radius,
694 client->m_known_objects, removed_objects);
695 m_env->getAddedActiveObjects(pos, radius, player_radius,
696 client->m_known_objects, added_objects);
698 // Ignore if nothing happened
699 if(removed_objects.empty() && added_objects.empty())
701 //infostream<<"active objects: none changed"<<std::endl;
705 std::string data_buffer;
709 // Handle removed objects
710 writeU16((u8*)buf, removed_objects.size());
711 data_buffer.append(buf, 2);
712 for(std::set<u16>::iterator
713 i = removed_objects.begin();
714 i != removed_objects.end(); ++i)
718 ServerActiveObject* obj = m_env->getActiveObject(id);
720 // Add to data buffer for sending
721 writeU16((u8*)buf, id);
722 data_buffer.append(buf, 2);
724 // Remove from known objects
725 client->m_known_objects.erase(id);
727 if(obj && obj->m_known_by_count > 0)
728 obj->m_known_by_count--;
731 // Handle added objects
732 writeU16((u8*)buf, added_objects.size());
733 data_buffer.append(buf, 2);
734 for(std::set<u16>::iterator
735 i = added_objects.begin();
736 i != added_objects.end(); ++i)
740 ServerActiveObject* obj = m_env->getActiveObject(id);
743 u8 type = ACTIVEOBJECT_TYPE_INVALID;
745 infostream<<"WARNING: "<<__FUNCTION_NAME
746 <<": NULL object"<<std::endl;
748 type = obj->getSendType();
750 // Add to data buffer for sending
751 writeU16((u8*)buf, id);
752 data_buffer.append(buf, 2);
753 writeU8((u8*)buf, type);
754 data_buffer.append(buf, 1);
757 data_buffer.append(serializeLongString(
758 obj->getClientInitializationData(client->net_proto_version)));
760 data_buffer.append(serializeLongString(""));
762 // Add to known objects
763 client->m_known_objects.insert(id);
766 obj->m_known_by_count++;
769 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
770 verbosestream << "Server: Sent object remove/add: "
771 << removed_objects.size() << " removed, "
772 << added_objects.size() << " added, "
773 << "packet size is " << pktSize << std::endl;
782 JMutexAutoLock envlock(m_env_mutex);
783 ScopeProfiler sp(g_profiler, "Server: sending object messages");
786 // Value = data sent by object
787 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
789 // Get active object messages from environment
791 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
795 std::vector<ActiveObjectMessage>* message_list = NULL;
796 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
797 n = buffered_messages.find(aom.id);
798 if (n == buffered_messages.end()) {
799 message_list = new std::vector<ActiveObjectMessage>;
800 buffered_messages[aom.id] = message_list;
803 message_list = n->second;
805 message_list->push_back(aom);
809 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
810 // Route data to every client
811 for (std::map<u16, RemoteClient*>::iterator
813 i != clients.end(); ++i) {
814 RemoteClient *client = i->second;
815 std::string reliable_data;
816 std::string unreliable_data;
817 // Go through all objects in message buffer
818 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
819 j = buffered_messages.begin();
820 j != buffered_messages.end(); ++j) {
821 // If object is not known by client, skip it
823 if (client->m_known_objects.find(id) == client->m_known_objects.end())
826 // Get message list of object
827 std::vector<ActiveObjectMessage>* list = j->second;
828 // Go through every message
829 for (std::vector<ActiveObjectMessage>::iterator
830 k = list->begin(); k != list->end(); ++k) {
831 // Compose the full new data with header
832 ActiveObjectMessage aom = *k;
833 std::string new_data;
836 writeU16((u8*)&buf[0], aom.id);
837 new_data.append(buf, 2);
839 new_data += serializeString(aom.datastring);
840 // Add data to buffer
842 reliable_data += new_data;
844 unreliable_data += new_data;
848 reliable_data and unreliable_data are now ready.
851 if(reliable_data.size() > 0) {
852 SendActiveObjectMessages(client->peer_id, reliable_data);
855 if(unreliable_data.size() > 0) {
856 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
861 // Clear buffered_messages
862 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
863 i = buffered_messages.begin();
864 i != buffered_messages.end(); ++i) {
870 Send queued-for-sending map edit events.
873 // We will be accessing the environment
874 JMutexAutoLock lock(m_env_mutex);
876 // Don't send too many at a time
879 // Single change sending is disabled if queue size is not small
880 bool disable_single_change_sending = false;
881 if(m_unsent_map_edit_queue.size() >= 4)
882 disable_single_change_sending = true;
884 int event_count = m_unsent_map_edit_queue.size();
886 // We'll log the amount of each
889 while(m_unsent_map_edit_queue.size() != 0)
891 MapEditEvent* event = m_unsent_map_edit_queue.front();
892 m_unsent_map_edit_queue.pop();
894 // Players far away from the change are stored here.
895 // Instead of sending the changes, MapBlocks are set not sent
897 std::vector<u16> far_players;
899 switch (event->type) {
902 prof.add("MEET_ADDNODE", 1);
903 sendAddNode(event->p, event->n, event->already_known_by_peer,
904 &far_players, disable_single_change_sending ? 5 : 30,
905 event->type == MEET_ADDNODE);
907 case MEET_REMOVENODE:
908 prof.add("MEET_REMOVENODE", 1);
909 sendRemoveNode(event->p, event->already_known_by_peer,
910 &far_players, disable_single_change_sending ? 5 : 30);
912 case MEET_BLOCK_NODE_METADATA_CHANGED:
913 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
914 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
915 setBlockNotSent(event->p);
918 infostream << "Server: MEET_OTHER" << std::endl;
919 prof.add("MEET_OTHER", 1);
920 for(std::set<v3s16>::iterator
921 i = event->modified_blocks.begin();
922 i != event->modified_blocks.end(); ++i) {
927 prof.add("unknown", 1);
928 infostream << "WARNING: Server: Unknown MapEditEvent "
929 << ((u32)event->type) << std::endl;
934 Set blocks not sent to far players
936 if(!far_players.empty()) {
937 // Convert list format to that wanted by SetBlocksNotSent
938 std::map<v3s16, MapBlock*> modified_blocks2;
939 for(std::set<v3s16>::iterator
940 i = event->modified_blocks.begin();
941 i != event->modified_blocks.end(); ++i) {
942 modified_blocks2[*i] =
943 m_env->getMap().getBlockNoCreateNoEx(*i);
946 // Set blocks not sent
947 for(std::vector<u16>::iterator
948 i = far_players.begin();
949 i != far_players.end(); ++i) {
950 if(RemoteClient *client = getClient(*i))
951 client->SetBlocksNotSent(modified_blocks2);
957 /*// Don't send too many at a time
959 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
963 if(event_count >= 5){
964 infostream<<"Server: MapEditEvents:"<<std::endl;
965 prof.print(infostream);
966 } else if(event_count != 0){
967 verbosestream<<"Server: MapEditEvents:"<<std::endl;
968 prof.print(verbosestream);
974 Trigger emergethread (it somehow gets to a non-triggered but
975 bysy state sometimes)
978 float &counter = m_emergethread_trigger_timer;
984 m_emerge->startThreads();
988 // Save map, players and auth stuff
990 float &counter = m_savemap_timer;
992 if(counter >= g_settings->getFloat("server_map_save_interval"))
995 JMutexAutoLock lock(m_env_mutex);
997 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1000 if (m_banmanager->isModified()) {
1001 m_banmanager->save();
1004 // Save changed parts of map
1005 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1008 m_env->saveLoadedPlayers();
1010 // Save environment metadata
1016 void Server::Receive()
1018 DSTACK(__FUNCTION_NAME);
1019 SharedBuffer<u8> data;
1023 datasize = m_con.Receive(peer_id,data);
1024 ProcessData(*data, datasize, peer_id);
1026 catch(con::InvalidIncomingDataException &e) {
1027 infostream<<"Server::Receive(): "
1028 "InvalidIncomingDataException: what()="
1029 <<e.what()<<std::endl;
1031 catch(SerializationError &e) {
1032 infostream<<"Server::Receive(): "
1033 "SerializationError: what()="
1034 <<e.what()<<std::endl;
1036 catch(ClientStateError &e) {
1037 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1038 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1039 L"Try reconnecting or updating your client");
1041 catch(con::PeerNotFoundException &e) {
1046 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1048 std::string playername = "";
1049 PlayerSAO *playersao = NULL;
1052 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1053 if (client != NULL) {
1054 playername = client->getName();
1055 playersao = emergePlayer(playername.c_str(), peer_id);
1057 } catch (std::exception &e) {
1063 RemotePlayer *player =
1064 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1066 // If failed, cancel
1067 if((playersao == NULL) || (player == NULL)) {
1068 if(player && player->peer_id != 0) {
1069 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1070 <<" (player allocated to an another client)"<<std::endl;
1071 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1072 L"name. If your client closed unexpectedly, try again in "
1075 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1077 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1083 Send complete position information
1085 SendMovePlayer(peer_id);
1088 SendPlayerPrivileges(peer_id);
1090 // Send inventory formspec
1091 SendPlayerInventoryFormspec(peer_id);
1094 SendInventory(playersao);
1097 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1100 SendPlayerBreath(peer_id);
1102 // Show death screen if necessary
1103 if(player->isDead())
1104 SendDeathscreen(peer_id, false, v3f(0,0,0));
1106 // Note things in chat if not in simple singleplayer mode
1107 if(!m_simple_singleplayer_mode) {
1108 // Send information about server to player in chat
1109 SendChatMessage(peer_id, getStatusString());
1111 // Send information about joining in chat
1113 std::wstring name = L"unknown";
1114 Player *player = m_env->getPlayer(peer_id);
1116 name = narrow_to_wide(player->getName());
1118 std::wstring message;
1121 message += L" joined the game.";
1122 SendChatMessage(PEER_ID_INEXISTENT,message);
1125 Address addr = getPeerAddress(player->peer_id);
1126 std::string ip_str = addr.serializeString();
1127 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1132 std::vector<std::string> names = m_clients.getPlayerNames();
1134 actionstream<<player->getName() <<" joins game. List of players: ";
1136 for (std::vector<std::string>::iterator i = names.begin();
1137 i != names.end(); i++) {
1138 actionstream << *i << " ";
1141 actionstream << player->getName() <<std::endl;
1146 inline void Server::handleCommand(NetworkPacket* pkt)
1148 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1149 (this->*opHandle.handler)(pkt);
1152 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1154 DSTACK(__FUNCTION_NAME);
1155 // Environment is locked first.
1156 JMutexAutoLock envlock(m_env_mutex);
1158 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1161 Address address = getPeerAddress(peer_id);
1162 std::string addr_s = address.serializeString();
1164 if(m_banmanager->isIpBanned(addr_s)) {
1165 std::string ban_name = m_banmanager->getBanName(addr_s);
1166 infostream << "Server: A banned client tried to connect from "
1167 << addr_s << "; banned name was "
1168 << ban_name << std::endl;
1169 // This actually doesn't seem to transfer to the client
1170 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1171 + narrow_to_wide(ban_name));
1175 catch(con::PeerNotFoundException &e) {
1177 * no peer for this packet found
1178 * most common reason is peer timeout, e.g. peer didn't
1179 * respond for some time, your server was overloaded or
1182 infostream << "Server::ProcessData(): Cancelling: peer "
1183 << peer_id << " not found" << std::endl;
1191 NetworkPacket pkt(data, datasize, peer_id);
1193 ToServerCommand command = (ToServerCommand) pkt.getCommand();
1195 // Command must be handled into ToServerCommandHandler
1196 if (command >= TOSERVER_NUM_MSG_TYPES) {
1197 infostream << "Server: Ignoring unknown command "
1198 << command << std::endl;
1201 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1202 handleCommand(&pkt);
1206 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1208 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1209 errorstream << "Server::ProcessData(): Cancelling: Peer"
1210 " serialization format invalid or not initialized."
1211 " Skipping incoming command=" << command << std::endl;
1215 /* Handle commands related to client startup */
1216 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1217 handleCommand(&pkt);
1221 if (m_clients.getClientState(peer_id) < CS_Active) {
1222 if (command == TOSERVER_PLAYERPOS) return;
1224 errorstream << "Got packet command: " << command << " for peer id "
1225 << peer_id << " but client isn't active yet. Dropping packet "
1230 handleCommand(&pkt);
1232 catch(SendFailedException &e) {
1233 errorstream << "Server::ProcessData(): SendFailedException: "
1234 << "what=" << e.what()
1239 void Server::setTimeOfDay(u32 time)
1241 m_env->setTimeOfDay(time);
1242 m_time_of_day_send_timer = 0;
1245 void Server::onMapEditEvent(MapEditEvent *event)
1247 if(m_ignore_map_edit_events)
1249 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1251 MapEditEvent *e = event->clone();
1252 m_unsent_map_edit_queue.push(e);
1255 Inventory* Server::getInventory(const InventoryLocation &loc)
1258 case InventoryLocation::UNDEFINED:
1259 case InventoryLocation::CURRENT_PLAYER:
1261 case InventoryLocation::PLAYER:
1263 Player *player = m_env->getPlayer(loc.name.c_str());
1266 PlayerSAO *playersao = player->getPlayerSAO();
1269 return playersao->getInventory();
1272 case InventoryLocation::NODEMETA:
1274 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1277 return meta->getInventory();
1280 case InventoryLocation::DETACHED:
1282 if(m_detached_inventories.count(loc.name) == 0)
1284 return m_detached_inventories[loc.name];
1288 sanity_check(false); // abort
1293 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1296 case InventoryLocation::UNDEFINED:
1298 case InventoryLocation::PLAYER:
1303 Player *player = m_env->getPlayer(loc.name.c_str());
1306 PlayerSAO *playersao = player->getPlayerSAO();
1310 SendInventory(playersao);
1313 case InventoryLocation::NODEMETA:
1315 v3s16 blockpos = getNodeBlockPos(loc.p);
1317 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1319 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1321 setBlockNotSent(blockpos);
1324 case InventoryLocation::DETACHED:
1326 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1330 sanity_check(false); // abort
1335 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1337 std::vector<u16> clients = m_clients.getClientIDs();
1339 // Set the modified blocks unsent for all the clients
1340 for (std::vector<u16>::iterator i = clients.begin();
1341 i != clients.end(); ++i) {
1342 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1343 client->SetBlocksNotSent(block);
1348 void Server::peerAdded(con::Peer *peer)
1350 DSTACK(__FUNCTION_NAME);
1351 verbosestream<<"Server::peerAdded(): peer->id="
1352 <<peer->id<<std::endl;
1355 c.type = con::PEER_ADDED;
1356 c.peer_id = peer->id;
1358 m_peer_change_queue.push(c);
1361 void Server::deletingPeer(con::Peer *peer, bool timeout)
1363 DSTACK(__FUNCTION_NAME);
1364 verbosestream<<"Server::deletingPeer(): peer->id="
1365 <<peer->id<<", timeout="<<timeout<<std::endl;
1367 m_clients.event(peer->id, CSE_Disconnect);
1369 c.type = con::PEER_REMOVED;
1370 c.peer_id = peer->id;
1371 c.timeout = timeout;
1372 m_peer_change_queue.push(c);
1375 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1377 *retval = m_con.getPeerStat(peer_id,type);
1378 if (*retval == -1) return false;
1382 bool Server::getClientInfo(
1391 std::string* vers_string
1394 *state = m_clients.getClientState(peer_id);
1396 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1398 if (client == NULL) {
1403 *uptime = client->uptime();
1404 *ser_vers = client->serialization_version;
1405 *prot_vers = client->net_proto_version;
1407 *major = client->getMajor();
1408 *minor = client->getMinor();
1409 *patch = client->getPatch();
1410 *vers_string = client->getPatch();
1417 void Server::handlePeerChanges()
1419 while(m_peer_change_queue.size() > 0)
1421 con::PeerChange c = m_peer_change_queue.front();
1422 m_peer_change_queue.pop();
1424 verbosestream<<"Server: Handling peer change: "
1425 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1430 case con::PEER_ADDED:
1431 m_clients.CreateClient(c.peer_id);
1434 case con::PEER_REMOVED:
1435 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1439 FATAL_ERROR("Invalid peer change event received!");
1445 void Server::Send(NetworkPacket* pkt)
1447 m_clients.send(pkt->getPeerId(),
1448 clientCommandFactoryTable[pkt->getCommand()].channel,
1450 clientCommandFactoryTable[pkt->getCommand()].reliable);
1453 void Server::SendMovement(u16 peer_id)
1455 DSTACK(__FUNCTION_NAME);
1456 std::ostringstream os(std::ios_base::binary);
1458 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1460 pkt << g_settings->getFloat("movement_acceleration_default");
1461 pkt << g_settings->getFloat("movement_acceleration_air");
1462 pkt << g_settings->getFloat("movement_acceleration_fast");
1463 pkt << g_settings->getFloat("movement_speed_walk");
1464 pkt << g_settings->getFloat("movement_speed_crouch");
1465 pkt << g_settings->getFloat("movement_speed_fast");
1466 pkt << g_settings->getFloat("movement_speed_climb");
1467 pkt << g_settings->getFloat("movement_speed_jump");
1468 pkt << g_settings->getFloat("movement_liquid_fluidity");
1469 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1470 pkt << g_settings->getFloat("movement_liquid_sink");
1471 pkt << g_settings->getFloat("movement_gravity");
1476 void Server::SendHP(u16 peer_id, u8 hp)
1478 DSTACK(__FUNCTION_NAME);
1480 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1485 void Server::SendBreath(u16 peer_id, u16 breath)
1487 DSTACK(__FUNCTION_NAME);
1489 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1490 pkt << (u16) breath;
1494 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
1496 DSTACK(__FUNCTION_NAME);
1498 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1501 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1502 pkt << custom_reason;
1507 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1509 DSTACK(__FUNCTION_NAME);
1511 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1516 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1517 v3f camera_point_target)
1519 DSTACK(__FUNCTION_NAME);
1521 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1522 pkt << set_camera_point_target << camera_point_target;
1526 void Server::SendItemDef(u16 peer_id,
1527 IItemDefManager *itemdef, u16 protocol_version)
1529 DSTACK(__FUNCTION_NAME);
1531 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1535 u32 length of the next item
1536 zlib-compressed serialized ItemDefManager
1538 std::ostringstream tmp_os(std::ios::binary);
1539 itemdef->serialize(tmp_os, protocol_version);
1540 std::ostringstream tmp_os2(std::ios::binary);
1541 compressZlib(tmp_os.str(), tmp_os2);
1542 pkt.putLongString(tmp_os2.str());
1545 verbosestream << "Server: Sending item definitions to id(" << peer_id
1546 << "): size=" << pkt.getSize() << std::endl;
1551 void Server::SendNodeDef(u16 peer_id,
1552 INodeDefManager *nodedef, u16 protocol_version)
1554 DSTACK(__FUNCTION_NAME);
1556 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1560 u32 length of the next item
1561 zlib-compressed serialized NodeDefManager
1563 std::ostringstream tmp_os(std::ios::binary);
1564 nodedef->serialize(tmp_os, protocol_version);
1565 std::ostringstream tmp_os2(std::ios::binary);
1566 compressZlib(tmp_os.str(), tmp_os2);
1568 pkt.putLongString(tmp_os2.str());
1571 verbosestream << "Server: Sending node definitions to id(" << peer_id
1572 << "): size=" << pkt.getSize() << std::endl;
1578 Non-static send methods
1581 void Server::SendInventory(PlayerSAO* playerSAO)
1583 DSTACK(__FUNCTION_NAME);
1585 UpdateCrafting(playerSAO->getPlayer());
1591 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1593 std::ostringstream os;
1594 playerSAO->getInventory()->serialize(os);
1596 std::string s = os.str();
1598 pkt.putRawString(s.c_str(), s.size());
1602 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1604 DSTACK(__FUNCTION_NAME);
1606 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1609 if (peer_id != PEER_ID_INEXISTENT) {
1613 m_clients.sendToAll(0, &pkt, true);
1617 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1618 const std::string &formname)
1620 DSTACK(__FUNCTION_NAME);
1622 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1624 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1630 // Spawns a particle on peer with peer_id
1631 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1632 float expirationtime, float size, bool collisiondetection,
1633 bool vertical, std::string texture)
1635 DSTACK(__FUNCTION_NAME);
1637 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1639 pkt << pos << velocity << acceleration << expirationtime
1640 << size << collisiondetection;
1641 pkt.putLongString(texture);
1644 if (peer_id != PEER_ID_INEXISTENT) {
1648 m_clients.sendToAll(0, &pkt, true);
1652 // Adds a ParticleSpawner on peer with peer_id
1653 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1654 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1655 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1657 DSTACK(__FUNCTION_NAME);
1659 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1661 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1662 << minacc << maxacc << minexptime << maxexptime << minsize
1663 << maxsize << collisiondetection;
1665 pkt.putLongString(texture);
1667 pkt << id << vertical;
1669 if (peer_id != PEER_ID_INEXISTENT) {
1673 m_clients.sendToAll(0, &pkt, true);
1677 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1679 DSTACK(__FUNCTION_NAME);
1681 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1683 // Ugly error in this packet
1686 if (peer_id != PEER_ID_INEXISTENT) {
1690 m_clients.sendToAll(0, &pkt, true);
1695 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1697 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1699 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1700 << form->text << form->number << form->item << form->dir
1701 << form->align << form->offset << form->world_pos << form->size;
1706 void Server::SendHUDRemove(u16 peer_id, u32 id)
1708 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1713 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1715 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1716 pkt << id << (u8) stat;
1720 case HUD_STAT_SCALE:
1721 case HUD_STAT_ALIGN:
1722 case HUD_STAT_OFFSET:
1723 pkt << *(v2f *) value;
1727 pkt << *(std::string *) value;
1729 case HUD_STAT_WORLD_POS:
1730 pkt << *(v3f *) value;
1733 pkt << *(v2s32 *) value;
1735 case HUD_STAT_NUMBER:
1739 pkt << *(u32 *) value;
1746 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1748 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1750 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1752 pkt << flags << mask;
1757 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1759 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1760 pkt << param << value;
1764 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1765 const std::string &type, const std::vector<std::string> ¶ms)
1767 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1768 pkt << bgcolor << type << (u16) params.size();
1770 for(size_t i=0; i<params.size(); i++)
1776 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1779 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1782 pkt << do_override << (u16) (ratio * 65535);
1787 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1789 DSTACK(__FUNCTION_NAME);
1791 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1792 pkt << time << time_speed;
1794 if (peer_id == PEER_ID_INEXISTENT) {
1795 m_clients.sendToAll(0, &pkt, true);
1802 void Server::SendPlayerHP(u16 peer_id)
1804 DSTACK(__FUNCTION_NAME);
1805 PlayerSAO *playersao = getPlayerSAO(peer_id);
1807 SendHP(peer_id, playersao->getHP());
1808 m_script->player_event(playersao,"health_changed");
1810 // Send to other clients
1811 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1812 ActiveObjectMessage aom(playersao->getId(), true, str);
1813 playersao->m_messages_out.push(aom);
1816 void Server::SendPlayerBreath(u16 peer_id)
1818 DSTACK(__FUNCTION_NAME);
1819 PlayerSAO *playersao = getPlayerSAO(peer_id);
1822 m_script->player_event(playersao, "breath_changed");
1823 SendBreath(peer_id, playersao->getBreath());
1826 void Server::SendMovePlayer(u16 peer_id)
1828 DSTACK(__FUNCTION_NAME);
1829 Player *player = m_env->getPlayer(peer_id);
1832 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1833 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1836 v3f pos = player->getPosition();
1837 f32 pitch = player->getPitch();
1838 f32 yaw = player->getYaw();
1839 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1840 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1841 << " pitch=" << pitch
1849 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1851 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1854 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1855 << animation_frames[3] << animation_speed;
1860 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1862 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1863 pkt << first << third;
1866 void Server::SendPlayerPrivileges(u16 peer_id)
1868 Player *player = m_env->getPlayer(peer_id);
1870 if(player->peer_id == PEER_ID_INEXISTENT)
1873 std::set<std::string> privs;
1874 m_script->getAuth(player->getName(), NULL, &privs);
1876 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1877 pkt << (u16) privs.size();
1879 for(std::set<std::string>::const_iterator i = privs.begin();
1880 i != privs.end(); i++) {
1887 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1889 Player *player = m_env->getPlayer(peer_id);
1891 if(player->peer_id == PEER_ID_INEXISTENT)
1894 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1895 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1899 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1901 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, peer_id);
1902 pkt.putRawString(datas.c_str(), datas.size());
1904 return pkt.getSize();
1907 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1909 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1912 pkt.putRawString(datas.c_str(), datas.size());
1914 m_clients.send(pkt.getPeerId(),
1915 clientCommandFactoryTable[pkt.getCommand()].channel,
1920 s32 Server::playSound(const SimpleSoundSpec &spec,
1921 const ServerSoundParams ¶ms)
1923 // Find out initial position of sound
1924 bool pos_exists = false;
1925 v3f pos = params.getPos(m_env, &pos_exists);
1926 // If position is not found while it should be, cancel sound
1927 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1930 // Filter destination clients
1931 std::vector<u16> dst_clients;
1932 if(params.to_player != "")
1934 Player *player = m_env->getPlayer(params.to_player.c_str());
1936 infostream<<"Server::playSound: Player \""<<params.to_player
1937 <<"\" not found"<<std::endl;
1940 if(player->peer_id == PEER_ID_INEXISTENT){
1941 infostream<<"Server::playSound: Player \""<<params.to_player
1942 <<"\" not connected"<<std::endl;
1945 dst_clients.push_back(player->peer_id);
1948 std::vector<u16> clients = m_clients.getClientIDs();
1950 for(std::vector<u16>::iterator
1951 i = clients.begin(); i != clients.end(); ++i) {
1952 Player *player = m_env->getPlayer(*i);
1957 if(player->getPosition().getDistanceFrom(pos) >
1958 params.max_hear_distance)
1961 dst_clients.push_back(*i);
1965 if(dst_clients.empty())
1969 s32 id = m_next_sound_id++;
1970 // The sound will exist as a reference in m_playing_sounds
1971 m_playing_sounds[id] = ServerPlayingSound();
1972 ServerPlayingSound &psound = m_playing_sounds[id];
1973 psound.params = params;
1975 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1976 pkt << id << spec.name << (float) (spec.gain * params.gain)
1977 << (u8) params.type << pos << params.object << params.loop;
1979 for(std::vector<u16>::iterator i = dst_clients.begin();
1980 i != dst_clients.end(); i++) {
1981 psound.clients.insert(*i);
1982 m_clients.send(*i, 0, &pkt, true);
1986 void Server::stopSound(s32 handle)
1988 // Get sound reference
1989 std::map<s32, ServerPlayingSound>::iterator i =
1990 m_playing_sounds.find(handle);
1991 if(i == m_playing_sounds.end())
1993 ServerPlayingSound &psound = i->second;
1995 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
1998 for(std::set<u16>::iterator i = psound.clients.begin();
1999 i != psound.clients.end(); i++) {
2001 m_clients.send(*i, 0, &pkt, true);
2003 // Remove sound reference
2004 m_playing_sounds.erase(i);
2007 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2008 std::vector<u16> *far_players, float far_d_nodes)
2010 float maxd = far_d_nodes*BS;
2011 v3f p_f = intToFloat(p, BS);
2013 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2016 std::vector<u16> clients = m_clients.getClientIDs();
2017 for(std::vector<u16>::iterator i = clients.begin();
2018 i != clients.end(); ++i) {
2021 if(Player *player = m_env->getPlayer(*i)) {
2022 // If player is far away, only set modified blocks not sent
2023 v3f player_pos = player->getPosition();
2024 if(player_pos.getDistanceFrom(p_f) > maxd) {
2025 far_players->push_back(*i);
2032 m_clients.send(*i, 0, &pkt, true);
2036 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2037 std::vector<u16> *far_players, float far_d_nodes,
2038 bool remove_metadata)
2040 float maxd = far_d_nodes*BS;
2041 v3f p_f = intToFloat(p, BS);
2043 std::vector<u16> clients = m_clients.getClientIDs();
2044 for(std::vector<u16>::iterator i = clients.begin();
2045 i != clients.end(); ++i) {
2049 if(Player *player = m_env->getPlayer(*i)) {
2050 // If player is far away, only set modified blocks not sent
2051 v3f player_pos = player->getPosition();
2052 if(player_pos.getDistanceFrom(p_f) > maxd) {
2053 far_players->push_back(*i);
2059 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2061 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2063 pkt << p << n.param0 << n.param1 << n.param2
2064 << (u8) (remove_metadata ? 0 : 1);
2066 if (!remove_metadata) {
2067 if (client->net_proto_version <= 21) {
2068 // Old clients always clear metadata; fix it
2069 // by sending the full block again.
2070 client->SetBlockNotSent(p);
2077 if (pkt.getSize() > 0)
2078 m_clients.send(*i, 0, &pkt, true);
2082 void Server::setBlockNotSent(v3s16 p)
2084 std::vector<u16> clients = m_clients.getClientIDs();
2086 for(std::vector<u16>::iterator i = clients.begin();
2087 i != clients.end(); ++i) {
2088 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2089 client->SetBlockNotSent(p);
2094 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2096 DSTACK(__FUNCTION_NAME);
2098 v3s16 p = block->getPos();
2101 Create a packet with the block in the right format
2104 std::ostringstream os(std::ios_base::binary);
2105 block->serialize(os, ver, false);
2106 block->serializeNetworkSpecific(os, net_proto_version);
2107 std::string s = os.str();
2109 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2112 pkt.putRawString(s.c_str(), s.size());
2116 void Server::SendBlocks(float dtime)
2118 DSTACK(__FUNCTION_NAME);
2120 JMutexAutoLock envlock(m_env_mutex);
2121 //TODO check if one big lock could be faster then multiple small ones
2123 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2125 std::vector<PrioritySortedBlockTransfer> queue;
2127 s32 total_sending = 0;
2130 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2132 std::vector<u16> clients = m_clients.getClientIDs();
2135 for(std::vector<u16>::iterator i = clients.begin();
2136 i != clients.end(); ++i) {
2137 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2142 total_sending += client->SendingCount();
2143 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2149 // Lowest priority number comes first.
2150 // Lowest is most important.
2151 std::sort(queue.begin(), queue.end());
2154 for(u32 i=0; i<queue.size(); i++)
2156 //TODO: Calculate limit dynamically
2157 if(total_sending >= g_settings->getS32
2158 ("max_simultaneous_block_sends_server_total"))
2161 PrioritySortedBlockTransfer q = queue[i];
2163 MapBlock *block = NULL;
2166 block = m_env->getMap().getBlockNoCreate(q.pos);
2168 catch(InvalidPositionException &e)
2173 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2178 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2180 client->SentBlock(q.pos);
2186 void Server::fillMediaCache()
2188 DSTACK(__FUNCTION_NAME);
2190 infostream<<"Server: Calculating media file checksums"<<std::endl;
2192 // Collect all media file paths
2193 std::vector<std::string> paths;
2194 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2195 i != m_mods.end(); i++) {
2196 const ModSpec &mod = *i;
2197 paths.push_back(mod.path + DIR_DELIM + "textures");
2198 paths.push_back(mod.path + DIR_DELIM + "sounds");
2199 paths.push_back(mod.path + DIR_DELIM + "media");
2200 paths.push_back(mod.path + DIR_DELIM + "models");
2202 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2204 // Collect media file information from paths into cache
2205 for(std::vector<std::string>::iterator i = paths.begin();
2206 i != paths.end(); i++) {
2207 std::string mediapath = *i;
2208 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2209 for (u32 j = 0; j < dirlist.size(); j++) {
2210 if (dirlist[j].dir) // Ignode dirs
2212 std::string filename = dirlist[j].name;
2213 // If name contains illegal characters, ignore the file
2214 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2215 infostream<<"Server: ignoring illegal file name: \""
2216 << filename << "\"" << std::endl;
2219 // If name is not in a supported format, ignore it
2220 const char *supported_ext[] = {
2221 ".png", ".jpg", ".bmp", ".tga",
2222 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2224 ".x", ".b3d", ".md2", ".obj",
2227 if (removeStringEnd(filename, supported_ext) == ""){
2228 infostream << "Server: ignoring unsupported file extension: \""
2229 << filename << "\"" << std::endl;
2232 // Ok, attempt to load the file and add to cache
2233 std::string filepath = mediapath + DIR_DELIM + filename;
2235 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2237 errorstream << "Server::fillMediaCache(): Could not open \""
2238 << filename << "\" for reading" << std::endl;
2241 std::ostringstream tmp_os(std::ios_base::binary);
2245 fis.read(buf, 1024);
2246 std::streamsize len = fis.gcount();
2247 tmp_os.write(buf, len);
2256 errorstream<<"Server::fillMediaCache(): Failed to read \""
2257 << filename << "\"" << std::endl;
2260 if(tmp_os.str().length() == 0) {
2261 errorstream << "Server::fillMediaCache(): Empty file \""
2262 << filepath << "\"" << std::endl;
2267 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2269 unsigned char *digest = sha1.getDigest();
2270 std::string sha1_base64 = base64_encode(digest, 20);
2271 std::string sha1_hex = hex_encode((char*)digest, 20);
2275 m_media[filename] = MediaInfo(filepath, sha1_base64);
2276 verbosestream << "Server: " << sha1_hex << " is " << filename
2282 struct SendableMediaAnnouncement
2285 std::string sha1_digest;
2287 SendableMediaAnnouncement(const std::string &name_="",
2288 const std::string &sha1_digest_=""):
2290 sha1_digest(sha1_digest_)
2294 void Server::sendMediaAnnouncement(u16 peer_id)
2296 DSTACK(__FUNCTION_NAME);
2298 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2301 std::vector<SendableMediaAnnouncement> file_announcements;
2303 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2304 i != m_media.end(); i++){
2306 file_announcements.push_back(
2307 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2311 std::ostringstream os(std::ios_base::binary);
2313 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2314 pkt << (u16) file_announcements.size();
2316 for (std::vector<SendableMediaAnnouncement>::iterator
2317 j = file_announcements.begin();
2318 j != file_announcements.end(); ++j) {
2319 pkt << j->name << j->sha1_digest;
2322 pkt << g_settings->get("remote_media");
2326 struct SendableMedia
2332 SendableMedia(const std::string &name_="", const std::string &path_="",
2333 const std::string &data_=""):
2340 void Server::sendRequestedMedia(u16 peer_id,
2341 const std::vector<std::string> &tosend)
2343 DSTACK(__FUNCTION_NAME);
2345 verbosestream<<"Server::sendRequestedMedia(): "
2346 <<"Sending files to client"<<std::endl;
2350 // Put 5kB in one bunch (this is not accurate)
2351 u32 bytes_per_bunch = 5000;
2353 std::vector< std::vector<SendableMedia> > file_bunches;
2354 file_bunches.push_back(std::vector<SendableMedia>());
2356 u32 file_size_bunch_total = 0;
2358 for(std::vector<std::string>::const_iterator i = tosend.begin();
2359 i != tosend.end(); ++i) {
2360 const std::string &name = *i;
2362 if(m_media.find(name) == m_media.end()) {
2363 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2364 <<"unknown file \""<<(name)<<"\""<<std::endl;
2368 //TODO get path + name
2369 std::string tpath = m_media[name].path;
2372 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2373 if(fis.good() == false){
2374 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2375 <<tpath<<"\" for reading"<<std::endl;
2378 std::ostringstream tmp_os(std::ios_base::binary);
2382 fis.read(buf, 1024);
2383 std::streamsize len = fis.gcount();
2384 tmp_os.write(buf, len);
2385 file_size_bunch_total += len;
2394 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2395 <<name<<"\""<<std::endl;
2398 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2399 <<tname<<"\""<<std::endl;*/
2401 file_bunches[file_bunches.size()-1].push_back(
2402 SendableMedia(name, tpath, tmp_os.str()));
2404 // Start next bunch if got enough data
2405 if(file_size_bunch_total >= bytes_per_bunch) {
2406 file_bunches.push_back(std::vector<SendableMedia>());
2407 file_size_bunch_total = 0;
2412 /* Create and send packets */
2414 u16 num_bunches = file_bunches.size();
2415 for(u16 i = 0; i < num_bunches; i++) {
2418 u16 total number of texture bunches
2419 u16 index of this bunch
2420 u32 number of files in this bunch
2429 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2430 pkt << num_bunches << i << (u32) file_bunches[i].size();
2432 for(std::vector<SendableMedia>::iterator
2433 j = file_bunches[i].begin();
2434 j != file_bunches[i].end(); ++j) {
2436 pkt.putLongString(j->data);
2439 verbosestream << "Server::sendRequestedMedia(): bunch "
2440 << i << "/" << num_bunches
2441 << " files=" << file_bunches[i].size()
2442 << " size=" << pkt.getSize() << std::endl;
2447 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2449 if(m_detached_inventories.count(name) == 0) {
2450 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2453 Inventory *inv = m_detached_inventories[name];
2454 std::ostringstream os(std::ios_base::binary);
2456 os << serializeString(name);
2460 std::string s = os.str();
2462 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2463 pkt.putRawString(s.c_str(), s.size());
2465 if (peer_id != PEER_ID_INEXISTENT) {
2469 m_clients.sendToAll(0, &pkt, true);
2473 void Server::sendDetachedInventories(u16 peer_id)
2475 DSTACK(__FUNCTION_NAME);
2477 for(std::map<std::string, Inventory*>::iterator
2478 i = m_detached_inventories.begin();
2479 i != m_detached_inventories.end(); i++) {
2480 const std::string &name = i->first;
2481 //Inventory *inv = i->second;
2482 sendDetachedInventory(name, peer_id);
2490 void Server::DiePlayer(u16 peer_id)
2492 DSTACK(__FUNCTION_NAME);
2494 PlayerSAO *playersao = getPlayerSAO(peer_id);
2497 infostream << "Server::DiePlayer(): Player "
2498 << playersao->getPlayer()->getName()
2499 << " dies" << std::endl;
2501 playersao->setHP(0);
2503 // Trigger scripted stuff
2504 m_script->on_dieplayer(playersao);
2506 SendPlayerHP(peer_id);
2507 SendDeathscreen(peer_id, false, v3f(0,0,0));
2510 void Server::RespawnPlayer(u16 peer_id)
2512 DSTACK(__FUNCTION_NAME);
2514 PlayerSAO *playersao = getPlayerSAO(peer_id);
2517 infostream << "Server::RespawnPlayer(): Player "
2518 << playersao->getPlayer()->getName()
2519 << " respawns" << std::endl;
2521 playersao->setHP(PLAYER_MAX_HP);
2522 playersao->setBreath(PLAYER_MAX_BREATH);
2524 SendPlayerHP(peer_id);
2525 SendPlayerBreath(peer_id);
2527 bool repositioned = m_script->on_respawnplayer(playersao);
2529 v3f pos = findSpawnPos(m_env->getServerMap());
2530 // setPos will send the new position to client
2531 playersao->setPos(pos);
2535 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2537 DSTACK(__FUNCTION_NAME);
2539 SendAccessDenied(peer_id, reason, custom_reason);
2540 m_clients.event(peer_id, CSE_SetDenied);
2541 m_con.DisconnectPeer(peer_id);
2544 // 13/03/15: remove this function when protocol version 25 will become
2545 // the minimum version for MT users, maybe in 1 year
2546 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2548 DSTACK(__FUNCTION_NAME);
2550 SendAccessDenied_Legacy(peer_id, reason);
2551 m_clients.event(peer_id, CSE_SetDenied);
2552 m_con.DisconnectPeer(peer_id);
2555 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2557 DSTACK(__FUNCTION_NAME);
2558 std::wstring message;
2561 Clear references to playing sounds
2563 for(std::map<s32, ServerPlayingSound>::iterator
2564 i = m_playing_sounds.begin();
2565 i != m_playing_sounds.end();)
2567 ServerPlayingSound &psound = i->second;
2568 psound.clients.erase(peer_id);
2569 if(psound.clients.empty())
2570 m_playing_sounds.erase(i++);
2575 Player *player = m_env->getPlayer(peer_id);
2577 // Collect information about leaving in chat
2579 if(player != NULL && reason != CDR_DENY)
2581 std::wstring name = narrow_to_wide(player->getName());
2584 message += L" left the game.";
2585 if(reason == CDR_TIMEOUT)
2586 message += L" (timed out)";
2590 /* Run scripts and remove from environment */
2594 PlayerSAO *playersao = player->getPlayerSAO();
2597 m_script->on_leaveplayer(playersao);
2599 playersao->disconnected();
2607 if(player != NULL && reason != CDR_DENY) {
2608 std::ostringstream os(std::ios_base::binary);
2609 std::vector<u16> clients = m_clients.getClientIDs();
2611 for(std::vector<u16>::iterator i = clients.begin();
2612 i != clients.end(); ++i) {
2614 Player *player = m_env->getPlayer(*i);
2618 // Get name of player
2619 os << player->getName() << " ";
2622 actionstream << player->getName() << " "
2623 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2624 << " List of players: " << os.str() << std::endl;
2628 JMutexAutoLock env_lock(m_env_mutex);
2629 m_clients.DeleteClient(peer_id);
2633 // Send leave chat message to all remaining clients
2634 if(message.length() != 0)
2635 SendChatMessage(PEER_ID_INEXISTENT,message);
2638 void Server::UpdateCrafting(Player* player)
2640 DSTACK(__FUNCTION_NAME);
2642 // Get a preview for crafting
2644 InventoryLocation loc;
2645 loc.setPlayer(player->getName());
2646 getCraftingResult(&player->inventory, preview, false, this);
2647 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2649 // Put the new preview in
2650 InventoryList *plist = player->inventory.getList("craftpreview");
2651 sanity_check(plist);
2652 sanity_check(plist->getSize() >= 1);
2653 plist->changeItem(0, preview);
2656 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2658 RemoteClient *client = getClientNoEx(peer_id,state_min);
2660 throw ClientNotFoundException("Client not found");
2664 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2666 return m_clients.getClientNoEx(peer_id, state_min);
2669 std::string Server::getPlayerName(u16 peer_id)
2671 Player *player = m_env->getPlayer(peer_id);
2673 return "[id="+itos(peer_id)+"]";
2674 return player->getName();
2677 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2679 Player *player = m_env->getPlayer(peer_id);
2682 return player->getPlayerSAO();
2685 std::wstring Server::getStatusString()
2687 std::wostringstream os(std::ios_base::binary);
2690 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2692 os<<L", uptime="<<m_uptime.get();
2694 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2695 // Information about clients
2698 std::vector<u16> clients = m_clients.getClientIDs();
2699 for(std::vector<u16>::iterator i = clients.begin();
2700 i != clients.end(); ++i) {
2702 Player *player = m_env->getPlayer(*i);
2703 // Get name of player
2704 std::wstring name = L"unknown";
2706 name = narrow_to_wide(player->getName());
2707 // Add name to information string
2715 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2716 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2717 if(g_settings->get("motd") != "")
2718 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2722 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2724 std::set<std::string> privs;
2725 m_script->getAuth(name, NULL, &privs);
2729 bool Server::checkPriv(const std::string &name, const std::string &priv)
2731 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2732 return (privs.count(priv) != 0);
2735 void Server::reportPrivsModified(const std::string &name)
2738 std::vector<u16> clients = m_clients.getClientIDs();
2739 for(std::vector<u16>::iterator i = clients.begin();
2740 i != clients.end(); ++i) {
2741 Player *player = m_env->getPlayer(*i);
2742 reportPrivsModified(player->getName());
2745 Player *player = m_env->getPlayer(name.c_str());
2748 SendPlayerPrivileges(player->peer_id);
2749 PlayerSAO *sao = player->getPlayerSAO();
2752 sao->updatePrivileges(
2753 getPlayerEffectivePrivs(name),
2758 void Server::reportInventoryFormspecModified(const std::string &name)
2760 Player *player = m_env->getPlayer(name.c_str());
2763 SendPlayerInventoryFormspec(player->peer_id);
2766 void Server::setIpBanned(const std::string &ip, const std::string &name)
2768 m_banmanager->add(ip, name);
2771 void Server::unsetIpBanned(const std::string &ip_or_name)
2773 m_banmanager->remove(ip_or_name);
2776 std::string Server::getBanDescription(const std::string &ip_or_name)
2778 return m_banmanager->getBanDescription(ip_or_name);
2781 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2783 Player *player = m_env->getPlayer(name);
2787 if (player->peer_id == PEER_ID_INEXISTENT)
2790 SendChatMessage(player->peer_id, msg);
2793 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2795 Player *player = m_env->getPlayer(playername);
2799 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2803 SendShowFormspecMessage(player->peer_id, formspec, formname);
2807 u32 Server::hudAdd(Player *player, HudElement *form) {
2811 u32 id = player->addHud(form);
2813 SendHUDAdd(player->peer_id, id, form);
2818 bool Server::hudRemove(Player *player, u32 id) {
2822 HudElement* todel = player->removeHud(id);
2829 SendHUDRemove(player->peer_id, id);
2833 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2837 SendHUDChange(player->peer_id, id, stat, data);
2841 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2845 SendHUDSetFlags(player->peer_id, flags, mask);
2846 player->hud_flags = flags;
2848 PlayerSAO* playersao = player->getPlayerSAO();
2850 if (playersao == NULL)
2853 m_script->player_event(playersao, "hud_changed");
2857 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2860 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2863 std::ostringstream os(std::ios::binary);
2864 writeS32(os, hotbar_itemcount);
2865 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2869 void Server::hudSetHotbarImage(Player *player, std::string name) {
2873 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2876 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2880 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2883 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2888 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2892 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2897 SendEyeOffset(player->peer_id, first, third);
2901 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2902 const std::string &type, const std::vector<std::string> ¶ms)
2907 SendSetSky(player->peer_id, bgcolor, type, params);
2911 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2917 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2921 void Server::notifyPlayers(const std::wstring &msg)
2923 SendChatMessage(PEER_ID_INEXISTENT,msg);
2926 void Server::spawnParticle(const char *playername, v3f pos,
2927 v3f velocity, v3f acceleration,
2928 float expirationtime, float size, bool
2929 collisiondetection, bool vertical, std::string texture)
2931 Player *player = m_env->getPlayer(playername);
2934 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2935 expirationtime, size, collisiondetection, vertical, texture);
2938 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2939 float expirationtime, float size,
2940 bool collisiondetection, bool vertical, std::string texture)
2942 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2943 expirationtime, size, collisiondetection, vertical, texture);
2946 u32 Server::addParticleSpawner(const char *playername,
2947 u16 amount, float spawntime,
2948 v3f minpos, v3f maxpos,
2949 v3f minvel, v3f maxvel,
2950 v3f minacc, v3f maxacc,
2951 float minexptime, float maxexptime,
2952 float minsize, float maxsize,
2953 bool collisiondetection, bool vertical, std::string texture)
2955 Player *player = m_env->getPlayer(playername);
2960 for(;;) // look for unused particlespawner id
2963 if (std::find(m_particlespawner_ids.begin(),
2964 m_particlespawner_ids.end(), id)
2965 == m_particlespawner_ids.end())
2967 m_particlespawner_ids.push_back(id);
2972 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2973 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2974 minexptime, maxexptime, minsize, maxsize,
2975 collisiondetection, vertical, texture, id);
2980 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2981 v3f minpos, v3f maxpos,
2982 v3f minvel, v3f maxvel,
2983 v3f minacc, v3f maxacc,
2984 float minexptime, float maxexptime,
2985 float minsize, float maxsize,
2986 bool collisiondetection, bool vertical, std::string texture)
2989 for(;;) // look for unused particlespawner id
2992 if (std::find(m_particlespawner_ids.begin(),
2993 m_particlespawner_ids.end(), id)
2994 == m_particlespawner_ids.end())
2996 m_particlespawner_ids.push_back(id);
3001 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3002 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3003 minexptime, maxexptime, minsize, maxsize,
3004 collisiondetection, vertical, texture, id);
3009 void Server::deleteParticleSpawner(const char *playername, u32 id)
3011 Player *player = m_env->getPlayer(playername);
3015 m_particlespawner_ids.erase(
3016 std::remove(m_particlespawner_ids.begin(),
3017 m_particlespawner_ids.end(), id),
3018 m_particlespawner_ids.end());
3019 SendDeleteParticleSpawner(player->peer_id, id);
3022 void Server::deleteParticleSpawnerAll(u32 id)
3024 m_particlespawner_ids.erase(
3025 std::remove(m_particlespawner_ids.begin(),
3026 m_particlespawner_ids.end(), id),
3027 m_particlespawner_ids.end());
3028 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3031 Inventory* Server::createDetachedInventory(const std::string &name)
3033 if(m_detached_inventories.count(name) > 0){
3034 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3035 delete m_detached_inventories[name];
3037 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3039 Inventory *inv = new Inventory(m_itemdef);
3041 m_detached_inventories[name] = inv;
3042 //TODO find a better way to do this
3043 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3050 BoolScopeSet(bool *dst, bool val):
3053 m_orig_state = *m_dst;
3058 *m_dst = m_orig_state;
3065 // actions: time-reversed list
3066 // Return value: success/failure
3067 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3068 std::list<std::string> *log)
3070 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3071 ServerMap *map = (ServerMap*)(&m_env->getMap());
3073 // Fail if no actions to handle
3074 if(actions.empty()){
3075 log->push_back("Nothing to do.");
3082 for(std::list<RollbackAction>::const_iterator
3083 i = actions.begin();
3084 i != actions.end(); i++)
3086 const RollbackAction &action = *i;
3088 bool success = action.applyRevert(map, this, this);
3091 std::ostringstream os;
3092 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3093 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3095 log->push_back(os.str());
3097 std::ostringstream os;
3098 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3099 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3101 log->push_back(os.str());
3105 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3106 <<" failed"<<std::endl;
3108 // Call it done if less than half failed
3109 return num_failed <= num_tried/2;
3112 // IGameDef interface
3114 IItemDefManager* Server::getItemDefManager()
3118 INodeDefManager* Server::getNodeDefManager()
3122 ICraftDefManager* Server::getCraftDefManager()
3126 ITextureSource* Server::getTextureSource()
3130 IShaderSource* Server::getShaderSource()
3134 scene::ISceneManager* Server::getSceneManager()
3139 u16 Server::allocateUnknownNodeId(const std::string &name)
3141 return m_nodedef->allocateDummy(name);
3143 ISoundManager* Server::getSoundManager()
3145 return &dummySoundManager;
3147 MtEventManager* Server::getEventManager()
3152 IWritableItemDefManager* Server::getWritableItemDefManager()
3156 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3160 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3165 const ModSpec* Server::getModSpec(const std::string &modname)
3167 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3168 i != m_mods.end(); i++){
3169 const ModSpec &mod = *i;
3170 if(mod.name == modname)
3175 void Server::getModNames(std::vector<std::string> &modlist)
3177 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3178 modlist.push_back(i->name);
3181 std::string Server::getBuiltinLuaPath()
3183 return porting::path_share + DIR_DELIM + "builtin";
3186 v3f findSpawnPos(ServerMap &map)
3188 //return v3f(50,50,50)*BS;
3193 nodepos = v2s16(0,0);
3198 s16 water_level = map.getWaterLevel();
3200 // Try to find a good place a few times
3201 for(s32 i=0; i<1000; 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);
3217 bool is_good = false;
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){
3233 // Found a good place
3234 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3240 return intToFloat(nodepos, BS);
3243 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3245 bool newplayer = false;
3248 Try to get an existing player
3250 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3252 // If player is already connected, cancel
3253 if(player != NULL && player->peer_id != 0)
3255 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3260 If player with the wanted peer_id already exists, cancel.
3262 if(m_env->getPlayer(peer_id) != NULL)
3264 infostream<<"emergePlayer(): Player with wrong name but same"
3265 " peer_id already exists"<<std::endl;
3269 // Load player if it isn't already loaded
3271 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3274 // Create player if it doesn't exist
3277 player = new RemotePlayer(this, name);
3278 // Set player position
3279 infostream<<"Server: Finding spawn place for player \""
3280 <<name<<"\""<<std::endl;
3281 v3f pos = findSpawnPos(m_env->getServerMap());
3282 player->setPosition(pos);
3284 // Make sure the player is saved
3285 player->setModified(true);
3287 // Add player to environment
3288 m_env->addPlayer(player);
3291 // Create a new player active object
3292 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3293 getPlayerEffectivePrivs(player->getName()),
3296 /* Clean up old HUD elements from previous sessions */
3299 /* Add object to environment */
3300 m_env->addActiveObject(playersao);
3304 m_script->on_newplayer(playersao);
3310 void dedicated_server_loop(Server &server, bool &kill)
3312 DSTACK(__FUNCTION_NAME);
3314 verbosestream<<"dedicated_server_loop()"<<std::endl;
3316 IntervalLimiter m_profiler_interval;
3320 float steplen = g_settings->getFloat("dedicated_server_step");
3321 // This is kind of a hack but can be done like this
3322 // because server.step() is very light
3324 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3325 sleep_ms((int)(steplen*1000.0));
3327 server.step(steplen);
3329 if(server.getShutdownRequested() || kill)
3331 infostream<<"Dedicated server quitting"<<std::endl;
3333 if(g_settings->getBool("server_announce"))
3334 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3342 float profiler_print_interval =
3343 g_settings->getFloat("profiler_print_interval");
3344 if(profiler_print_interval != 0)
3346 if(m_profiler_interval.step(steplen, profiler_print_interval))
3348 infostream<<"Profiler:"<<std::endl;
3349 g_profiler->print(infostream);
3350 g_profiler->clear();