3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "jthread/jmutexautolock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_game.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_abm.h"
52 #include "content_sao.h"
54 #include "sound.h" // dummySoundManager
55 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "util/thread.h"
62 #include "defaultsettings.h"
63 #include "util/base64.h"
64 #include "util/sha1.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public JThread
81 ServerThread(Server *server):
90 void * ServerThread::Thread()
92 log_register_thread("ServerThread");
94 DSTACK(__FUNCTION_NAME);
95 BEGIN_DEBUG_EXCEPTION_HANDLER
97 m_server->AsyncRunStep(true);
101 porting::setThreadName("ServerThread");
103 while(!StopRequested())
106 //TimeTaker timer("AsyncRunStep() + Receive()");
108 m_server->AsyncRunStep();
113 catch(con::NoIncomingDataException &e)
116 catch(con::PeerNotFoundException &e)
118 infostream<<"Server: PeerNotFoundException"<<std::endl;
120 catch(ClientNotFoundException &e)
123 catch(con::ConnectionBindFailed &e)
125 m_server->setAsyncFatalError(e.what());
129 m_server->setAsyncFatalError(e.what());
133 END_DEBUG_EXCEPTION_HANDLER(errorstream)
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
140 if(pos_exists) *pos_exists = false;
145 if(pos_exists) *pos_exists = true;
150 ServerActiveObject *sao = env->getActiveObject(object);
153 if(pos_exists) *pos_exists = true;
154 return sao->getBasePosition(); }
166 const std::string &path_world,
167 const SubgameSpec &gamespec,
168 bool simple_singleplayer_mode,
171 m_path_world(path_world),
172 m_gamespec(gamespec),
173 m_simple_singleplayer_mode(simple_singleplayer_mode),
174 m_async_fatal_error(""),
183 m_enable_rollback_recording(false),
186 m_itemdef(createItemDefManager()),
187 m_nodedef(createNodeDefManager()),
188 m_craftdef(createCraftDefManager()),
189 m_event(new EventManager()),
191 m_time_of_day_send_timer(0),
194 m_shutdown_requested(false),
195 m_ignore_map_edit_events(false),
196 m_ignore_map_edit_events_peer_id(0),
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 ModConfiguration modconf(m_path_world);
247 m_mods = modconf.getMods();
248 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
249 // complain about mods with unsatisfied dependencies
250 if(!modconf.isConsistent())
252 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
253 it != unsatisfied_mods.end(); ++it)
256 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
257 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
258 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
259 errorstream << " \"" << *dep_it << "\"";
260 errorstream << std::endl;
264 Settings worldmt_settings;
265 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
266 worldmt_settings.readConfigFile(worldmt.c_str());
267 std::vector<std::string> names = worldmt_settings.getNames();
268 std::set<std::string> load_mod_names;
269 for(std::vector<std::string>::iterator it = names.begin();
270 it != names.end(); ++it)
272 std::string name = *it;
273 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
274 load_mod_names.insert(name.substr(9));
276 // complain about mods declared to be loaded, but not found
277 for(std::vector<ModSpec>::iterator it = m_mods.begin();
278 it != m_mods.end(); ++it)
279 load_mod_names.erase((*it).name);
280 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
281 it != unsatisfied_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 if(!load_mod_names.empty())
285 errorstream << "The following mods could not be found:";
286 for(std::set<std::string>::iterator it = load_mod_names.begin();
287 it != load_mod_names.end(); ++it)
288 errorstream << " \"" << (*it) << "\"";
289 errorstream << std::endl;
293 JMutexAutoLock envlock(m_env_mutex);
295 // Load mapgen params from Settings
296 m_emerge->loadMapgenParams();
298 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
299 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
301 // Initialize scripting
302 infostream<<"Server: Initializing Lua"<<std::endl;
304 m_script = new GameScripting(this);
306 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
308 if (!m_script->loadScript(scriptpath))
309 throw ModError("Failed to load and run " + scriptpath);
312 infostream<<"Server: Loading mods: ";
313 for(std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++){
315 const ModSpec &mod = *i;
316 infostream<<mod.name<<" ";
318 infostream<<std::endl;
319 // Load and run "mod" scripts
320 for(std::vector<ModSpec>::iterator i = m_mods.begin();
321 i != m_mods.end(); i++){
322 const ModSpec &mod = *i;
323 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
324 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
325 <<scriptpath<<"\"]"<<std::endl;
326 bool success = m_script->loadMod(scriptpath, mod.name);
328 errorstream<<"Server: Failed to load and run "
329 <<scriptpath<<std::endl;
330 throw ModError("Failed to load and run "+scriptpath);
334 // Read Textures and calculate sha1 sums
337 // Apply item aliases in the node definition manager
338 m_nodedef->updateAliases(m_itemdef);
340 m_nodedef->setNodeRegistrationStatus(true);
342 // Perform pending node name resolutions
343 m_nodedef->runNodeResolverCallbacks();
345 // Initialize Environment
346 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
348 m_clients.setEnv(m_env);
350 // Initialize mapgens
351 m_emerge->initMapgens();
353 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
354 if (m_enable_rollback_recording) {
355 // Create rollback manager
356 m_rollback = new RollbackManager(m_path_world, this);
359 // Give environment reference to scripting api
360 m_script->initializeEnvironment(m_env);
362 // Register us to receive map edit events
363 servermap->addEventReceiver(this);
365 // If file exists, load environment metadata
366 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
368 infostream<<"Server: Loading environment metadata"<<std::endl;
372 // Add some test ActiveBlockModifiers to environment
373 add_legacy_abms(m_env, m_nodedef);
375 m_liquid_transform_every = g_settings->getFloat("liquid_update");
380 infostream<<"Server destructing"<<std::endl;
382 // Send shutdown message
383 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
386 JMutexAutoLock envlock(m_env_mutex);
388 // Execute script shutdown hooks
389 m_script->on_shutdown();
391 infostream<<"Server: Saving players"<<std::endl;
392 m_env->saveLoadedPlayers();
394 infostream<<"Server: Saving environment metadata"<<std::endl;
402 // stop all emerge threads before deleting players that may have
403 // requested blocks to be emerged
404 m_emerge->stopThreads();
406 // Delete things in the reverse order of creation
409 // N.B. the EmergeManager should be deleted after the Environment since Map
410 // depends on EmergeManager to write its current params to the map meta
419 // Deinitialize scripting
420 infostream<<"Server: Deinitializing scripting"<<std::endl;
423 // Delete detached inventories
424 for (std::map<std::string, Inventory*>::iterator
425 i = m_detached_inventories.begin();
426 i != m_detached_inventories.end(); i++) {
431 void Server::start(Address bind_addr)
433 DSTACK(__FUNCTION_NAME);
435 m_bind_addr = bind_addr;
437 infostream<<"Starting server on "
438 << bind_addr.serializeString() <<"..."<<std::endl;
440 // Stop thread if already running
443 // Initialize connection
444 m_con.SetTimeoutMs(30);
445 m_con.Serve(bind_addr);
450 // ASCII art for the win!
452 <<" .__ __ __ "<<std::endl
453 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
454 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
455 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
456 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
457 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
458 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
459 actionstream<<"Server for gameid=\""<<m_gamespec.id
460 <<"\" listening on "<<bind_addr.serializeString()<<":"
461 <<bind_addr.getPort() << "."<<std::endl;
466 DSTACK(__FUNCTION_NAME);
468 infostream<<"Server: Stopping and waiting threads"<<std::endl;
470 // Stop threads (set run=false first so both start stopping)
472 //m_emergethread.setRun(false);
474 //m_emergethread.stop();
476 infostream<<"Server: Threads stopped"<<std::endl;
479 void Server::step(float dtime)
481 DSTACK(__FUNCTION_NAME);
486 JMutexAutoLock lock(m_step_dtime_mutex);
487 m_step_dtime += dtime;
489 // Throw if fatal error occurred in thread
490 std::string async_err = m_async_fatal_error.get();
492 throw ServerError(async_err);
496 void Server::AsyncRunStep(bool initial_step)
498 DSTACK(__FUNCTION_NAME);
500 g_profiler->add("Server::AsyncRunStep (num)", 1);
504 JMutexAutoLock lock1(m_step_dtime_mutex);
505 dtime = m_step_dtime;
509 // Send blocks to clients
513 if((dtime < 0.001) && (initial_step == false))
516 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
518 //infostream<<"Server steps "<<dtime<<std::endl;
519 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
522 JMutexAutoLock lock1(m_step_dtime_mutex);
523 m_step_dtime -= dtime;
530 m_uptime.set(m_uptime.get() + dtime);
536 Update time of day and overall game time
539 JMutexAutoLock envlock(m_env_mutex);
541 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
544 Send to clients at constant intervals
547 m_time_of_day_send_timer -= dtime;
548 if(m_time_of_day_send_timer < 0.0)
550 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
551 u16 time = m_env->getTimeOfDay();
552 float time_speed = g_settings->getFloat("time_speed");
553 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
558 JMutexAutoLock lock(m_env_mutex);
559 // Figure out and report maximum lag to environment
560 float max_lag = m_env->getMaxLagEstimate();
561 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
563 if(dtime > 0.1 && dtime > max_lag * 2.0)
564 infostream<<"Server: Maximum lag peaked to "<<dtime
568 m_env->reportMaxLagEstimate(max_lag);
570 ScopeProfiler sp(g_profiler, "SEnv step");
571 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
575 static const float map_timer_and_unload_dtime = 2.92;
576 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
578 JMutexAutoLock lock(m_env_mutex);
579 // Run Map's timers and unload unused data
580 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
581 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
582 g_settings->getFloat("server_unload_unused_data_timeout"));
593 JMutexAutoLock lock(m_env_mutex);
595 std::list<u16> clientids = m_clients.getClientIDs();
597 ScopeProfiler sp(g_profiler, "Server: handle players");
599 for(std::list<u16>::iterator
600 i = clientids.begin();
601 i != clientids.end(); ++i)
603 PlayerSAO *playersao = getPlayerSAO(*i);
604 if(playersao == NULL)
608 if(playersao->m_moved) {
610 playersao->m_moved = false;
614 Send player inventories if necessary
616 if(playersao->m_inventory_not_sent) {
623 /* Transform liquids */
624 m_liquid_transform_timer += dtime;
625 if(m_liquid_transform_timer >= m_liquid_transform_every)
627 m_liquid_transform_timer -= m_liquid_transform_every;
629 JMutexAutoLock lock(m_env_mutex);
631 ScopeProfiler sp(g_profiler, "Server: liquid transform");
633 std::map<v3s16, MapBlock*> modified_blocks;
634 m_env->getMap().transformLiquids(modified_blocks);
639 core::map<v3s16, MapBlock*> lighting_modified_blocks;
640 ServerMap &map = ((ServerMap&)m_env->getMap());
641 map.updateLighting(modified_blocks, lighting_modified_blocks);
643 // Add blocks modified by lighting to modified_blocks
644 for(core::map<v3s16, MapBlock*>::Iterator
645 i = lighting_modified_blocks.getIterator();
646 i.atEnd() == false; i++)
648 MapBlock *block = i.getNode()->getValue();
649 modified_blocks.insert(block->getPos(), block);
653 Set the modified blocks unsent for all the clients
655 if(!modified_blocks.empty())
657 SetBlocksNotSent(modified_blocks);
660 m_clients.step(dtime);
662 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
664 // send masterserver announce
666 float &counter = m_masterserver_timer;
667 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
668 g_settings->getBool("server_announce"))
670 ServerList::sendAnnounce(counter ? "update" : "start",
671 m_bind_addr.getPort(),
672 m_clients.getPlayerNames(),
674 m_env->getGameTime(),
677 m_emerge->params.mg_name,
686 Check added and deleted active objects
689 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
690 JMutexAutoLock envlock(m_env_mutex);
693 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
694 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
696 // Radius inside which objects are active
697 s16 radius = g_settings->getS16("active_object_send_range_blocks");
698 s16 player_radius = g_settings->getS16("player_transfer_distance");
700 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
701 !g_settings->getBool("unlimited_player_transfer_distance"))
702 player_radius = radius;
704 radius *= MAP_BLOCKSIZE;
705 player_radius *= MAP_BLOCKSIZE;
707 for(std::map<u16, RemoteClient*>::iterator
709 i != clients.end(); ++i)
711 RemoteClient *client = i->second;
713 // If definitions and textures have not been sent, don't
714 // send objects either
715 if (client->getState() < CS_DefinitionsSent)
718 Player *player = m_env->getPlayer(client->peer_id);
721 // This can happen if the client timeouts somehow
722 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
724 <<" has no associated player"<<std::endl;*/
727 v3s16 pos = floatToInt(player->getPosition(), BS);
729 std::set<u16> removed_objects;
730 std::set<u16> added_objects;
731 m_env->getRemovedActiveObjects(pos, radius, player_radius,
732 client->m_known_objects, removed_objects);
733 m_env->getAddedActiveObjects(pos, radius, player_radius,
734 client->m_known_objects, added_objects);
736 // Ignore if nothing happened
737 if(removed_objects.empty() && added_objects.empty())
739 //infostream<<"active objects: none changed"<<std::endl;
743 std::string data_buffer;
747 // Handle removed objects
748 writeU16((u8*)buf, removed_objects.size());
749 data_buffer.append(buf, 2);
750 for(std::set<u16>::iterator
751 i = removed_objects.begin();
752 i != removed_objects.end(); ++i)
756 ServerActiveObject* obj = m_env->getActiveObject(id);
758 // Add to data buffer for sending
759 writeU16((u8*)buf, id);
760 data_buffer.append(buf, 2);
762 // Remove from known objects
763 client->m_known_objects.erase(id);
765 if(obj && obj->m_known_by_count > 0)
766 obj->m_known_by_count--;
769 // Handle added objects
770 writeU16((u8*)buf, added_objects.size());
771 data_buffer.append(buf, 2);
772 for(std::set<u16>::iterator
773 i = added_objects.begin();
774 i != added_objects.end(); ++i)
778 ServerActiveObject* obj = m_env->getActiveObject(id);
781 u8 type = ACTIVEOBJECT_TYPE_INVALID;
783 infostream<<"WARNING: "<<__FUNCTION_NAME
784 <<": NULL object"<<std::endl;
786 type = obj->getSendType();
788 // Add to data buffer for sending
789 writeU16((u8*)buf, id);
790 data_buffer.append(buf, 2);
791 writeU8((u8*)buf, type);
792 data_buffer.append(buf, 1);
795 data_buffer.append(serializeLongString(
796 obj->getClientInitializationData(client->net_proto_version)));
798 data_buffer.append(serializeLongString(""));
800 // Add to known objects
801 client->m_known_objects.insert(id);
804 obj->m_known_by_count++;
807 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
808 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
811 verbosestream << "Server: Sent object remove/add: "
812 << removed_objects.size() << " removed, "
813 << added_objects.size() << " added, "
814 << "packet size is " << pkt->getSize() << std::endl;
825 JMutexAutoLock envlock(m_env_mutex);
826 ScopeProfiler sp(g_profiler, "Server: sending object messages");
829 // Value = data sent by object
830 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
832 // Get active object messages from environment
835 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
839 std::list<ActiveObjectMessage>* message_list = NULL;
840 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
841 n = buffered_messages.find(aom.id);
842 if(n == buffered_messages.end())
844 message_list = new std::list<ActiveObjectMessage>;
845 buffered_messages[aom.id] = message_list;
849 message_list = n->second;
851 message_list->push_back(aom);
855 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
856 // Route data to every client
857 for(std::map<u16, RemoteClient*>::iterator
859 i != clients.end(); ++i)
861 RemoteClient *client = i->second;
862 std::string reliable_data;
863 std::string unreliable_data;
864 // Go through all objects in message buffer
865 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
866 j = buffered_messages.begin();
867 j != buffered_messages.end(); ++j)
869 // If object is not known by client, skip it
871 if(client->m_known_objects.find(id) == client->m_known_objects.end())
873 // Get message list of object
874 std::list<ActiveObjectMessage>* list = j->second;
875 // Go through every message
876 for(std::list<ActiveObjectMessage>::iterator
877 k = list->begin(); k != list->end(); ++k)
879 // Compose the full new data with header
880 ActiveObjectMessage aom = *k;
881 std::string new_data;
884 writeU16((u8*)&buf[0], aom.id);
885 new_data.append(buf, 2);
887 new_data += serializeString(aom.datastring);
888 // Add data to buffer
890 reliable_data += new_data;
892 unreliable_data += new_data;
896 reliable_data and unreliable_data are now ready.
899 if(reliable_data.size() > 0) {
900 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
903 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
907 if(unreliable_data.size() > 0) {
908 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
911 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
917 // Clear buffered_messages
918 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
919 i = buffered_messages.begin();
920 i != buffered_messages.end(); ++i)
927 Send queued-for-sending map edit events.
930 // We will be accessing the environment
931 JMutexAutoLock lock(m_env_mutex);
933 // Don't send too many at a time
936 // Single change sending is disabled if queue size is not small
937 bool disable_single_change_sending = false;
938 if(m_unsent_map_edit_queue.size() >= 4)
939 disable_single_change_sending = true;
941 int event_count = m_unsent_map_edit_queue.size();
943 // We'll log the amount of each
946 while(m_unsent_map_edit_queue.size() != 0)
948 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
950 // Players far away from the change are stored here.
951 // Instead of sending the changes, MapBlocks are set not sent
953 std::list<u16> far_players;
955 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
957 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
958 prof.add("MEET_ADDNODE", 1);
959 if(disable_single_change_sending)
960 sendAddNode(event->p, event->n, event->already_known_by_peer,
961 &far_players, 5, event->type == MEET_ADDNODE);
963 sendAddNode(event->p, event->n, event->already_known_by_peer,
964 &far_players, 30, event->type == MEET_ADDNODE);
966 else if(event->type == MEET_REMOVENODE)
968 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
969 prof.add("MEET_REMOVENODE", 1);
970 if(disable_single_change_sending)
971 sendRemoveNode(event->p, event->already_known_by_peer,
974 sendRemoveNode(event->p, event->already_known_by_peer,
977 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
979 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
980 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
981 setBlockNotSent(event->p);
983 else if(event->type == MEET_OTHER)
985 infostream<<"Server: MEET_OTHER"<<std::endl;
986 prof.add("MEET_OTHER", 1);
987 for(std::set<v3s16>::iterator
988 i = event->modified_blocks.begin();
989 i != event->modified_blocks.end(); ++i)
996 prof.add("unknown", 1);
997 infostream<<"WARNING: Server: Unknown MapEditEvent "
998 <<((u32)event->type)<<std::endl;
1002 Set blocks not sent to far players
1004 if(!far_players.empty())
1006 // Convert list format to that wanted by SetBlocksNotSent
1007 std::map<v3s16, MapBlock*> modified_blocks2;
1008 for(std::set<v3s16>::iterator
1009 i = event->modified_blocks.begin();
1010 i != event->modified_blocks.end(); ++i)
1012 modified_blocks2[*i] =
1013 m_env->getMap().getBlockNoCreateNoEx(*i);
1015 // Set blocks not sent
1016 for(std::list<u16>::iterator
1017 i = far_players.begin();
1018 i != far_players.end(); ++i)
1021 RemoteClient *client = getClient(peer_id);
1024 client->SetBlocksNotSent(modified_blocks2);
1030 /*// Don't send too many at a time
1032 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1036 if(event_count >= 5){
1037 infostream<<"Server: MapEditEvents:"<<std::endl;
1038 prof.print(infostream);
1039 } else if(event_count != 0){
1040 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1041 prof.print(verbosestream);
1047 Trigger emergethread (it somehow gets to a non-triggered but
1048 bysy state sometimes)
1051 float &counter = m_emergethread_trigger_timer;
1057 m_emerge->startThreads();
1061 // Save map, players and auth stuff
1063 float &counter = m_savemap_timer;
1065 if(counter >= g_settings->getFloat("server_map_save_interval"))
1068 JMutexAutoLock lock(m_env_mutex);
1070 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1073 if (m_banmanager->isModified()) {
1074 m_banmanager->save();
1077 // Save changed parts of map
1078 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1081 m_env->saveLoadedPlayers();
1083 // Save environment metadata
1089 void Server::Receive()
1091 DSTACK(__FUNCTION_NAME);
1092 SharedBuffer<u8> data;
1096 datasize = m_con.Receive(peer_id,data);
1097 ProcessData(*data, datasize, peer_id);
1099 catch(con::InvalidIncomingDataException &e) {
1100 infostream<<"Server::Receive(): "
1101 "InvalidIncomingDataException: what()="
1102 <<e.what()<<std::endl;
1104 catch(SerializationError &e) {
1105 infostream<<"Server::Receive(): "
1106 "SerializationError: what()="
1107 <<e.what()<<std::endl;
1109 catch(ClientStateError &e) {
1110 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1111 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1112 L"Try reconnecting or updating your client");
1114 catch(con::PeerNotFoundException &e) {
1119 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1121 std::string playername = "";
1122 PlayerSAO *playersao = NULL;
1125 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1126 if (client != NULL) {
1127 playername = client->getName();
1128 playersao = emergePlayer(playername.c_str(), peer_id);
1130 } catch (std::exception &e) {
1136 RemotePlayer *player =
1137 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1139 // If failed, cancel
1140 if((playersao == NULL) || (player == NULL)) {
1141 if(player && player->peer_id != 0) {
1142 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1143 <<" (player allocated to an another client)"<<std::endl;
1144 DenyAccess(peer_id, L"Another client is connected with this "
1145 L"name. If your client closed unexpectedly, try again in "
1148 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1150 DenyAccess(peer_id, L"Could not allocate player.");
1156 Send complete position information
1158 SendMovePlayer(peer_id);
1161 SendPlayerPrivileges(peer_id);
1163 // Send inventory formspec
1164 SendPlayerInventoryFormspec(peer_id);
1167 UpdateCrafting(peer_id);
1168 SendInventory(peer_id);
1171 if(g_settings->getBool("enable_damage"))
1172 SendPlayerHP(peer_id);
1175 SendPlayerBreath(peer_id);
1177 // Show death screen if necessary
1179 SendDeathscreen(peer_id, false, v3f(0,0,0));
1181 // Note things in chat if not in simple singleplayer mode
1182 if(!m_simple_singleplayer_mode) {
1183 // Send information about server to player in chat
1184 SendChatMessage(peer_id, getStatusString());
1186 // Send information about joining in chat
1188 std::wstring name = L"unknown";
1189 Player *player = m_env->getPlayer(peer_id);
1191 name = narrow_to_wide(player->getName());
1193 std::wstring message;
1196 message += L" joined the game.";
1197 SendChatMessage(PEER_ID_INEXISTENT,message);
1200 Address addr = getPeerAddress(player->peer_id);
1201 std::string ip_str = addr.serializeString();
1202 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1207 std::vector<std::string> names = m_clients.getPlayerNames();
1209 actionstream<<player->getName() <<" joins game. List of players: ";
1211 for (std::vector<std::string>::iterator i = names.begin();
1212 i != names.end(); i++) {
1213 actionstream << *i << " ";
1216 actionstream << player->getName() <<std::endl;
1221 inline void Server::handleCommand(NetworkPacket* pkt)
1223 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1224 (this->*opHandle.handler)(pkt);
1227 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1229 DSTACK(__FUNCTION_NAME);
1230 // Environment is locked first.
1231 JMutexAutoLock envlock(m_env_mutex);
1233 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1236 Address address = getPeerAddress(peer_id);
1237 std::string addr_s = address.serializeString();
1239 if(m_banmanager->isIpBanned(addr_s)) {
1240 std::string ban_name = m_banmanager->getBanName(addr_s);
1241 infostream << "Server: A banned client tried to connect from "
1242 << addr_s << "; banned name was "
1243 << ban_name << std::endl;
1244 // This actually doesn't seem to transfer to the client
1245 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1246 + narrow_to_wide(ban_name));
1250 catch(con::PeerNotFoundException &e) {
1252 * no peer for this packet found
1253 * most common reason is peer timeout, e.g. peer didn't
1254 * respond for some time, your server was overloaded or
1257 infostream << "Server::ProcessData(): Cancelling: peer "
1258 << peer_id << " not found" << std::endl;
1266 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1268 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1270 // Command must be handled into ToServerCommandHandler
1271 if (command >= TOSERVER_NUM_MSG_TYPES) {
1272 infostream << "Server: Ignoring unknown command "
1273 << command << std::endl;
1276 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1282 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1284 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1285 errorstream << "Server::ProcessData(): Cancelling: Peer"
1286 " serialization format invalid or not initialized."
1287 " Skipping incoming command=" << command << std::endl;
1293 /* Handle commands related to client startup */
1294 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1300 if (m_clients.getClientState(peer_id) < CS_Active) {
1301 if (command == TOSERVER_PLAYERPOS) return;
1303 errorstream << "Got packet command: " << command << " for peer id "
1304 << peer_id << " but client isn't active yet. Dropping packet "
1315 catch(SendFailedException &e) {
1316 errorstream << "Server::ProcessData(): SendFailedException: "
1317 << "what=" << e.what()
1322 void Server::setTimeOfDay(u32 time)
1324 m_env->setTimeOfDay(time);
1325 m_time_of_day_send_timer = 0;
1328 void Server::onMapEditEvent(MapEditEvent *event)
1330 if(m_ignore_map_edit_events)
1332 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1334 MapEditEvent *e = event->clone();
1335 m_unsent_map_edit_queue.push_back(e);
1338 Inventory* Server::getInventory(const InventoryLocation &loc)
1341 case InventoryLocation::UNDEFINED:
1342 case InventoryLocation::CURRENT_PLAYER:
1344 case InventoryLocation::PLAYER:
1346 Player *player = m_env->getPlayer(loc.name.c_str());
1349 PlayerSAO *playersao = player->getPlayerSAO();
1352 return playersao->getInventory();
1355 case InventoryLocation::NODEMETA:
1357 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1360 return meta->getInventory();
1363 case InventoryLocation::DETACHED:
1365 if(m_detached_inventories.count(loc.name) == 0)
1367 return m_detached_inventories[loc.name];
1375 void Server::setInventoryModified(const InventoryLocation &loc)
1378 case InventoryLocation::UNDEFINED:
1380 case InventoryLocation::PLAYER:
1382 Player *player = m_env->getPlayer(loc.name.c_str());
1385 PlayerSAO *playersao = player->getPlayerSAO();
1388 playersao->m_inventory_not_sent = true;
1389 playersao->m_wielded_item_not_sent = true;
1392 case InventoryLocation::NODEMETA:
1394 v3s16 blockpos = getNodeBlockPos(loc.p);
1396 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1398 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1400 setBlockNotSent(blockpos);
1403 case InventoryLocation::DETACHED:
1405 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1413 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1415 std::list<u16> clients = m_clients.getClientIDs();
1417 // Set the modified blocks unsent for all the clients
1418 for (std::list<u16>::iterator
1419 i = clients.begin();
1420 i != clients.end(); ++i) {
1421 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
1423 client->SetBlocksNotSent(block);
1428 void Server::peerAdded(con::Peer *peer)
1430 DSTACK(__FUNCTION_NAME);
1431 verbosestream<<"Server::peerAdded(): peer->id="
1432 <<peer->id<<std::endl;
1435 c.type = con::PEER_ADDED;
1436 c.peer_id = peer->id;
1438 m_peer_change_queue.push_back(c);
1441 void Server::deletingPeer(con::Peer *peer, bool timeout)
1443 DSTACK(__FUNCTION_NAME);
1444 verbosestream<<"Server::deletingPeer(): peer->id="
1445 <<peer->id<<", timeout="<<timeout<<std::endl;
1447 m_clients.event(peer->id, CSE_Disconnect);
1449 c.type = con::PEER_REMOVED;
1450 c.peer_id = peer->id;
1451 c.timeout = timeout;
1452 m_peer_change_queue.push_back(c);
1455 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1457 *retval = m_con.getPeerStat(peer_id,type);
1458 if (*retval == -1) return false;
1462 bool Server::getClientInfo(
1471 std::string* vers_string
1474 *state = m_clients.getClientState(peer_id);
1476 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1478 if (client == NULL) {
1483 *uptime = client->uptime();
1484 *ser_vers = client->serialization_version;
1485 *prot_vers = client->net_proto_version;
1487 *major = client->getMajor();
1488 *minor = client->getMinor();
1489 *patch = client->getPatch();
1490 *vers_string = client->getPatch();
1497 void Server::handlePeerChanges()
1499 while(m_peer_change_queue.size() > 0)
1501 con::PeerChange c = m_peer_change_queue.pop_front();
1503 verbosestream<<"Server: Handling peer change: "
1504 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1509 case con::PEER_ADDED:
1510 m_clients.CreateClient(c.peer_id);
1513 case con::PEER_REMOVED:
1514 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1518 assert("Invalid peer change event received!" == 0);
1524 void Server::Send(NetworkPacket* pkt)
1526 m_clients.send(pkt->getPeerId(),
1527 clientCommandFactoryTable[pkt->getCommand()].channel,
1529 clientCommandFactoryTable[pkt->getCommand()].reliable);
1532 void Server::SendMovement(u16 peer_id)
1534 DSTACK(__FUNCTION_NAME);
1535 std::ostringstream os(std::ios_base::binary);
1537 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1539 *pkt << g_settings->getFloat("movement_acceleration_default");
1540 *pkt << g_settings->getFloat("movement_acceleration_air");
1541 *pkt << g_settings->getFloat("movement_acceleration_fast");
1542 *pkt << g_settings->getFloat("movement_speed_walk");
1543 *pkt << g_settings->getFloat("movement_speed_crouch");
1544 *pkt << g_settings->getFloat("movement_speed_fast");
1545 *pkt << g_settings->getFloat("movement_speed_climb");
1546 *pkt << g_settings->getFloat("movement_speed_jump");
1547 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1548 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1549 *pkt << g_settings->getFloat("movement_liquid_sink");
1550 *pkt << g_settings->getFloat("movement_gravity");
1555 void Server::SendHP(u16 peer_id, u8 hp)
1557 DSTACK(__FUNCTION_NAME);
1559 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1564 void Server::SendBreath(u16 peer_id, u16 breath)
1566 DSTACK(__FUNCTION_NAME);
1568 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1569 *pkt << (u16) breath;
1573 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1575 DSTACK(__FUNCTION_NAME);
1577 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1582 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1583 v3f camera_point_target)
1585 DSTACK(__FUNCTION_NAME);
1587 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1588 *pkt << set_camera_point_target << camera_point_target;
1592 void Server::SendItemDef(u16 peer_id,
1593 IItemDefManager *itemdef, u16 protocol_version)
1595 DSTACK(__FUNCTION_NAME);
1597 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1601 u32 length of the next item
1602 zlib-compressed serialized ItemDefManager
1604 std::ostringstream tmp_os(std::ios::binary);
1605 itemdef->serialize(tmp_os, protocol_version);
1606 std::ostringstream tmp_os2(std::ios::binary);
1607 compressZlib(tmp_os.str(), tmp_os2);
1608 pkt->putLongString(tmp_os2.str());
1611 verbosestream << "Server: Sending item definitions to id(" << peer_id
1612 << "): size=" << pkt->getSize() << std::endl;
1617 void Server::SendNodeDef(u16 peer_id,
1618 INodeDefManager *nodedef, u16 protocol_version)
1620 DSTACK(__FUNCTION_NAME);
1622 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1626 u32 length of the next item
1627 zlib-compressed serialized NodeDefManager
1629 std::ostringstream tmp_os(std::ios::binary);
1630 nodedef->serialize(tmp_os, protocol_version);
1631 std::ostringstream tmp_os2(std::ios::binary);
1632 compressZlib(tmp_os.str(), tmp_os2);
1634 pkt->putLongString(tmp_os2.str());
1637 verbosestream << "Server: Sending node definitions to id(" << peer_id
1638 << "): size=" << pkt->getSize() << std::endl;
1644 Non-static send methods
1647 void Server::SendInventory(u16 peer_id)
1649 DSTACK(__FUNCTION_NAME);
1651 PlayerSAO *playersao = getPlayerSAO(peer_id);
1654 playersao->m_inventory_not_sent = false;
1660 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0, peer_id);
1662 std::ostringstream os;
1663 playersao->getInventory()->serialize(os);
1665 std::string s = os.str();
1667 pkt->putRawString(s.c_str(), s.size());
1671 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1673 DSTACK(__FUNCTION_NAME);
1675 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1678 if (peer_id != PEER_ID_INEXISTENT) {
1682 m_clients.sendToAll(0,pkt,true);
1686 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1687 const std::string &formname)
1689 DSTACK(__FUNCTION_NAME);
1691 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1693 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1699 // Spawns a particle on peer with peer_id
1700 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1701 float expirationtime, float size, bool collisiondetection,
1702 bool vertical, std::string texture)
1704 DSTACK(__FUNCTION_NAME);
1706 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1708 *pkt << pos << velocity << acceleration << expirationtime
1709 << size << collisiondetection;
1710 pkt->putLongString(texture);
1713 if (peer_id != PEER_ID_INEXISTENT) {
1717 m_clients.sendToAll(0,pkt,true);
1721 // Adds a ParticleSpawner on peer with peer_id
1722 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1723 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1724 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1726 DSTACK(__FUNCTION_NAME);
1728 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1730 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1731 << minacc << maxacc << minexptime << maxexptime << minsize
1732 << maxsize << collisiondetection;
1734 pkt->putLongString(texture);
1736 *pkt << id << vertical;
1738 if (peer_id != PEER_ID_INEXISTENT) {
1742 m_clients.sendToAll(0, pkt, true);
1746 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1748 DSTACK(__FUNCTION_NAME);
1750 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1752 // Ugly error in this packet
1755 if (peer_id != PEER_ID_INEXISTENT) {
1759 m_clients.sendToAll(0, pkt, true);
1764 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1766 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1768 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1769 << form->text << form->number << form->item << form->dir
1770 << form->align << form->offset << form->world_pos << form->size;
1775 void Server::SendHUDRemove(u16 peer_id, u32 id)
1777 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1782 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1784 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1785 *pkt << id << (u8) stat;
1789 case HUD_STAT_SCALE:
1790 case HUD_STAT_ALIGN:
1791 case HUD_STAT_OFFSET:
1792 *pkt << *(v2f *) value;
1796 *pkt << *(std::string *) value;
1798 case HUD_STAT_WORLD_POS:
1799 *pkt << *(v3f *) value;
1802 *pkt << *(v2s32 *) value;
1804 case HUD_STAT_NUMBER:
1808 *pkt << *(u32 *) value;
1815 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1817 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1819 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1821 *pkt << flags << mask;
1826 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1828 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1829 *pkt << param << value;
1833 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1834 const std::string &type, const std::vector<std::string> ¶ms)
1836 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1837 *pkt << bgcolor << type << (u16) params.size();
1839 for(size_t i=0; i<params.size(); i++)
1845 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1848 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1851 *pkt << do_override << (u16) (ratio * 65535);
1856 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1858 DSTACK(__FUNCTION_NAME);
1860 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1861 *pkt << time << time_speed;
1863 if (peer_id == PEER_ID_INEXISTENT) {
1864 m_clients.sendToAll(0, pkt, true);
1871 void Server::SendPlayerHP(u16 peer_id)
1873 DSTACK(__FUNCTION_NAME);
1874 PlayerSAO *playersao = getPlayerSAO(peer_id);
1876 SendHP(peer_id, playersao->getHP());
1877 m_script->player_event(playersao,"health_changed");
1879 // Send to other clients
1880 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1881 ActiveObjectMessage aom(playersao->getId(), true, str);
1882 playersao->m_messages_out.push_back(aom);
1885 void Server::SendPlayerBreath(u16 peer_id)
1887 DSTACK(__FUNCTION_NAME);
1888 PlayerSAO *playersao = getPlayerSAO(peer_id);
1891 m_script->player_event(playersao, "breath_changed");
1892 SendBreath(peer_id, playersao->getBreath());
1895 void Server::SendMovePlayer(u16 peer_id)
1897 DSTACK(__FUNCTION_NAME);
1898 Player *player = m_env->getPlayer(peer_id);
1901 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1902 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1905 v3f pos = player->getPosition();
1906 f32 pitch = player->getPitch();
1907 f32 yaw = player->getYaw();
1908 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1909 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1918 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1920 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1923 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1924 << animation_frames[3] << animation_speed;
1929 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1931 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1932 *pkt << first << third;
1935 void Server::SendPlayerPrivileges(u16 peer_id)
1937 Player *player = m_env->getPlayer(peer_id);
1939 if(player->peer_id == PEER_ID_INEXISTENT)
1942 std::set<std::string> privs;
1943 m_script->getAuth(player->getName(), NULL, &privs);
1945 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1946 *pkt << (u16) privs.size();
1948 for(std::set<std::string>::const_iterator i = privs.begin();
1949 i != privs.end(); i++) {
1956 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1958 Player *player = m_env->getPlayer(peer_id);
1960 if(player->peer_id == PEER_ID_INEXISTENT)
1963 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1964 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1968 s32 Server::playSound(const SimpleSoundSpec &spec,
1969 const ServerSoundParams ¶ms)
1971 // Find out initial position of sound
1972 bool pos_exists = false;
1973 v3f pos = params.getPos(m_env, &pos_exists);
1974 // If position is not found while it should be, cancel sound
1975 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1978 // Filter destination clients
1979 std::list<u16> dst_clients;
1980 if(params.to_player != "")
1982 Player *player = m_env->getPlayer(params.to_player.c_str());
1984 infostream<<"Server::playSound: Player \""<<params.to_player
1985 <<"\" not found"<<std::endl;
1988 if(player->peer_id == PEER_ID_INEXISTENT){
1989 infostream<<"Server::playSound: Player \""<<params.to_player
1990 <<"\" not connected"<<std::endl;
1993 dst_clients.push_back(player->peer_id);
1997 std::list<u16> clients = m_clients.getClientIDs();
1999 for(std::list<u16>::iterator
2000 i = clients.begin(); i != clients.end(); ++i)
2002 Player *player = m_env->getPlayer(*i);
2006 if(player->getPosition().getDistanceFrom(pos) >
2007 params.max_hear_distance)
2010 dst_clients.push_back(*i);
2013 if(dst_clients.empty())
2017 s32 id = m_next_sound_id++;
2018 // The sound will exist as a reference in m_playing_sounds
2019 m_playing_sounds[id] = ServerPlayingSound();
2020 ServerPlayingSound &psound = m_playing_sounds[id];
2021 psound.params = params;
2022 for(std::list<u16>::iterator i = dst_clients.begin();
2023 i != dst_clients.end(); i++)
2024 psound.clients.insert(*i);
2026 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
2027 *pkt << id << spec.name << (float) (spec.gain * params.gain)
2028 << (u8) params.type << pos << params.object << params.loop;
2029 for(std::list<u16>::iterator i = dst_clients.begin();
2030 i != dst_clients.end(); i++) {
2032 m_clients.send(*i, 0, pkt, true, false);
2037 void Server::stopSound(s32 handle)
2039 // Get sound reference
2040 std::map<s32, ServerPlayingSound>::iterator i =
2041 m_playing_sounds.find(handle);
2042 if(i == m_playing_sounds.end())
2044 ServerPlayingSound &psound = i->second;
2046 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2049 for(std::set<u16>::iterator i = psound.clients.begin();
2050 i != psound.clients.end(); i++) {
2052 m_clients.send(*i, 0, pkt, true, false);
2055 // Remove sound reference
2056 m_playing_sounds.erase(i);
2059 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2060 std::list<u16> *far_players, float far_d_nodes)
2062 float maxd = far_d_nodes*BS;
2063 v3f p_f = intToFloat(p, BS);
2065 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2068 std::list<u16> clients = m_clients.getClientIDs();
2069 for(std::list<u16>::iterator
2070 i = clients.begin();
2071 i != clients.end(); ++i) {
2074 if(Player *player = m_env->getPlayer(*i)) {
2075 // If player is far away, only set modified blocks not sent
2076 v3f player_pos = player->getPosition();
2077 if(player_pos.getDistanceFrom(p_f) > maxd) {
2078 far_players->push_back(*i);
2085 m_clients.send(*i, 0, pkt, true, false);
2087 // This loop needs the deletion of the packet here
2091 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2092 std::list<u16> *far_players, float far_d_nodes,
2093 bool remove_metadata)
2095 float maxd = far_d_nodes*BS;
2096 v3f p_f = intToFloat(p, BS);
2098 std::list<u16> clients = m_clients.getClientIDs();
2099 for(std::list<u16>::iterator
2100 i = clients.begin();
2101 i != clients.end(); ++i)
2107 Player *player = m_env->getPlayer(*i);
2110 // If player is far away, only set modified blocks not sent
2111 v3f player_pos = player->getPosition();
2112 if(player_pos.getDistanceFrom(p_f) > maxd)
2114 far_players->push_back(*i);
2120 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2122 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2124 *pkt << p << n.param0 << n.param1 << n.param2
2125 << (u8) (remove_metadata ? 0 : 1);
2127 if (!remove_metadata) {
2128 if (client->net_proto_version <= 21) {
2129 // Old clients always clear metadata; fix it
2130 // by sending the full block again.
2131 client->SetBlockNotSent(p);
2138 if (pkt->getSize() > 0)
2139 m_clients.send(*i, 0, pkt, true);
2143 void Server::setBlockNotSent(v3s16 p)
2145 std::list<u16> clients = m_clients.getClientIDs();
2147 for(std::list<u16>::iterator
2148 i = clients.begin();
2149 i != clients.end(); ++i)
2151 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2152 client->SetBlockNotSent(p);
2157 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2159 DSTACK(__FUNCTION_NAME);
2161 v3s16 p = block->getPos();
2164 Create a packet with the block in the right format
2167 std::ostringstream os(std::ios_base::binary);
2168 block->serialize(os, ver, false);
2169 block->serializeNetworkSpecific(os, net_proto_version);
2170 std::string s = os.str();
2172 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2173 2 + 2 + 2 + 2 + s.size(), peer_id);
2176 pkt->putRawString(s.c_str(), s.size());
2180 void Server::SendBlocks(float dtime)
2182 DSTACK(__FUNCTION_NAME);
2184 JMutexAutoLock envlock(m_env_mutex);
2185 //TODO check if one big lock could be faster then multiple small ones
2187 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2189 std::vector<PrioritySortedBlockTransfer> queue;
2191 s32 total_sending = 0;
2194 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2196 std::list<u16> clients = m_clients.getClientIDs();
2199 for(std::list<u16>::iterator
2200 i = clients.begin();
2201 i != clients.end(); ++i)
2203 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2208 total_sending += client->SendingCount();
2209 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2215 // Lowest priority number comes first.
2216 // Lowest is most important.
2217 std::sort(queue.begin(), queue.end());
2220 for(u32 i=0; i<queue.size(); i++)
2222 //TODO: Calculate limit dynamically
2223 if(total_sending >= g_settings->getS32
2224 ("max_simultaneous_block_sends_server_total"))
2227 PrioritySortedBlockTransfer q = queue[i];
2229 MapBlock *block = NULL;
2232 block = m_env->getMap().getBlockNoCreate(q.pos);
2234 catch(InvalidPositionException &e)
2239 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2244 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2246 client->SentBlock(q.pos);
2252 void Server::fillMediaCache()
2254 DSTACK(__FUNCTION_NAME);
2256 infostream<<"Server: Calculating media file checksums"<<std::endl;
2258 // Collect all media file paths
2259 std::list<std::string> paths;
2260 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2261 i != m_mods.end(); i++){
2262 const ModSpec &mod = *i;
2263 paths.push_back(mod.path + DIR_DELIM + "textures");
2264 paths.push_back(mod.path + DIR_DELIM + "sounds");
2265 paths.push_back(mod.path + DIR_DELIM + "media");
2266 paths.push_back(mod.path + DIR_DELIM + "models");
2268 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2270 // Collect media file information from paths into cache
2271 for(std::list<std::string>::iterator i = paths.begin();
2272 i != paths.end(); i++)
2274 std::string mediapath = *i;
2275 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2276 for(u32 j=0; j<dirlist.size(); j++){
2277 if(dirlist[j].dir) // Ignode dirs
2279 std::string filename = dirlist[j].name;
2280 // If name contains illegal characters, ignore the file
2281 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2282 infostream<<"Server: ignoring illegal file name: \""
2283 <<filename<<"\""<<std::endl;
2286 // If name is not in a supported format, ignore it
2287 const char *supported_ext[] = {
2288 ".png", ".jpg", ".bmp", ".tga",
2289 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2291 ".x", ".b3d", ".md2", ".obj",
2294 if(removeStringEnd(filename, supported_ext) == ""){
2295 infostream<<"Server: ignoring unsupported file extension: \""
2296 <<filename<<"\""<<std::endl;
2299 // Ok, attempt to load the file and add to cache
2300 std::string filepath = mediapath + DIR_DELIM + filename;
2302 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2303 if(fis.good() == false){
2304 errorstream<<"Server::fillMediaCache(): Could not open \""
2305 <<filename<<"\" for reading"<<std::endl;
2308 std::ostringstream tmp_os(std::ios_base::binary);
2312 fis.read(buf, 1024);
2313 std::streamsize len = fis.gcount();
2314 tmp_os.write(buf, len);
2323 errorstream<<"Server::fillMediaCache(): Failed to read \""
2324 <<filename<<"\""<<std::endl;
2327 if(tmp_os.str().length() == 0){
2328 errorstream<<"Server::fillMediaCache(): Empty file \""
2329 <<filepath<<"\""<<std::endl;
2334 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2336 unsigned char *digest = sha1.getDigest();
2337 std::string sha1_base64 = base64_encode(digest, 20);
2338 std::string sha1_hex = hex_encode((char*)digest, 20);
2342 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2343 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2348 struct SendableMediaAnnouncement
2351 std::string sha1_digest;
2353 SendableMediaAnnouncement(const std::string &name_="",
2354 const std::string &sha1_digest_=""):
2356 sha1_digest(sha1_digest_)
2360 void Server::sendMediaAnnouncement(u16 peer_id)
2362 DSTACK(__FUNCTION_NAME);
2364 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2367 std::list<SendableMediaAnnouncement> file_announcements;
2369 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2370 i != m_media.end(); i++){
2372 file_announcements.push_back(
2373 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2377 std::ostringstream os(std::ios_base::binary);
2384 u16 length of sha1_digest
2389 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2390 *pkt << (u16) file_announcements.size();
2392 for(std::list<SendableMediaAnnouncement>::iterator
2393 j = file_announcements.begin();
2394 j != file_announcements.end(); ++j) {
2395 *pkt << j->name << j->sha1_digest;
2398 *pkt << g_settings->get("remote_media");
2402 struct SendableMedia
2408 SendableMedia(const std::string &name_="", const std::string &path_="",
2409 const std::string &data_=""):
2416 void Server::sendRequestedMedia(u16 peer_id,
2417 const std::list<std::string> &tosend)
2419 DSTACK(__FUNCTION_NAME);
2421 verbosestream<<"Server::sendRequestedMedia(): "
2422 <<"Sending files to client"<<std::endl;
2426 // Put 5kB in one bunch (this is not accurate)
2427 u32 bytes_per_bunch = 5000;
2429 std::vector< std::list<SendableMedia> > file_bunches;
2430 file_bunches.push_back(std::list<SendableMedia>());
2432 u32 file_size_bunch_total = 0;
2434 for(std::list<std::string>::const_iterator i = tosend.begin();
2435 i != tosend.end(); ++i)
2437 const std::string &name = *i;
2439 if(m_media.find(name) == m_media.end()) {
2440 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2441 <<"unknown file \""<<(name)<<"\""<<std::endl;
2445 //TODO get path + name
2446 std::string tpath = m_media[name].path;
2449 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2450 if(fis.good() == false){
2451 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2452 <<tpath<<"\" for reading"<<std::endl;
2455 std::ostringstream tmp_os(std::ios_base::binary);
2459 fis.read(buf, 1024);
2460 std::streamsize len = fis.gcount();
2461 tmp_os.write(buf, len);
2462 file_size_bunch_total += len;
2471 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2472 <<name<<"\""<<std::endl;
2475 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2476 <<tname<<"\""<<std::endl;*/
2478 file_bunches[file_bunches.size()-1].push_back(
2479 SendableMedia(name, tpath, tmp_os.str()));
2481 // Start next bunch if got enough data
2482 if(file_size_bunch_total >= bytes_per_bunch) {
2483 file_bunches.push_back(std::list<SendableMedia>());
2484 file_size_bunch_total = 0;
2489 /* Create and send packets */
2491 u16 num_bunches = file_bunches.size();
2492 for(u16 i = 0; i < num_bunches; i++) {
2495 u16 total number of texture bunches
2496 u16 index of this bunch
2497 u32 number of files in this bunch
2506 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2507 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2509 for(std::list<SendableMedia>::iterator
2510 j = file_bunches[i].begin();
2511 j != file_bunches[i].end(); ++j) {
2513 pkt->putLongString(j->data);
2516 verbosestream << "Server::sendRequestedMedia(): bunch "
2517 << i << "/" << num_bunches
2518 << " files=" << file_bunches[i].size()
2519 << " size=" << pkt->getSize() << std::endl;
2524 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2526 if(m_detached_inventories.count(name) == 0) {
2527 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2530 Inventory *inv = m_detached_inventories[name];
2531 std::ostringstream os(std::ios_base::binary);
2533 os << serializeString(name);
2537 std::string s = os.str();
2539 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2540 pkt->putRawString(s.c_str(), s.size());
2542 if (peer_id != PEER_ID_INEXISTENT) {
2546 m_clients.sendToAll(0, pkt, true);
2550 void Server::sendDetachedInventories(u16 peer_id)
2552 DSTACK(__FUNCTION_NAME);
2554 for(std::map<std::string, Inventory*>::iterator
2555 i = m_detached_inventories.begin();
2556 i != m_detached_inventories.end(); i++) {
2557 const std::string &name = i->first;
2558 //Inventory *inv = i->second;
2559 sendDetachedInventory(name, peer_id);
2567 void Server::DiePlayer(u16 peer_id)
2569 DSTACK(__FUNCTION_NAME);
2571 PlayerSAO *playersao = getPlayerSAO(peer_id);
2574 infostream << "Server::DiePlayer(): Player "
2575 << playersao->getPlayer()->getName()
2576 << " dies" << std::endl;
2578 playersao->setHP(0);
2580 // Trigger scripted stuff
2581 m_script->on_dieplayer(playersao);
2583 SendPlayerHP(peer_id);
2584 SendDeathscreen(peer_id, false, v3f(0,0,0));
2587 void Server::RespawnPlayer(u16 peer_id)
2589 DSTACK(__FUNCTION_NAME);
2591 PlayerSAO *playersao = getPlayerSAO(peer_id);
2594 infostream << "Server::RespawnPlayer(): Player "
2595 << playersao->getPlayer()->getName()
2596 << " respawns" << std::endl;
2598 playersao->setHP(PLAYER_MAX_HP);
2599 playersao->setBreath(PLAYER_MAX_BREATH);
2601 SendPlayerHP(peer_id);
2602 SendPlayerBreath(peer_id);
2604 bool repositioned = m_script->on_respawnplayer(playersao);
2606 v3f pos = findSpawnPos(m_env->getServerMap());
2607 playersao->setPos(pos);
2611 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2613 DSTACK(__FUNCTION_NAME);
2615 SendAccessDenied(peer_id, reason);
2616 m_clients.event(peer_id, CSE_SetDenied);
2617 m_con.DisconnectPeer(peer_id);
2620 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2622 DSTACK(__FUNCTION_NAME);
2623 std::wstring message;
2626 Clear references to playing sounds
2628 for(std::map<s32, ServerPlayingSound>::iterator
2629 i = m_playing_sounds.begin();
2630 i != m_playing_sounds.end();)
2632 ServerPlayingSound &psound = i->second;
2633 psound.clients.erase(peer_id);
2634 if(psound.clients.empty())
2635 m_playing_sounds.erase(i++);
2640 Player *player = m_env->getPlayer(peer_id);
2642 // Collect information about leaving in chat
2644 if(player != NULL && reason != CDR_DENY)
2646 std::wstring name = narrow_to_wide(player->getName());
2649 message += L" left the game.";
2650 if(reason == CDR_TIMEOUT)
2651 message += L" (timed out)";
2655 /* Run scripts and remove from environment */
2659 PlayerSAO *playersao = player->getPlayerSAO();
2662 m_script->on_leaveplayer(playersao);
2664 playersao->disconnected();
2672 if(player != NULL && reason != CDR_DENY)
2674 std::ostringstream os(std::ios_base::binary);
2675 std::list<u16> clients = m_clients.getClientIDs();
2677 for(std::list<u16>::iterator
2678 i = clients.begin();
2679 i != clients.end(); ++i)
2682 Player *player = m_env->getPlayer(*i);
2685 // Get name of player
2686 os<<player->getName()<<" ";
2689 actionstream<<player->getName()<<" "
2690 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2691 <<" List of players: "<<os.str()<<std::endl;
2695 JMutexAutoLock env_lock(m_env_mutex);
2696 m_clients.DeleteClient(peer_id);
2700 // Send leave chat message to all remaining clients
2701 if(message.length() != 0)
2702 SendChatMessage(PEER_ID_INEXISTENT,message);
2705 void Server::UpdateCrafting(u16 peer_id)
2707 DSTACK(__FUNCTION_NAME);
2709 Player* player = m_env->getPlayer(peer_id);
2712 // Get a preview for crafting
2714 InventoryLocation loc;
2715 loc.setPlayer(player->getName());
2716 getCraftingResult(&player->inventory, preview, false, this);
2717 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2719 // Put the new preview in
2720 InventoryList *plist = player->inventory.getList("craftpreview");
2722 assert(plist->getSize() >= 1);
2723 plist->changeItem(0, preview);
2726 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2728 RemoteClient *client = getClientNoEx(peer_id,state_min);
2730 throw ClientNotFoundException("Client not found");
2734 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2736 return m_clients.getClientNoEx(peer_id, state_min);
2739 std::string Server::getPlayerName(u16 peer_id)
2741 Player *player = m_env->getPlayer(peer_id);
2743 return "[id="+itos(peer_id)+"]";
2744 return player->getName();
2747 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2749 Player *player = m_env->getPlayer(peer_id);
2752 return player->getPlayerSAO();
2755 std::wstring Server::getStatusString()
2757 std::wostringstream os(std::ios_base::binary);
2760 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2762 os<<L", uptime="<<m_uptime.get();
2764 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2765 // Information about clients
2768 std::list<u16> clients = m_clients.getClientIDs();
2769 for(std::list<u16>::iterator i = clients.begin();
2770 i != clients.end(); ++i)
2773 Player *player = m_env->getPlayer(*i);
2774 // Get name of player
2775 std::wstring name = L"unknown";
2777 name = narrow_to_wide(player->getName());
2778 // Add name to information string
2786 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2787 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2788 if(g_settings->get("motd") != "")
2789 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2793 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2795 std::set<std::string> privs;
2796 m_script->getAuth(name, NULL, &privs);
2800 bool Server::checkPriv(const std::string &name, const std::string &priv)
2802 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2803 return (privs.count(priv) != 0);
2806 void Server::reportPrivsModified(const std::string &name)
2809 std::list<u16> clients = m_clients.getClientIDs();
2810 for(std::list<u16>::iterator
2811 i = clients.begin();
2812 i != clients.end(); ++i){
2813 Player *player = m_env->getPlayer(*i);
2814 reportPrivsModified(player->getName());
2817 Player *player = m_env->getPlayer(name.c_str());
2820 SendPlayerPrivileges(player->peer_id);
2821 PlayerSAO *sao = player->getPlayerSAO();
2824 sao->updatePrivileges(
2825 getPlayerEffectivePrivs(name),
2830 void Server::reportInventoryFormspecModified(const std::string &name)
2832 Player *player = m_env->getPlayer(name.c_str());
2835 SendPlayerInventoryFormspec(player->peer_id);
2838 void Server::setIpBanned(const std::string &ip, const std::string &name)
2840 m_banmanager->add(ip, name);
2843 void Server::unsetIpBanned(const std::string &ip_or_name)
2845 m_banmanager->remove(ip_or_name);
2848 std::string Server::getBanDescription(const std::string &ip_or_name)
2850 return m_banmanager->getBanDescription(ip_or_name);
2853 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2855 Player *player = m_env->getPlayer(name);
2859 if (player->peer_id == PEER_ID_INEXISTENT)
2862 SendChatMessage(player->peer_id, msg);
2865 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2867 Player *player = m_env->getPlayer(playername);
2871 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2875 SendShowFormspecMessage(player->peer_id, formspec, formname);
2879 u32 Server::hudAdd(Player *player, HudElement *form) {
2883 u32 id = player->addHud(form);
2885 SendHUDAdd(player->peer_id, id, form);
2890 bool Server::hudRemove(Player *player, u32 id) {
2894 HudElement* todel = player->removeHud(id);
2901 SendHUDRemove(player->peer_id, id);
2905 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2909 SendHUDChange(player->peer_id, id, stat, data);
2913 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2917 SendHUDSetFlags(player->peer_id, flags, mask);
2918 player->hud_flags = flags;
2920 PlayerSAO* playersao = player->getPlayerSAO();
2922 if (playersao == NULL)
2925 m_script->player_event(playersao, "hud_changed");
2929 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2932 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2935 std::ostringstream os(std::ios::binary);
2936 writeS32(os, hotbar_itemcount);
2937 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2941 void Server::hudSetHotbarImage(Player *player, std::string name) {
2945 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2948 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2952 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2955 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2960 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2964 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2969 SendEyeOffset(player->peer_id, first, third);
2973 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2974 const std::string &type, const std::vector<std::string> ¶ms)
2979 SendSetSky(player->peer_id, bgcolor, type, params);
2983 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2989 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2993 void Server::notifyPlayers(const std::wstring &msg)
2995 SendChatMessage(PEER_ID_INEXISTENT,msg);
2998 void Server::spawnParticle(const char *playername, v3f pos,
2999 v3f velocity, v3f acceleration,
3000 float expirationtime, float size, bool
3001 collisiondetection, bool vertical, std::string texture)
3003 Player *player = m_env->getPlayer(playername);
3006 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3007 expirationtime, size, collisiondetection, vertical, texture);
3010 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3011 float expirationtime, float size,
3012 bool collisiondetection, bool vertical, std::string texture)
3014 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3015 expirationtime, size, collisiondetection, vertical, texture);
3018 u32 Server::addParticleSpawner(const char *playername,
3019 u16 amount, float spawntime,
3020 v3f minpos, v3f maxpos,
3021 v3f minvel, v3f maxvel,
3022 v3f minacc, v3f maxacc,
3023 float minexptime, float maxexptime,
3024 float minsize, float maxsize,
3025 bool collisiondetection, bool vertical, std::string texture)
3027 Player *player = m_env->getPlayer(playername);
3032 for(;;) // look for unused particlespawner id
3035 if (std::find(m_particlespawner_ids.begin(),
3036 m_particlespawner_ids.end(), id)
3037 == m_particlespawner_ids.end())
3039 m_particlespawner_ids.push_back(id);
3044 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3045 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3046 minexptime, maxexptime, minsize, maxsize,
3047 collisiondetection, vertical, texture, id);
3052 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3053 v3f minpos, v3f maxpos,
3054 v3f minvel, v3f maxvel,
3055 v3f minacc, v3f maxacc,
3056 float minexptime, float maxexptime,
3057 float minsize, float maxsize,
3058 bool collisiondetection, bool vertical, std::string texture)
3061 for(;;) // look for unused particlespawner id
3064 if (std::find(m_particlespawner_ids.begin(),
3065 m_particlespawner_ids.end(), id)
3066 == m_particlespawner_ids.end())
3068 m_particlespawner_ids.push_back(id);
3073 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3074 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3075 minexptime, maxexptime, minsize, maxsize,
3076 collisiondetection, vertical, texture, id);
3081 void Server::deleteParticleSpawner(const char *playername, u32 id)
3083 Player *player = m_env->getPlayer(playername);
3087 m_particlespawner_ids.erase(
3088 std::remove(m_particlespawner_ids.begin(),
3089 m_particlespawner_ids.end(), id),
3090 m_particlespawner_ids.end());
3091 SendDeleteParticleSpawner(player->peer_id, id);
3094 void Server::deleteParticleSpawnerAll(u32 id)
3096 m_particlespawner_ids.erase(
3097 std::remove(m_particlespawner_ids.begin(),
3098 m_particlespawner_ids.end(), id),
3099 m_particlespawner_ids.end());
3100 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3103 Inventory* Server::createDetachedInventory(const std::string &name)
3105 if(m_detached_inventories.count(name) > 0){
3106 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3107 delete m_detached_inventories[name];
3109 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3111 Inventory *inv = new Inventory(m_itemdef);
3113 m_detached_inventories[name] = inv;
3114 //TODO find a better way to do this
3115 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3122 BoolScopeSet(bool *dst, bool val):
3125 m_orig_state = *m_dst;
3130 *m_dst = m_orig_state;
3137 // actions: time-reversed list
3138 // Return value: success/failure
3139 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3140 std::list<std::string> *log)
3142 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3143 ServerMap *map = (ServerMap*)(&m_env->getMap());
3145 // Fail if no actions to handle
3146 if(actions.empty()){
3147 log->push_back("Nothing to do.");
3154 for(std::list<RollbackAction>::const_iterator
3155 i = actions.begin();
3156 i != actions.end(); i++)
3158 const RollbackAction &action = *i;
3160 bool success = action.applyRevert(map, this, this);
3163 std::ostringstream os;
3164 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3165 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3167 log->push_back(os.str());
3169 std::ostringstream os;
3170 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3171 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3173 log->push_back(os.str());
3177 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3178 <<" failed"<<std::endl;
3180 // Call it done if less than half failed
3181 return num_failed <= num_tried/2;
3184 // IGameDef interface
3186 IItemDefManager* Server::getItemDefManager()
3190 INodeDefManager* Server::getNodeDefManager()
3194 ICraftDefManager* Server::getCraftDefManager()
3198 ITextureSource* Server::getTextureSource()
3202 IShaderSource* Server::getShaderSource()
3206 scene::ISceneManager* Server::getSceneManager()
3211 u16 Server::allocateUnknownNodeId(const std::string &name)
3213 return m_nodedef->allocateDummy(name);
3215 ISoundManager* Server::getSoundManager()
3217 return &dummySoundManager;
3219 MtEventManager* Server::getEventManager()
3224 IWritableItemDefManager* Server::getWritableItemDefManager()
3228 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3232 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3237 const ModSpec* Server::getModSpec(const std::string &modname)
3239 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3240 i != m_mods.end(); i++){
3241 const ModSpec &mod = *i;
3242 if(mod.name == modname)
3247 void Server::getModNames(std::list<std::string> &modlist)
3249 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3251 modlist.push_back(i->name);
3254 std::string Server::getBuiltinLuaPath()
3256 return porting::path_share + DIR_DELIM + "builtin";
3259 v3f findSpawnPos(ServerMap &map)
3261 //return v3f(50,50,50)*BS;
3266 nodepos = v2s16(0,0);
3271 s16 water_level = map.getWaterLevel();
3273 // Try to find a good place a few times
3274 for(s32 i=0; i<1000; i++)
3277 // We're going to try to throw the player to this position
3278 v2s16 nodepos2d = v2s16(
3279 -range + (myrand() % (range * 2)),
3280 -range + (myrand() % (range * 2)));
3282 // Get ground height at point
3283 s16 groundheight = map.findGroundLevel(nodepos2d);
3284 if (groundheight <= water_level) // Don't go underwater
3286 if (groundheight > water_level + 6) // Don't go to high places
3289 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3290 bool is_good = false;
3292 for (s32 i = 0; i < 10; i++) {
3293 v3s16 blockpos = getNodeBlockPos(nodepos);
3294 map.emergeBlock(blockpos, true);
3295 content_t c = map.getNodeNoEx(nodepos).getContent();
3296 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3298 if (air_count >= 2){
3306 // Found a good place
3307 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3313 return intToFloat(nodepos, BS);
3316 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3318 bool newplayer = false;
3321 Try to get an existing player
3323 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3325 // If player is already connected, cancel
3326 if(player != NULL && player->peer_id != 0)
3328 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3333 If player with the wanted peer_id already exists, cancel.
3335 if(m_env->getPlayer(peer_id) != NULL)
3337 infostream<<"emergePlayer(): Player with wrong name but same"
3338 " peer_id already exists"<<std::endl;
3342 // Load player if it isn't already loaded
3344 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3347 // Create player if it doesn't exist
3350 player = new RemotePlayer(this, name);
3351 // Set player position
3352 infostream<<"Server: Finding spawn place for player \""
3353 <<name<<"\""<<std::endl;
3354 v3f pos = findSpawnPos(m_env->getServerMap());
3355 player->setPosition(pos);
3357 // Make sure the player is saved
3358 player->setModified(true);
3360 // Add player to environment
3361 m_env->addPlayer(player);
3364 // Create a new player active object
3365 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3366 getPlayerEffectivePrivs(player->getName()),
3369 /* Clean up old HUD elements from previous sessions */
3372 /* Add object to environment */
3373 m_env->addActiveObject(playersao);
3377 m_script->on_newplayer(playersao);
3383 void dedicated_server_loop(Server &server, bool &kill)
3385 DSTACK(__FUNCTION_NAME);
3387 verbosestream<<"dedicated_server_loop()"<<std::endl;
3389 IntervalLimiter m_profiler_interval;
3393 float steplen = g_settings->getFloat("dedicated_server_step");
3394 // This is kind of a hack but can be done like this
3395 // because server.step() is very light
3397 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3398 sleep_ms((int)(steplen*1000.0));
3400 server.step(steplen);
3402 if(server.getShutdownRequested() || kill)
3404 infostream<<"Dedicated server quitting"<<std::endl;
3406 if(g_settings->getBool("server_announce"))
3407 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3415 float profiler_print_interval =
3416 g_settings->getFloat("profiler_print_interval");
3417 if(profiler_print_interval != 0)
3419 if(m_profiler_interval.step(steplen, profiler_print_interval))
3421 infostream<<"Profiler:"<<std::endl;
3422 g_profiler->print(infostream);
3423 g_profiler->clear();