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(!initializeWorld(m_path_world, m_gamespec.id))
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();
485 throw ServerError(async_err);
489 void Server::AsyncRunStep(bool initial_step)
491 DSTACK(__FUNCTION_NAME);
493 g_profiler->add("Server::AsyncRunStep (num)", 1);
497 JMutexAutoLock lock1(m_step_dtime_mutex);
498 dtime = m_step_dtime;
502 // Send blocks to clients
506 if((dtime < 0.001) && (initial_step == false))
509 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
511 //infostream<<"Server steps "<<dtime<<std::endl;
512 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
515 JMutexAutoLock lock1(m_step_dtime_mutex);
516 m_step_dtime -= dtime;
523 m_uptime.set(m_uptime.get() + dtime);
529 Update time of day and overall game time
531 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
534 Send to clients at constant intervals
537 m_time_of_day_send_timer -= dtime;
538 if(m_time_of_day_send_timer < 0.0) {
539 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
540 u16 time = m_env->getTimeOfDay();
541 float time_speed = g_settings->getFloat("time_speed");
542 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
546 JMutexAutoLock lock(m_env_mutex);
547 // Figure out and report maximum lag to environment
548 float max_lag = m_env->getMaxLagEstimate();
549 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
551 if(dtime > 0.1 && dtime > max_lag * 2.0)
552 infostream<<"Server: Maximum lag peaked to "<<dtime
556 m_env->reportMaxLagEstimate(max_lag);
558 ScopeProfiler sp(g_profiler, "SEnv step");
559 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
563 static const float map_timer_and_unload_dtime = 2.92;
564 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
566 JMutexAutoLock lock(m_env_mutex);
567 // Run Map's timers and unload unused data
568 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
569 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
570 g_settings->getFloat("server_unload_unused_data_timeout"));
577 /* Transform liquids */
578 m_liquid_transform_timer += dtime;
579 if(m_liquid_transform_timer >= m_liquid_transform_every)
581 m_liquid_transform_timer -= m_liquid_transform_every;
583 JMutexAutoLock lock(m_env_mutex);
585 ScopeProfiler sp(g_profiler, "Server: liquid transform");
587 std::map<v3s16, MapBlock*> modified_blocks;
588 m_env->getMap().transformLiquids(modified_blocks);
593 core::map<v3s16, MapBlock*> lighting_modified_blocks;
594 ServerMap &map = ((ServerMap&)m_env->getMap());
595 map.updateLighting(modified_blocks, lighting_modified_blocks);
597 // Add blocks modified by lighting to modified_blocks
598 for(core::map<v3s16, MapBlock*>::Iterator
599 i = lighting_modified_blocks.getIterator();
600 i.atEnd() == false; i++)
602 MapBlock *block = i.getNode()->getValue();
603 modified_blocks.insert(block->getPos(), block);
607 Set the modified blocks unsent for all the clients
609 if(!modified_blocks.empty())
611 SetBlocksNotSent(modified_blocks);
614 m_clients.step(dtime);
616 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
618 // send masterserver announce
620 float &counter = m_masterserver_timer;
621 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
622 g_settings->getBool("server_announce"))
624 ServerList::sendAnnounce(counter ? "update" : "start",
625 m_bind_addr.getPort(),
626 m_clients.getPlayerNames(),
628 m_env->getGameTime(),
631 m_emerge->params.mg_name,
640 Check added and deleted active objects
643 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
644 JMutexAutoLock envlock(m_env_mutex);
647 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
648 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
650 // Radius inside which objects are active
651 s16 radius = g_settings->getS16("active_object_send_range_blocks");
652 s16 player_radius = g_settings->getS16("player_transfer_distance");
654 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
655 !g_settings->getBool("unlimited_player_transfer_distance"))
656 player_radius = radius;
658 radius *= MAP_BLOCKSIZE;
659 player_radius *= MAP_BLOCKSIZE;
661 for(std::map<u16, RemoteClient*>::iterator
663 i != clients.end(); ++i)
665 RemoteClient *client = i->second;
667 // If definitions and textures have not been sent, don't
668 // send objects either
669 if (client->getState() < CS_DefinitionsSent)
672 Player *player = m_env->getPlayer(client->peer_id);
675 // This can happen if the client timeouts somehow
676 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
678 <<" has no associated player"<<std::endl;*/
681 v3s16 pos = floatToInt(player->getPosition(), BS);
683 std::set<u16> removed_objects;
684 std::set<u16> added_objects;
685 m_env->getRemovedActiveObjects(pos, radius, player_radius,
686 client->m_known_objects, removed_objects);
687 m_env->getAddedActiveObjects(pos, radius, player_radius,
688 client->m_known_objects, added_objects);
690 // Ignore if nothing happened
691 if(removed_objects.empty() && added_objects.empty())
693 //infostream<<"active objects: none changed"<<std::endl;
697 std::string data_buffer;
701 // Handle removed objects
702 writeU16((u8*)buf, removed_objects.size());
703 data_buffer.append(buf, 2);
704 for(std::set<u16>::iterator
705 i = removed_objects.begin();
706 i != removed_objects.end(); ++i)
710 ServerActiveObject* obj = m_env->getActiveObject(id);
712 // Add to data buffer for sending
713 writeU16((u8*)buf, id);
714 data_buffer.append(buf, 2);
716 // Remove from known objects
717 client->m_known_objects.erase(id);
719 if(obj && obj->m_known_by_count > 0)
720 obj->m_known_by_count--;
723 // Handle added objects
724 writeU16((u8*)buf, added_objects.size());
725 data_buffer.append(buf, 2);
726 for(std::set<u16>::iterator
727 i = added_objects.begin();
728 i != added_objects.end(); ++i)
732 ServerActiveObject* obj = m_env->getActiveObject(id);
735 u8 type = ACTIVEOBJECT_TYPE_INVALID;
737 infostream<<"WARNING: "<<__FUNCTION_NAME
738 <<": NULL object"<<std::endl;
740 type = obj->getSendType();
742 // Add to data buffer for sending
743 writeU16((u8*)buf, id);
744 data_buffer.append(buf, 2);
745 writeU8((u8*)buf, type);
746 data_buffer.append(buf, 1);
749 data_buffer.append(serializeLongString(
750 obj->getClientInitializationData(client->net_proto_version)));
752 data_buffer.append(serializeLongString(""));
754 // Add to known objects
755 client->m_known_objects.insert(id);
758 obj->m_known_by_count++;
761 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
762 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
765 verbosestream << "Server: Sent object remove/add: "
766 << removed_objects.size() << " removed, "
767 << added_objects.size() << " added, "
768 << "packet size is " << pkt->getSize() << std::endl;
779 JMutexAutoLock envlock(m_env_mutex);
780 ScopeProfiler sp(g_profiler, "Server: sending object messages");
783 // Value = data sent by object
784 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
786 // Get active object messages from environment
788 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
792 std::vector<ActiveObjectMessage>* message_list = NULL;
793 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
794 n = buffered_messages.find(aom.id);
795 if (n == buffered_messages.end()) {
796 message_list = new std::vector<ActiveObjectMessage>;
797 buffered_messages[aom.id] = message_list;
800 message_list = n->second;
802 message_list->push_back(aom);
806 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
807 // Route data to every client
808 for (std::map<u16, RemoteClient*>::iterator
810 i != clients.end(); ++i) {
811 RemoteClient *client = i->second;
812 std::string reliable_data;
813 std::string unreliable_data;
814 // Go through all objects in message buffer
815 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
816 j = buffered_messages.begin();
817 j != buffered_messages.end(); ++j) {
818 // If object is not known by client, skip it
820 if (client->m_known_objects.find(id) == client->m_known_objects.end())
823 // Get message list of object
824 std::vector<ActiveObjectMessage>* list = j->second;
825 // Go through every message
826 for (std::vector<ActiveObjectMessage>::iterator
827 k = list->begin(); k != list->end(); ++k) {
828 // Compose the full new data with header
829 ActiveObjectMessage aom = *k;
830 std::string new_data;
833 writeU16((u8*)&buf[0], aom.id);
834 new_data.append(buf, 2);
836 new_data += serializeString(aom.datastring);
837 // Add data to buffer
839 reliable_data += new_data;
841 unreliable_data += new_data;
845 reliable_data and unreliable_data are now ready.
848 if(reliable_data.size() > 0) {
849 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
852 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
856 if(unreliable_data.size() > 0) {
857 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
860 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
866 // Clear buffered_messages
867 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
868 i = buffered_messages.begin();
869 i != buffered_messages.end(); ++i) {
875 Send queued-for-sending map edit events.
878 // We will be accessing the environment
879 JMutexAutoLock lock(m_env_mutex);
881 // Don't send too many at a time
884 // Single change sending is disabled if queue size is not small
885 bool disable_single_change_sending = false;
886 if(m_unsent_map_edit_queue.size() >= 4)
887 disable_single_change_sending = true;
889 int event_count = m_unsent_map_edit_queue.size();
891 // We'll log the amount of each
894 while(m_unsent_map_edit_queue.size() != 0)
896 MapEditEvent* event = m_unsent_map_edit_queue.front();
897 m_unsent_map_edit_queue.pop();
899 // Players far away from the change are stored here.
900 // Instead of sending the changes, MapBlocks are set not sent
902 std::vector<u16> far_players;
904 switch (event->type) {
907 prof.add("MEET_ADDNODE", 1);
908 sendAddNode(event->p, event->n, event->already_known_by_peer,
909 &far_players, disable_single_change_sending ? 5 : 30,
910 event->type == MEET_ADDNODE);
912 case MEET_REMOVENODE:
913 prof.add("MEET_REMOVENODE", 1);
914 sendRemoveNode(event->p, event->already_known_by_peer,
915 &far_players, disable_single_change_sending ? 5 : 30);
917 case MEET_BLOCK_NODE_METADATA_CHANGED:
918 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
919 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
920 setBlockNotSent(event->p);
923 infostream << "Server: MEET_OTHER" << std::endl;
924 prof.add("MEET_OTHER", 1);
925 for(std::set<v3s16>::iterator
926 i = event->modified_blocks.begin();
927 i != event->modified_blocks.end(); ++i) {
932 prof.add("unknown", 1);
933 infostream << "WARNING: Server: Unknown MapEditEvent "
934 << ((u32)event->type) << std::endl;
939 Set blocks not sent to far players
941 if(!far_players.empty()) {
942 // Convert list format to that wanted by SetBlocksNotSent
943 std::map<v3s16, MapBlock*> modified_blocks2;
944 for(std::set<v3s16>::iterator
945 i = event->modified_blocks.begin();
946 i != event->modified_blocks.end(); ++i) {
947 modified_blocks2[*i] =
948 m_env->getMap().getBlockNoCreateNoEx(*i);
951 // Set blocks not sent
952 for(std::vector<u16>::iterator
953 i = far_players.begin();
954 i != far_players.end(); ++i) {
955 if(RemoteClient *client = getClient(*i))
956 client->SetBlocksNotSent(modified_blocks2);
962 /*// Don't send too many at a time
964 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
968 if(event_count >= 5){
969 infostream<<"Server: MapEditEvents:"<<std::endl;
970 prof.print(infostream);
971 } else if(event_count != 0){
972 verbosestream<<"Server: MapEditEvents:"<<std::endl;
973 prof.print(verbosestream);
979 Trigger emergethread (it somehow gets to a non-triggered but
980 bysy state sometimes)
983 float &counter = m_emergethread_trigger_timer;
989 m_emerge->startThreads();
993 // Save map, players and auth stuff
995 float &counter = m_savemap_timer;
997 if(counter >= g_settings->getFloat("server_map_save_interval"))
1000 JMutexAutoLock lock(m_env_mutex);
1002 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1005 if (m_banmanager->isModified()) {
1006 m_banmanager->save();
1009 // Save changed parts of map
1010 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1013 m_env->saveLoadedPlayers();
1015 // Save environment metadata
1021 void Server::Receive()
1023 DSTACK(__FUNCTION_NAME);
1024 SharedBuffer<u8> data;
1028 datasize = m_con.Receive(peer_id,data);
1029 ProcessData(*data, datasize, peer_id);
1031 catch(con::InvalidIncomingDataException &e) {
1032 infostream<<"Server::Receive(): "
1033 "InvalidIncomingDataException: what()="
1034 <<e.what()<<std::endl;
1036 catch(SerializationError &e) {
1037 infostream<<"Server::Receive(): "
1038 "SerializationError: what()="
1039 <<e.what()<<std::endl;
1041 catch(ClientStateError &e) {
1042 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1043 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1044 L"Try reconnecting or updating your client");
1046 catch(con::PeerNotFoundException &e) {
1051 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1053 std::string playername = "";
1054 PlayerSAO *playersao = NULL;
1057 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1058 if (client != NULL) {
1059 playername = client->getName();
1060 playersao = emergePlayer(playername.c_str(), peer_id);
1062 } catch (std::exception &e) {
1068 RemotePlayer *player =
1069 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1071 // If failed, cancel
1072 if((playersao == NULL) || (player == NULL)) {
1073 if(player && player->peer_id != 0) {
1074 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1075 <<" (player allocated to an another client)"<<std::endl;
1076 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1077 L"name. If your client closed unexpectedly, try again in "
1080 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1082 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1088 Send complete position information
1090 SendMovePlayer(peer_id);
1093 SendPlayerPrivileges(peer_id);
1095 // Send inventory formspec
1096 SendPlayerInventoryFormspec(peer_id);
1099 SendInventory(playersao);
1102 if(g_settings->getBool("enable_damage"))
1103 SendPlayerHP(peer_id);
1106 SendPlayerBreath(peer_id);
1108 // Show death screen if necessary
1109 if(player->isDead())
1110 SendDeathscreen(peer_id, false, v3f(0,0,0));
1112 // Note things in chat if not in simple singleplayer mode
1113 if(!m_simple_singleplayer_mode) {
1114 // Send information about server to player in chat
1115 SendChatMessage(peer_id, getStatusString());
1117 // Send information about joining in chat
1119 std::wstring name = L"unknown";
1120 Player *player = m_env->getPlayer(peer_id);
1122 name = narrow_to_wide(player->getName());
1124 std::wstring message;
1127 message += L" joined the game.";
1128 SendChatMessage(PEER_ID_INEXISTENT,message);
1131 Address addr = getPeerAddress(player->peer_id);
1132 std::string ip_str = addr.serializeString();
1133 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1138 std::vector<std::string> names = m_clients.getPlayerNames();
1140 actionstream<<player->getName() <<" joins game. List of players: ";
1142 for (std::vector<std::string>::iterator i = names.begin();
1143 i != names.end(); i++) {
1144 actionstream << *i << " ";
1147 actionstream << player->getName() <<std::endl;
1152 inline void Server::handleCommand(NetworkPacket* pkt)
1154 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1155 (this->*opHandle.handler)(pkt);
1158 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1160 DSTACK(__FUNCTION_NAME);
1161 // Environment is locked first.
1162 JMutexAutoLock envlock(m_env_mutex);
1164 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1167 Address address = getPeerAddress(peer_id);
1168 std::string addr_s = address.serializeString();
1170 if(m_banmanager->isIpBanned(addr_s)) {
1171 std::string ban_name = m_banmanager->getBanName(addr_s);
1172 infostream << "Server: A banned client tried to connect from "
1173 << addr_s << "; banned name was "
1174 << ban_name << std::endl;
1175 // This actually doesn't seem to transfer to the client
1176 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1177 + narrow_to_wide(ban_name));
1181 catch(con::PeerNotFoundException &e) {
1183 * no peer for this packet found
1184 * most common reason is peer timeout, e.g. peer didn't
1185 * respond for some time, your server was overloaded or
1188 infostream << "Server::ProcessData(): Cancelling: peer "
1189 << peer_id << " not found" << std::endl;
1197 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1199 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1201 // Command must be handled into ToServerCommandHandler
1202 if (command >= TOSERVER_NUM_MSG_TYPES) {
1203 infostream << "Server: Ignoring unknown command "
1204 << command << std::endl;
1207 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1213 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1215 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1216 errorstream << "Server::ProcessData(): Cancelling: Peer"
1217 " serialization format invalid or not initialized."
1218 " Skipping incoming command=" << command << std::endl;
1224 /* Handle commands related to client startup */
1225 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1231 if (m_clients.getClientState(peer_id) < CS_Active) {
1232 if (command == TOSERVER_PLAYERPOS) return;
1234 errorstream << "Got packet command: " << command << " for peer id "
1235 << peer_id << " but client isn't active yet. Dropping packet "
1246 catch(SendFailedException &e) {
1247 errorstream << "Server::ProcessData(): SendFailedException: "
1248 << "what=" << e.what()
1253 void Server::setTimeOfDay(u32 time)
1255 m_env->setTimeOfDay(time);
1256 m_time_of_day_send_timer = 0;
1259 void Server::onMapEditEvent(MapEditEvent *event)
1261 if(m_ignore_map_edit_events)
1263 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1265 MapEditEvent *e = event->clone();
1266 m_unsent_map_edit_queue.push(e);
1269 Inventory* Server::getInventory(const InventoryLocation &loc)
1272 case InventoryLocation::UNDEFINED:
1273 case InventoryLocation::CURRENT_PLAYER:
1275 case InventoryLocation::PLAYER:
1277 Player *player = m_env->getPlayer(loc.name.c_str());
1280 PlayerSAO *playersao = player->getPlayerSAO();
1283 return playersao->getInventory();
1286 case InventoryLocation::NODEMETA:
1288 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1291 return meta->getInventory();
1294 case InventoryLocation::DETACHED:
1296 if(m_detached_inventories.count(loc.name) == 0)
1298 return m_detached_inventories[loc.name];
1302 sanity_check(false); // abort
1307 void Server::setInventoryModified(const InventoryLocation &loc)
1310 case InventoryLocation::UNDEFINED:
1312 case InventoryLocation::PLAYER:
1314 Player *player = m_env->getPlayer(loc.name.c_str());
1317 PlayerSAO *playersao = player->getPlayerSAO();
1321 SendInventory(playersao);
1324 case InventoryLocation::NODEMETA:
1326 v3s16 blockpos = getNodeBlockPos(loc.p);
1328 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1330 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1332 setBlockNotSent(blockpos);
1335 case InventoryLocation::DETACHED:
1337 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1341 sanity_check(false); // abort
1346 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1348 std::vector<u16> clients = m_clients.getClientIDs();
1350 // Set the modified blocks unsent for all the clients
1351 for (std::vector<u16>::iterator i = clients.begin();
1352 i != clients.end(); ++i) {
1353 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1354 client->SetBlocksNotSent(block);
1359 void Server::peerAdded(con::Peer *peer)
1361 DSTACK(__FUNCTION_NAME);
1362 verbosestream<<"Server::peerAdded(): peer->id="
1363 <<peer->id<<std::endl;
1366 c.type = con::PEER_ADDED;
1367 c.peer_id = peer->id;
1369 m_peer_change_queue.push(c);
1372 void Server::deletingPeer(con::Peer *peer, bool timeout)
1374 DSTACK(__FUNCTION_NAME);
1375 verbosestream<<"Server::deletingPeer(): peer->id="
1376 <<peer->id<<", timeout="<<timeout<<std::endl;
1378 m_clients.event(peer->id, CSE_Disconnect);
1380 c.type = con::PEER_REMOVED;
1381 c.peer_id = peer->id;
1382 c.timeout = timeout;
1383 m_peer_change_queue.push(c);
1386 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1388 *retval = m_con.getPeerStat(peer_id,type);
1389 if (*retval == -1) return false;
1393 bool Server::getClientInfo(
1402 std::string* vers_string
1405 *state = m_clients.getClientState(peer_id);
1407 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1409 if (client == NULL) {
1414 *uptime = client->uptime();
1415 *ser_vers = client->serialization_version;
1416 *prot_vers = client->net_proto_version;
1418 *major = client->getMajor();
1419 *minor = client->getMinor();
1420 *patch = client->getPatch();
1421 *vers_string = client->getPatch();
1428 void Server::handlePeerChanges()
1430 while(m_peer_change_queue.size() > 0)
1432 con::PeerChange c = m_peer_change_queue.front();
1433 m_peer_change_queue.pop();
1435 verbosestream<<"Server: Handling peer change: "
1436 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1441 case con::PEER_ADDED:
1442 m_clients.CreateClient(c.peer_id);
1445 case con::PEER_REMOVED:
1446 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1450 FATAL_ERROR("Invalid peer change event received!");
1456 void Server::Send(NetworkPacket* pkt)
1458 m_clients.send(pkt->getPeerId(),
1459 clientCommandFactoryTable[pkt->getCommand()].channel,
1461 clientCommandFactoryTable[pkt->getCommand()].reliable);
1464 void Server::SendMovement(u16 peer_id)
1466 DSTACK(__FUNCTION_NAME);
1467 std::ostringstream os(std::ios_base::binary);
1469 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1471 *pkt << g_settings->getFloat("movement_acceleration_default");
1472 *pkt << g_settings->getFloat("movement_acceleration_air");
1473 *pkt << g_settings->getFloat("movement_acceleration_fast");
1474 *pkt << g_settings->getFloat("movement_speed_walk");
1475 *pkt << g_settings->getFloat("movement_speed_crouch");
1476 *pkt << g_settings->getFloat("movement_speed_fast");
1477 *pkt << g_settings->getFloat("movement_speed_climb");
1478 *pkt << g_settings->getFloat("movement_speed_jump");
1479 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1480 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1481 *pkt << g_settings->getFloat("movement_liquid_sink");
1482 *pkt << g_settings->getFloat("movement_gravity");
1487 void Server::SendHP(u16 peer_id, u8 hp)
1489 DSTACK(__FUNCTION_NAME);
1491 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1496 void Server::SendBreath(u16 peer_id, u16 breath)
1498 DSTACK(__FUNCTION_NAME);
1500 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1501 *pkt << (u16) breath;
1505 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
1507 DSTACK(__FUNCTION_NAME);
1509 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1512 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1513 pkt << custom_reason;
1518 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1520 DSTACK(__FUNCTION_NAME);
1522 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1527 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1528 v3f camera_point_target)
1530 DSTACK(__FUNCTION_NAME);
1532 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1533 *pkt << set_camera_point_target << camera_point_target;
1537 void Server::SendItemDef(u16 peer_id,
1538 IItemDefManager *itemdef, u16 protocol_version)
1540 DSTACK(__FUNCTION_NAME);
1542 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1546 u32 length of the next item
1547 zlib-compressed serialized ItemDefManager
1549 std::ostringstream tmp_os(std::ios::binary);
1550 itemdef->serialize(tmp_os, protocol_version);
1551 std::ostringstream tmp_os2(std::ios::binary);
1552 compressZlib(tmp_os.str(), tmp_os2);
1553 pkt->putLongString(tmp_os2.str());
1556 verbosestream << "Server: Sending item definitions to id(" << peer_id
1557 << "): size=" << pkt->getSize() << std::endl;
1562 void Server::SendNodeDef(u16 peer_id,
1563 INodeDefManager *nodedef, u16 protocol_version)
1565 DSTACK(__FUNCTION_NAME);
1567 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1571 u32 length of the next item
1572 zlib-compressed serialized NodeDefManager
1574 std::ostringstream tmp_os(std::ios::binary);
1575 nodedef->serialize(tmp_os, protocol_version);
1576 std::ostringstream tmp_os2(std::ios::binary);
1577 compressZlib(tmp_os.str(), tmp_os2);
1579 pkt->putLongString(tmp_os2.str());
1582 verbosestream << "Server: Sending node definitions to id(" << peer_id
1583 << "): size=" << pkt->getSize() << std::endl;
1589 Non-static send methods
1592 void Server::SendInventory(PlayerSAO* playerSAO)
1594 DSTACK(__FUNCTION_NAME);
1596 UpdateCrafting(playerSAO->getPlayer());
1602 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1603 playerSAO->getPeerID());
1605 std::ostringstream os;
1606 playerSAO->getInventory()->serialize(os);
1608 std::string s = os.str();
1610 pkt->putRawString(s.c_str(), s.size());
1614 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1616 DSTACK(__FUNCTION_NAME);
1618 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1621 if (peer_id != PEER_ID_INEXISTENT) {
1625 m_clients.sendToAll(0,pkt,true);
1629 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1630 const std::string &formname)
1632 DSTACK(__FUNCTION_NAME);
1634 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1636 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1642 // Spawns a particle on peer with peer_id
1643 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1644 float expirationtime, float size, bool collisiondetection,
1645 bool vertical, std::string texture)
1647 DSTACK(__FUNCTION_NAME);
1649 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1651 *pkt << pos << velocity << acceleration << expirationtime
1652 << size << collisiondetection;
1653 pkt->putLongString(texture);
1656 if (peer_id != PEER_ID_INEXISTENT) {
1660 m_clients.sendToAll(0,pkt,true);
1664 // Adds a ParticleSpawner on peer with peer_id
1665 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1666 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1667 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1669 DSTACK(__FUNCTION_NAME);
1671 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1673 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1674 << minacc << maxacc << minexptime << maxexptime << minsize
1675 << maxsize << collisiondetection;
1677 pkt->putLongString(texture);
1679 *pkt << id << vertical;
1681 if (peer_id != PEER_ID_INEXISTENT) {
1685 m_clients.sendToAll(0, pkt, true);
1689 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1691 DSTACK(__FUNCTION_NAME);
1693 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1695 // Ugly error in this packet
1698 if (peer_id != PEER_ID_INEXISTENT) {
1702 m_clients.sendToAll(0, pkt, true);
1707 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1709 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1711 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1712 << form->text << form->number << form->item << form->dir
1713 << form->align << form->offset << form->world_pos << form->size;
1718 void Server::SendHUDRemove(u16 peer_id, u32 id)
1720 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1725 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1727 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1728 *pkt << id << (u8) stat;
1732 case HUD_STAT_SCALE:
1733 case HUD_STAT_ALIGN:
1734 case HUD_STAT_OFFSET:
1735 *pkt << *(v2f *) value;
1739 *pkt << *(std::string *) value;
1741 case HUD_STAT_WORLD_POS:
1742 *pkt << *(v3f *) value;
1745 *pkt << *(v2s32 *) value;
1747 case HUD_STAT_NUMBER:
1751 *pkt << *(u32 *) value;
1758 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1760 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1762 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1764 *pkt << flags << mask;
1769 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1771 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1772 *pkt << param << value;
1776 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1777 const std::string &type, const std::vector<std::string> ¶ms)
1779 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1780 *pkt << bgcolor << type << (u16) params.size();
1782 for(size_t i=0; i<params.size(); i++)
1788 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1791 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1794 *pkt << do_override << (u16) (ratio * 65535);
1799 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1801 DSTACK(__FUNCTION_NAME);
1803 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1804 *pkt << time << time_speed;
1806 if (peer_id == PEER_ID_INEXISTENT) {
1807 m_clients.sendToAll(0, pkt, true);
1814 void Server::SendPlayerHP(u16 peer_id)
1816 DSTACK(__FUNCTION_NAME);
1817 PlayerSAO *playersao = getPlayerSAO(peer_id);
1819 SendHP(peer_id, playersao->getHP());
1820 m_script->player_event(playersao,"health_changed");
1822 // Send to other clients
1823 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1824 ActiveObjectMessage aom(playersao->getId(), true, str);
1825 playersao->m_messages_out.push(aom);
1828 void Server::SendPlayerBreath(u16 peer_id)
1830 DSTACK(__FUNCTION_NAME);
1831 PlayerSAO *playersao = getPlayerSAO(peer_id);
1834 m_script->player_event(playersao, "breath_changed");
1835 SendBreath(peer_id, playersao->getBreath());
1838 void Server::SendMovePlayer(u16 peer_id)
1840 DSTACK(__FUNCTION_NAME);
1841 Player *player = m_env->getPlayer(peer_id);
1844 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1845 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1848 v3f pos = player->getPosition();
1849 f32 pitch = player->getPitch();
1850 f32 yaw = player->getYaw();
1851 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1852 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1861 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1863 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1866 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1867 << animation_frames[3] << animation_speed;
1872 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1874 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1875 *pkt << first << third;
1878 void Server::SendPlayerPrivileges(u16 peer_id)
1880 Player *player = m_env->getPlayer(peer_id);
1882 if(player->peer_id == PEER_ID_INEXISTENT)
1885 std::set<std::string> privs;
1886 m_script->getAuth(player->getName(), NULL, &privs);
1888 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1889 *pkt << (u16) privs.size();
1891 for(std::set<std::string>::const_iterator i = privs.begin();
1892 i != privs.end(); i++) {
1899 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1901 Player *player = m_env->getPlayer(peer_id);
1903 if(player->peer_id == PEER_ID_INEXISTENT)
1906 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1907 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1911 s32 Server::playSound(const SimpleSoundSpec &spec,
1912 const ServerSoundParams ¶ms)
1914 // Find out initial position of sound
1915 bool pos_exists = false;
1916 v3f pos = params.getPos(m_env, &pos_exists);
1917 // If position is not found while it should be, cancel sound
1918 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1921 // Filter destination clients
1922 std::vector<u16> dst_clients;
1923 if(params.to_player != "")
1925 Player *player = m_env->getPlayer(params.to_player.c_str());
1927 infostream<<"Server::playSound: Player \""<<params.to_player
1928 <<"\" not found"<<std::endl;
1931 if(player->peer_id == PEER_ID_INEXISTENT){
1932 infostream<<"Server::playSound: Player \""<<params.to_player
1933 <<"\" not connected"<<std::endl;
1936 dst_clients.push_back(player->peer_id);
1939 std::vector<u16> clients = m_clients.getClientIDs();
1941 for(std::vector<u16>::iterator
1942 i = clients.begin(); i != clients.end(); ++i) {
1943 Player *player = m_env->getPlayer(*i);
1948 if(player->getPosition().getDistanceFrom(pos) >
1949 params.max_hear_distance)
1952 dst_clients.push_back(*i);
1956 if(dst_clients.empty())
1960 s32 id = m_next_sound_id++;
1961 // The sound will exist as a reference in m_playing_sounds
1962 m_playing_sounds[id] = ServerPlayingSound();
1963 ServerPlayingSound &psound = m_playing_sounds[id];
1964 psound.params = params;
1966 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1967 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1968 << (u8) params.type << pos << params.object << params.loop;
1970 for(std::vector<u16>::iterator i = dst_clients.begin();
1971 i != dst_clients.end(); i++) {
1972 psound.clients.insert(*i);
1973 m_clients.send(*i, 0, pkt, true, false);
1978 void Server::stopSound(s32 handle)
1980 // Get sound reference
1981 std::map<s32, ServerPlayingSound>::iterator i =
1982 m_playing_sounds.find(handle);
1983 if(i == m_playing_sounds.end())
1985 ServerPlayingSound &psound = i->second;
1987 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
1990 for(std::set<u16>::iterator i = psound.clients.begin();
1991 i != psound.clients.end(); i++) {
1993 m_clients.send(*i, 0, pkt, true, false);
1996 // Remove sound reference
1997 m_playing_sounds.erase(i);
2000 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2001 std::vector<u16> *far_players, float far_d_nodes)
2003 float maxd = far_d_nodes*BS;
2004 v3f p_f = intToFloat(p, BS);
2006 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2009 std::vector<u16> clients = m_clients.getClientIDs();
2010 for(std::vector<u16>::iterator i = clients.begin();
2011 i != clients.end(); ++i) {
2014 if(Player *player = m_env->getPlayer(*i)) {
2015 // If player is far away, only set modified blocks not sent
2016 v3f player_pos = player->getPosition();
2017 if(player_pos.getDistanceFrom(p_f) > maxd) {
2018 far_players->push_back(*i);
2025 m_clients.send(*i, 0, pkt, true, false);
2027 // This loop needs the deletion of the packet here
2031 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2032 std::vector<u16> *far_players, float far_d_nodes,
2033 bool remove_metadata)
2035 float maxd = far_d_nodes*BS;
2036 v3f p_f = intToFloat(p, BS);
2038 std::vector<u16> clients = m_clients.getClientIDs();
2039 for(std::vector<u16>::iterator i = clients.begin();
2040 i != clients.end(); ++i) {
2044 if(Player *player = m_env->getPlayer(*i)) {
2045 // If player is far away, only set modified blocks not sent
2046 v3f player_pos = player->getPosition();
2047 if(player_pos.getDistanceFrom(p_f) > maxd) {
2048 far_players->push_back(*i);
2054 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2056 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2058 *pkt << p << n.param0 << n.param1 << n.param2
2059 << (u8) (remove_metadata ? 0 : 1);
2061 if (!remove_metadata) {
2062 if (client->net_proto_version <= 21) {
2063 // Old clients always clear metadata; fix it
2064 // by sending the full block again.
2065 client->SetBlockNotSent(p);
2072 if (pkt->getSize() > 0)
2073 m_clients.send(*i, 0, pkt, true);
2077 void Server::setBlockNotSent(v3s16 p)
2079 std::vector<u16> clients = m_clients.getClientIDs();
2081 for(std::vector<u16>::iterator i = clients.begin();
2082 i != clients.end(); ++i) {
2083 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2084 client->SetBlockNotSent(p);
2089 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2091 DSTACK(__FUNCTION_NAME);
2093 v3s16 p = block->getPos();
2096 Create a packet with the block in the right format
2099 std::ostringstream os(std::ios_base::binary);
2100 block->serialize(os, ver, false);
2101 block->serializeNetworkSpecific(os, net_proto_version);
2102 std::string s = os.str();
2104 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2105 2 + 2 + 2 + 2 + s.size(), peer_id);
2108 pkt->putRawString(s.c_str(), s.size());
2112 void Server::SendBlocks(float dtime)
2114 DSTACK(__FUNCTION_NAME);
2116 JMutexAutoLock envlock(m_env_mutex);
2117 //TODO check if one big lock could be faster then multiple small ones
2119 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2121 std::vector<PrioritySortedBlockTransfer> queue;
2123 s32 total_sending = 0;
2126 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2128 std::vector<u16> clients = m_clients.getClientIDs();
2131 for(std::vector<u16>::iterator i = clients.begin();
2132 i != clients.end(); ++i) {
2133 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2138 total_sending += client->SendingCount();
2139 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2145 // Lowest priority number comes first.
2146 // Lowest is most important.
2147 std::sort(queue.begin(), queue.end());
2150 for(u32 i=0; i<queue.size(); i++)
2152 //TODO: Calculate limit dynamically
2153 if(total_sending >= g_settings->getS32
2154 ("max_simultaneous_block_sends_server_total"))
2157 PrioritySortedBlockTransfer q = queue[i];
2159 MapBlock *block = NULL;
2162 block = m_env->getMap().getBlockNoCreate(q.pos);
2164 catch(InvalidPositionException &e)
2169 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2174 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2176 client->SentBlock(q.pos);
2182 void Server::fillMediaCache()
2184 DSTACK(__FUNCTION_NAME);
2186 infostream<<"Server: Calculating media file checksums"<<std::endl;
2188 // Collect all media file paths
2189 std::vector<std::string> paths;
2190 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2191 i != m_mods.end(); i++) {
2192 const ModSpec &mod = *i;
2193 paths.push_back(mod.path + DIR_DELIM + "textures");
2194 paths.push_back(mod.path + DIR_DELIM + "sounds");
2195 paths.push_back(mod.path + DIR_DELIM + "media");
2196 paths.push_back(mod.path + DIR_DELIM + "models");
2198 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2200 // Collect media file information from paths into cache
2201 for(std::vector<std::string>::iterator i = paths.begin();
2202 i != paths.end(); i++) {
2203 std::string mediapath = *i;
2204 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2205 for (u32 j = 0; j < dirlist.size(); j++) {
2206 if (dirlist[j].dir) // Ignode dirs
2208 std::string filename = dirlist[j].name;
2209 // If name contains illegal characters, ignore the file
2210 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2211 infostream<<"Server: ignoring illegal file name: \""
2212 << filename << "\"" << std::endl;
2215 // If name is not in a supported format, ignore it
2216 const char *supported_ext[] = {
2217 ".png", ".jpg", ".bmp", ".tga",
2218 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2220 ".x", ".b3d", ".md2", ".obj",
2223 if (removeStringEnd(filename, supported_ext) == ""){
2224 infostream << "Server: ignoring unsupported file extension: \""
2225 << filename << "\"" << std::endl;
2228 // Ok, attempt to load the file and add to cache
2229 std::string filepath = mediapath + DIR_DELIM + filename;
2231 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2233 errorstream << "Server::fillMediaCache(): Could not open \""
2234 << filename << "\" for reading" << std::endl;
2237 std::ostringstream tmp_os(std::ios_base::binary);
2241 fis.read(buf, 1024);
2242 std::streamsize len = fis.gcount();
2243 tmp_os.write(buf, len);
2252 errorstream<<"Server::fillMediaCache(): Failed to read \""
2253 << filename << "\"" << std::endl;
2256 if(tmp_os.str().length() == 0) {
2257 errorstream << "Server::fillMediaCache(): Empty file \""
2258 << filepath << "\"" << std::endl;
2263 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2265 unsigned char *digest = sha1.getDigest();
2266 std::string sha1_base64 = base64_encode(digest, 20);
2267 std::string sha1_hex = hex_encode((char*)digest, 20);
2271 m_media[filename] = MediaInfo(filepath, sha1_base64);
2272 verbosestream << "Server: " << sha1_hex << " is " << filename
2278 struct SendableMediaAnnouncement
2281 std::string sha1_digest;
2283 SendableMediaAnnouncement(const std::string &name_="",
2284 const std::string &sha1_digest_=""):
2286 sha1_digest(sha1_digest_)
2290 void Server::sendMediaAnnouncement(u16 peer_id)
2292 DSTACK(__FUNCTION_NAME);
2294 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2297 std::vector<SendableMediaAnnouncement> file_announcements;
2299 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2300 i != m_media.end(); i++){
2302 file_announcements.push_back(
2303 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2307 std::ostringstream os(std::ios_base::binary);
2314 u16 length of sha1_digest
2319 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2320 *pkt << (u16) file_announcements.size();
2322 for (std::vector<SendableMediaAnnouncement>::iterator
2323 j = file_announcements.begin();
2324 j != file_announcements.end(); ++j) {
2325 *pkt << j->name << j->sha1_digest;
2328 *pkt << g_settings->get("remote_media");
2332 struct SendableMedia
2338 SendableMedia(const std::string &name_="", const std::string &path_="",
2339 const std::string &data_=""):
2346 void Server::sendRequestedMedia(u16 peer_id,
2347 const std::vector<std::string> &tosend)
2349 DSTACK(__FUNCTION_NAME);
2351 verbosestream<<"Server::sendRequestedMedia(): "
2352 <<"Sending files to client"<<std::endl;
2356 // Put 5kB in one bunch (this is not accurate)
2357 u32 bytes_per_bunch = 5000;
2359 std::vector< std::vector<SendableMedia> > file_bunches;
2360 file_bunches.push_back(std::vector<SendableMedia>());
2362 u32 file_size_bunch_total = 0;
2364 for(std::vector<std::string>::const_iterator i = tosend.begin();
2365 i != tosend.end(); ++i) {
2366 const std::string &name = *i;
2368 if(m_media.find(name) == m_media.end()) {
2369 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2370 <<"unknown file \""<<(name)<<"\""<<std::endl;
2374 //TODO get path + name
2375 std::string tpath = m_media[name].path;
2378 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2379 if(fis.good() == false){
2380 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2381 <<tpath<<"\" for reading"<<std::endl;
2384 std::ostringstream tmp_os(std::ios_base::binary);
2388 fis.read(buf, 1024);
2389 std::streamsize len = fis.gcount();
2390 tmp_os.write(buf, len);
2391 file_size_bunch_total += len;
2400 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2401 <<name<<"\""<<std::endl;
2404 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2405 <<tname<<"\""<<std::endl;*/
2407 file_bunches[file_bunches.size()-1].push_back(
2408 SendableMedia(name, tpath, tmp_os.str()));
2410 // Start next bunch if got enough data
2411 if(file_size_bunch_total >= bytes_per_bunch) {
2412 file_bunches.push_back(std::vector<SendableMedia>());
2413 file_size_bunch_total = 0;
2418 /* Create and send packets */
2420 u16 num_bunches = file_bunches.size();
2421 for(u16 i = 0; i < num_bunches; i++) {
2424 u16 total number of texture bunches
2425 u16 index of this bunch
2426 u32 number of files in this bunch
2435 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2436 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2438 for(std::vector<SendableMedia>::iterator
2439 j = file_bunches[i].begin();
2440 j != file_bunches[i].end(); ++j) {
2442 pkt->putLongString(j->data);
2445 verbosestream << "Server::sendRequestedMedia(): bunch "
2446 << i << "/" << num_bunches
2447 << " files=" << file_bunches[i].size()
2448 << " size=" << pkt->getSize() << std::endl;
2453 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2455 if(m_detached_inventories.count(name) == 0) {
2456 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2459 Inventory *inv = m_detached_inventories[name];
2460 std::ostringstream os(std::ios_base::binary);
2462 os << serializeString(name);
2466 std::string s = os.str();
2468 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2469 pkt->putRawString(s.c_str(), s.size());
2471 if (peer_id != PEER_ID_INEXISTENT) {
2475 m_clients.sendToAll(0, pkt, true);
2479 void Server::sendDetachedInventories(u16 peer_id)
2481 DSTACK(__FUNCTION_NAME);
2483 for(std::map<std::string, Inventory*>::iterator
2484 i = m_detached_inventories.begin();
2485 i != m_detached_inventories.end(); i++) {
2486 const std::string &name = i->first;
2487 //Inventory *inv = i->second;
2488 sendDetachedInventory(name, peer_id);
2496 void Server::DiePlayer(u16 peer_id)
2498 DSTACK(__FUNCTION_NAME);
2500 PlayerSAO *playersao = getPlayerSAO(peer_id);
2503 infostream << "Server::DiePlayer(): Player "
2504 << playersao->getPlayer()->getName()
2505 << " dies" << std::endl;
2507 playersao->setHP(0);
2509 // Trigger scripted stuff
2510 m_script->on_dieplayer(playersao);
2512 SendPlayerHP(peer_id);
2513 SendDeathscreen(peer_id, false, v3f(0,0,0));
2516 void Server::RespawnPlayer(u16 peer_id)
2518 DSTACK(__FUNCTION_NAME);
2520 PlayerSAO *playersao = getPlayerSAO(peer_id);
2523 infostream << "Server::RespawnPlayer(): Player "
2524 << playersao->getPlayer()->getName()
2525 << " respawns" << std::endl;
2527 playersao->setHP(PLAYER_MAX_HP);
2528 playersao->setBreath(PLAYER_MAX_BREATH);
2530 SendPlayerHP(peer_id);
2531 SendPlayerBreath(peer_id);
2533 bool repositioned = m_script->on_respawnplayer(playersao);
2535 v3f pos = findSpawnPos(m_env->getServerMap());
2536 // setPos will send the new position to client
2537 playersao->setPos(pos);
2541 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2543 DSTACK(__FUNCTION_NAME);
2545 SendAccessDenied(peer_id, reason, custom_reason);
2546 m_clients.event(peer_id, CSE_SetDenied);
2547 m_con.DisconnectPeer(peer_id);
2550 // 13/03/15: remove this function when protocol version 25 will become
2551 // the minimum version for MT users, maybe in 1 year
2552 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2554 DSTACK(__FUNCTION_NAME);
2556 SendAccessDenied_Legacy(peer_id, reason);
2557 m_clients.event(peer_id, CSE_SetDenied);
2558 m_con.DisconnectPeer(peer_id);
2561 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2563 DSTACK(__FUNCTION_NAME);
2564 std::wstring message;
2567 Clear references to playing sounds
2569 for(std::map<s32, ServerPlayingSound>::iterator
2570 i = m_playing_sounds.begin();
2571 i != m_playing_sounds.end();)
2573 ServerPlayingSound &psound = i->second;
2574 psound.clients.erase(peer_id);
2575 if(psound.clients.empty())
2576 m_playing_sounds.erase(i++);
2581 Player *player = m_env->getPlayer(peer_id);
2583 // Collect information about leaving in chat
2585 if(player != NULL && reason != CDR_DENY)
2587 std::wstring name = narrow_to_wide(player->getName());
2590 message += L" left the game.";
2591 if(reason == CDR_TIMEOUT)
2592 message += L" (timed out)";
2596 /* Run scripts and remove from environment */
2600 PlayerSAO *playersao = player->getPlayerSAO();
2603 m_script->on_leaveplayer(playersao);
2605 playersao->disconnected();
2613 if(player != NULL && reason != CDR_DENY) {
2614 std::ostringstream os(std::ios_base::binary);
2615 std::vector<u16> clients = m_clients.getClientIDs();
2617 for(std::vector<u16>::iterator i = clients.begin();
2618 i != clients.end(); ++i) {
2620 Player *player = m_env->getPlayer(*i);
2624 // Get name of player
2625 os << player->getName() << " ";
2628 actionstream << player->getName() << " "
2629 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2630 << " List of players: " << os.str() << std::endl;
2634 JMutexAutoLock env_lock(m_env_mutex);
2635 m_clients.DeleteClient(peer_id);
2639 // Send leave chat message to all remaining clients
2640 if(message.length() != 0)
2641 SendChatMessage(PEER_ID_INEXISTENT,message);
2644 void Server::UpdateCrafting(Player* player)
2646 DSTACK(__FUNCTION_NAME);
2648 // Get a preview for crafting
2650 InventoryLocation loc;
2651 loc.setPlayer(player->getName());
2652 getCraftingResult(&player->inventory, preview, false, this);
2653 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2655 // Put the new preview in
2656 InventoryList *plist = player->inventory.getList("craftpreview");
2657 sanity_check(plist);
2658 sanity_check(plist->getSize() >= 1);
2659 plist->changeItem(0, preview);
2662 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2664 RemoteClient *client = getClientNoEx(peer_id,state_min);
2666 throw ClientNotFoundException("Client not found");
2670 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2672 return m_clients.getClientNoEx(peer_id, state_min);
2675 std::string Server::getPlayerName(u16 peer_id)
2677 Player *player = m_env->getPlayer(peer_id);
2679 return "[id="+itos(peer_id)+"]";
2680 return player->getName();
2683 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2685 Player *player = m_env->getPlayer(peer_id);
2688 return player->getPlayerSAO();
2691 std::wstring Server::getStatusString()
2693 std::wostringstream os(std::ios_base::binary);
2696 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2698 os<<L", uptime="<<m_uptime.get();
2700 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2701 // Information about clients
2704 std::vector<u16> clients = m_clients.getClientIDs();
2705 for(std::vector<u16>::iterator i = clients.begin();
2706 i != clients.end(); ++i) {
2708 Player *player = m_env->getPlayer(*i);
2709 // Get name of player
2710 std::wstring name = L"unknown";
2712 name = narrow_to_wide(player->getName());
2713 // Add name to information string
2721 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2722 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2723 if(g_settings->get("motd") != "")
2724 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2728 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2730 std::set<std::string> privs;
2731 m_script->getAuth(name, NULL, &privs);
2735 bool Server::checkPriv(const std::string &name, const std::string &priv)
2737 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2738 return (privs.count(priv) != 0);
2741 void Server::reportPrivsModified(const std::string &name)
2744 std::vector<u16> clients = m_clients.getClientIDs();
2745 for(std::vector<u16>::iterator i = clients.begin();
2746 i != clients.end(); ++i) {
2747 Player *player = m_env->getPlayer(*i);
2748 reportPrivsModified(player->getName());
2751 Player *player = m_env->getPlayer(name.c_str());
2754 SendPlayerPrivileges(player->peer_id);
2755 PlayerSAO *sao = player->getPlayerSAO();
2758 sao->updatePrivileges(
2759 getPlayerEffectivePrivs(name),
2764 void Server::reportInventoryFormspecModified(const std::string &name)
2766 Player *player = m_env->getPlayer(name.c_str());
2769 SendPlayerInventoryFormspec(player->peer_id);
2772 void Server::setIpBanned(const std::string &ip, const std::string &name)
2774 m_banmanager->add(ip, name);
2777 void Server::unsetIpBanned(const std::string &ip_or_name)
2779 m_banmanager->remove(ip_or_name);
2782 std::string Server::getBanDescription(const std::string &ip_or_name)
2784 return m_banmanager->getBanDescription(ip_or_name);
2787 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2789 Player *player = m_env->getPlayer(name);
2793 if (player->peer_id == PEER_ID_INEXISTENT)
2796 SendChatMessage(player->peer_id, msg);
2799 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2801 Player *player = m_env->getPlayer(playername);
2805 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2809 SendShowFormspecMessage(player->peer_id, formspec, formname);
2813 u32 Server::hudAdd(Player *player, HudElement *form) {
2817 u32 id = player->addHud(form);
2819 SendHUDAdd(player->peer_id, id, form);
2824 bool Server::hudRemove(Player *player, u32 id) {
2828 HudElement* todel = player->removeHud(id);
2835 SendHUDRemove(player->peer_id, id);
2839 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2843 SendHUDChange(player->peer_id, id, stat, data);
2847 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2851 SendHUDSetFlags(player->peer_id, flags, mask);
2852 player->hud_flags = flags;
2854 PlayerSAO* playersao = player->getPlayerSAO();
2856 if (playersao == NULL)
2859 m_script->player_event(playersao, "hud_changed");
2863 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2866 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2869 std::ostringstream os(std::ios::binary);
2870 writeS32(os, hotbar_itemcount);
2871 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2875 void Server::hudSetHotbarImage(Player *player, std::string name) {
2879 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2882 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2886 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2889 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2894 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2898 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2903 SendEyeOffset(player->peer_id, first, third);
2907 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2908 const std::string &type, const std::vector<std::string> ¶ms)
2913 SendSetSky(player->peer_id, bgcolor, type, params);
2917 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2923 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2927 void Server::notifyPlayers(const std::wstring &msg)
2929 SendChatMessage(PEER_ID_INEXISTENT,msg);
2932 void Server::spawnParticle(const char *playername, v3f pos,
2933 v3f velocity, v3f acceleration,
2934 float expirationtime, float size, bool
2935 collisiondetection, bool vertical, std::string texture)
2937 Player *player = m_env->getPlayer(playername);
2940 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2941 expirationtime, size, collisiondetection, vertical, texture);
2944 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2945 float expirationtime, float size,
2946 bool collisiondetection, bool vertical, std::string texture)
2948 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2949 expirationtime, size, collisiondetection, vertical, texture);
2952 u32 Server::addParticleSpawner(const char *playername,
2953 u16 amount, float spawntime,
2954 v3f minpos, v3f maxpos,
2955 v3f minvel, v3f maxvel,
2956 v3f minacc, v3f maxacc,
2957 float minexptime, float maxexptime,
2958 float minsize, float maxsize,
2959 bool collisiondetection, bool vertical, std::string texture)
2961 Player *player = m_env->getPlayer(playername);
2966 for(;;) // look for unused particlespawner id
2969 if (std::find(m_particlespawner_ids.begin(),
2970 m_particlespawner_ids.end(), id)
2971 == m_particlespawner_ids.end())
2973 m_particlespawner_ids.push_back(id);
2978 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2979 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2980 minexptime, maxexptime, minsize, maxsize,
2981 collisiondetection, vertical, texture, id);
2986 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2987 v3f minpos, v3f maxpos,
2988 v3f minvel, v3f maxvel,
2989 v3f minacc, v3f maxacc,
2990 float minexptime, float maxexptime,
2991 float minsize, float maxsize,
2992 bool collisiondetection, bool vertical, std::string texture)
2995 for(;;) // look for unused particlespawner id
2998 if (std::find(m_particlespawner_ids.begin(),
2999 m_particlespawner_ids.end(), id)
3000 == m_particlespawner_ids.end())
3002 m_particlespawner_ids.push_back(id);
3007 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3008 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3009 minexptime, maxexptime, minsize, maxsize,
3010 collisiondetection, vertical, texture, id);
3015 void Server::deleteParticleSpawner(const char *playername, u32 id)
3017 Player *player = m_env->getPlayer(playername);
3021 m_particlespawner_ids.erase(
3022 std::remove(m_particlespawner_ids.begin(),
3023 m_particlespawner_ids.end(), id),
3024 m_particlespawner_ids.end());
3025 SendDeleteParticleSpawner(player->peer_id, id);
3028 void Server::deleteParticleSpawnerAll(u32 id)
3030 m_particlespawner_ids.erase(
3031 std::remove(m_particlespawner_ids.begin(),
3032 m_particlespawner_ids.end(), id),
3033 m_particlespawner_ids.end());
3034 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3037 Inventory* Server::createDetachedInventory(const std::string &name)
3039 if(m_detached_inventories.count(name) > 0){
3040 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3041 delete m_detached_inventories[name];
3043 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3045 Inventory *inv = new Inventory(m_itemdef);
3047 m_detached_inventories[name] = inv;
3048 //TODO find a better way to do this
3049 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3056 BoolScopeSet(bool *dst, bool val):
3059 m_orig_state = *m_dst;
3064 *m_dst = m_orig_state;
3071 // actions: time-reversed list
3072 // Return value: success/failure
3073 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3074 std::list<std::string> *log)
3076 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3077 ServerMap *map = (ServerMap*)(&m_env->getMap());
3079 // Fail if no actions to handle
3080 if(actions.empty()){
3081 log->push_back("Nothing to do.");
3088 for(std::list<RollbackAction>::const_iterator
3089 i = actions.begin();
3090 i != actions.end(); i++)
3092 const RollbackAction &action = *i;
3094 bool success = action.applyRevert(map, this, this);
3097 std::ostringstream os;
3098 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3099 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3101 log->push_back(os.str());
3103 std::ostringstream os;
3104 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3105 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3107 log->push_back(os.str());
3111 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3112 <<" failed"<<std::endl;
3114 // Call it done if less than half failed
3115 return num_failed <= num_tried/2;
3118 // IGameDef interface
3120 IItemDefManager* Server::getItemDefManager()
3124 INodeDefManager* Server::getNodeDefManager()
3128 ICraftDefManager* Server::getCraftDefManager()
3132 ITextureSource* Server::getTextureSource()
3136 IShaderSource* Server::getShaderSource()
3140 scene::ISceneManager* Server::getSceneManager()
3145 u16 Server::allocateUnknownNodeId(const std::string &name)
3147 return m_nodedef->allocateDummy(name);
3149 ISoundManager* Server::getSoundManager()
3151 return &dummySoundManager;
3153 MtEventManager* Server::getEventManager()
3158 IWritableItemDefManager* Server::getWritableItemDefManager()
3162 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3166 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3171 const ModSpec* Server::getModSpec(const std::string &modname)
3173 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3174 i != m_mods.end(); i++){
3175 const ModSpec &mod = *i;
3176 if(mod.name == modname)
3181 void Server::getModNames(std::vector<std::string> &modlist)
3183 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3184 modlist.push_back(i->name);
3187 std::string Server::getBuiltinLuaPath()
3189 return porting::path_share + DIR_DELIM + "builtin";
3192 v3f findSpawnPos(ServerMap &map)
3194 //return v3f(50,50,50)*BS;
3199 nodepos = v2s16(0,0);
3204 s16 water_level = map.getWaterLevel();
3206 // Try to find a good place a few times
3207 for(s32 i=0; i<1000; i++)
3210 // We're going to try to throw the player to this position
3211 v2s16 nodepos2d = v2s16(
3212 -range + (myrand() % (range * 2)),
3213 -range + (myrand() % (range * 2)));
3215 // Get ground height at point
3216 s16 groundheight = map.findGroundLevel(nodepos2d);
3217 if (groundheight <= water_level) // Don't go underwater
3219 if (groundheight > water_level + 6) // Don't go to high places
3222 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3223 bool is_good = false;
3225 for (s32 i = 0; i < 10; i++) {
3226 v3s16 blockpos = getNodeBlockPos(nodepos);
3227 map.emergeBlock(blockpos, true);
3228 content_t c = map.getNodeNoEx(nodepos).getContent();
3229 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3231 if (air_count >= 2){
3239 // Found a good place
3240 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3246 return intToFloat(nodepos, BS);
3249 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3251 bool newplayer = false;
3254 Try to get an existing player
3256 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3258 // If player is already connected, cancel
3259 if(player != NULL && player->peer_id != 0)
3261 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3266 If player with the wanted peer_id already exists, cancel.
3268 if(m_env->getPlayer(peer_id) != NULL)
3270 infostream<<"emergePlayer(): Player with wrong name but same"
3271 " peer_id already exists"<<std::endl;
3275 // Load player if it isn't already loaded
3277 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3280 // Create player if it doesn't exist
3283 player = new RemotePlayer(this, name);
3284 // Set player position
3285 infostream<<"Server: Finding spawn place for player \""
3286 <<name<<"\""<<std::endl;
3287 v3f pos = findSpawnPos(m_env->getServerMap());
3288 player->setPosition(pos);
3290 // Make sure the player is saved
3291 player->setModified(true);
3293 // Add player to environment
3294 m_env->addPlayer(player);
3297 // Create a new player active object
3298 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3299 getPlayerEffectivePrivs(player->getName()),
3302 /* Clean up old HUD elements from previous sessions */
3305 /* Add object to environment */
3306 m_env->addActiveObject(playersao);
3310 m_script->on_newplayer(playersao);
3316 void dedicated_server_loop(Server &server, bool &kill)
3318 DSTACK(__FUNCTION_NAME);
3320 verbosestream<<"dedicated_server_loop()"<<std::endl;
3322 IntervalLimiter m_profiler_interval;
3326 float steplen = g_settings->getFloat("dedicated_server_step");
3327 // This is kind of a hack but can be done like this
3328 // because server.step() is very light
3330 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3331 sleep_ms((int)(steplen*1000.0));
3333 server.step(steplen);
3335 if(server.getShutdownRequested() || kill)
3337 infostream<<"Dedicated server quitting"<<std::endl;
3339 if(g_settings->getBool("server_announce"))
3340 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3348 float profiler_print_interval =
3349 g_settings->getFloat("profiler_print_interval");
3350 if(profiler_print_interval != 0)
3352 if(m_profiler_interval.step(steplen, profiler_print_interval))
3354 infostream<<"Profiler:"<<std::endl;
3355 g_profiler->print(infostream);
3356 g_profiler->clear();