3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public JThread
80 ServerThread(Server *server):
89 void * ServerThread::Thread()
91 log_register_thread("ServerThread");
93 DSTACK(__FUNCTION_NAME);
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
100 porting::setThreadName("ServerThread");
102 while(!StopRequested())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
107 m_server->AsyncRunStep();
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
165 const std::string &path_world,
166 const SubgameSpec &gamespec,
167 bool simple_singleplayer_mode,
170 m_path_world(path_world),
171 m_gamespec(gamespec),
172 m_simple_singleplayer_mode(simple_singleplayer_mode),
173 m_async_fatal_error(""),
182 m_enable_rollback_recording(false),
185 m_itemdef(createItemDefManager()),
186 m_nodedef(createNodeDefManager()),
187 m_craftdef(createCraftDefManager()),
188 m_event(new EventManager()),
190 m_time_of_day_send_timer(0),
193 m_shutdown_requested(false),
194 m_ignore_map_edit_events(false),
195 m_ignore_map_edit_events_peer_id(0),
199 m_liquid_transform_timer = 0.0;
200 m_liquid_transform_every = 1.0;
201 m_print_info_timer = 0.0;
202 m_masterserver_timer = 0.0;
203 m_objectdata_timer = 0.0;
204 m_emergethread_trigger_timer = 0.0;
205 m_savemap_timer = 0.0;
208 m_lag = g_settings->getFloat("dedicated_server_step");
211 throw ServerError("Supplied empty world path");
213 if(!gamespec.isValid())
214 throw ServerError("Supplied invalid gamespec");
216 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
217 if(m_simple_singleplayer_mode)
218 infostream<<" in simple singleplayer mode"<<std::endl;
220 infostream<<std::endl;
221 infostream<<"- world: "<<m_path_world<<std::endl;
222 infostream<<"- game: "<<m_gamespec.path<<std::endl;
224 // Create world if it doesn't exist
225 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
226 throw ServerError("Failed to initialize world");
228 // Create server thread
229 m_thread = new ServerThread(this);
231 // Create emerge manager
232 m_emerge = new EmergeManager(this);
234 // Create ban manager
235 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
236 m_banmanager = new BanManager(ban_path);
238 ModConfiguration modconf(m_path_world);
239 m_mods = modconf.getMods();
240 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
241 // complain about mods with unsatisfied dependencies
242 if(!modconf.isConsistent())
244 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
245 it != unsatisfied_mods.end(); ++it)
248 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
249 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
250 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
251 errorstream << " \"" << *dep_it << "\"";
252 errorstream << std::endl;
256 Settings worldmt_settings;
257 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
258 worldmt_settings.readConfigFile(worldmt.c_str());
259 std::vector<std::string> names = worldmt_settings.getNames();
260 std::set<std::string> load_mod_names;
261 for(std::vector<std::string>::iterator it = names.begin();
262 it != names.end(); ++it)
264 std::string name = *it;
265 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
266 load_mod_names.insert(name.substr(9));
268 // complain about mods declared to be loaded, but not found
269 for(std::vector<ModSpec>::iterator it = m_mods.begin();
270 it != m_mods.end(); ++it)
271 load_mod_names.erase((*it).name);
272 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
273 it != unsatisfied_mods.end(); ++it)
274 load_mod_names.erase((*it).name);
275 if(!load_mod_names.empty())
277 errorstream << "The following mods could not be found:";
278 for(std::set<std::string>::iterator it = load_mod_names.begin();
279 it != load_mod_names.end(); ++it)
280 errorstream << " \"" << (*it) << "\"";
281 errorstream << std::endl;
285 JMutexAutoLock envlock(m_env_mutex);
287 // Load mapgen params from Settings
288 m_emerge->loadMapgenParams();
290 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
291 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
293 // Initialize scripting
294 infostream<<"Server: Initializing Lua"<<std::endl;
296 m_script = new GameScripting(this);
298 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
300 if (!m_script->loadScript(scriptpath))
301 throw ModError("Failed to load and run " + scriptpath);
304 infostream<<"Server: Loading mods: ";
305 for(std::vector<ModSpec>::iterator i = m_mods.begin();
306 i != m_mods.end(); i++){
307 const ModSpec &mod = *i;
308 infostream<<mod.name<<" ";
310 infostream<<std::endl;
311 // Load and run "mod" scripts
312 for(std::vector<ModSpec>::iterator i = m_mods.begin();
313 i != m_mods.end(); i++){
314 const ModSpec &mod = *i;
315 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
316 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
317 <<scriptpath<<"\"]"<<std::endl;
318 bool success = m_script->loadMod(scriptpath, mod.name);
320 errorstream<<"Server: Failed to load and run "
321 <<scriptpath<<std::endl;
322 throw ModError("Failed to load and run "+scriptpath);
326 // Read Textures and calculate sha1 sums
329 // Apply item aliases in the node definition manager
330 m_nodedef->updateAliases(m_itemdef);
332 m_nodedef->setNodeRegistrationStatus(true);
334 // Perform pending node name resolutions
335 m_nodedef->runNodeResolverCallbacks();
337 // Initialize Environment
338 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
340 m_clients.setEnv(m_env);
342 // Initialize mapgens
343 m_emerge->initMapgens();
345 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
346 if (m_enable_rollback_recording) {
347 // Create rollback manager
348 m_rollback = new RollbackManager(m_path_world, this);
351 // Give environment reference to scripting api
352 m_script->initializeEnvironment(m_env);
354 // Register us to receive map edit events
355 servermap->addEventReceiver(this);
357 // If file exists, load environment metadata
358 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
360 infostream<<"Server: Loading environment metadata"<<std::endl;
364 // Add some test ActiveBlockModifiers to environment
365 add_legacy_abms(m_env, m_nodedef);
367 m_liquid_transform_every = g_settings->getFloat("liquid_update");
372 infostream<<"Server destructing"<<std::endl;
374 // Send shutdown message
375 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
378 JMutexAutoLock envlock(m_env_mutex);
380 // Execute script shutdown hooks
381 m_script->on_shutdown();
383 infostream<<"Server: Saving players"<<std::endl;
384 m_env->saveLoadedPlayers();
386 infostream<<"Server: Saving environment metadata"<<std::endl;
394 // stop all emerge threads before deleting players that may have
395 // requested blocks to be emerged
396 m_emerge->stopThreads();
398 // Delete things in the reverse order of creation
401 // N.B. the EmergeManager should be deleted after the Environment since Map
402 // depends on EmergeManager to write its current params to the map meta
411 // Deinitialize scripting
412 infostream<<"Server: Deinitializing scripting"<<std::endl;
415 // Delete detached inventories
416 for (std::map<std::string, Inventory*>::iterator
417 i = m_detached_inventories.begin();
418 i != m_detached_inventories.end(); i++) {
423 void Server::start(Address bind_addr)
425 DSTACK(__FUNCTION_NAME);
427 m_bind_addr = bind_addr;
429 infostream<<"Starting server on "
430 << bind_addr.serializeString() <<"..."<<std::endl;
432 // Stop thread if already running
435 // Initialize connection
436 m_con.SetTimeoutMs(30);
437 m_con.Serve(bind_addr);
442 // ASCII art for the win!
444 <<" .__ __ __ "<<std::endl
445 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
446 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
447 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
448 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
449 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
450 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
451 actionstream<<"Server for gameid=\""<<m_gamespec.id
452 <<"\" listening on "<<bind_addr.serializeString()<<":"
453 <<bind_addr.getPort() << "."<<std::endl;
458 DSTACK(__FUNCTION_NAME);
460 infostream<<"Server: Stopping and waiting threads"<<std::endl;
462 // Stop threads (set run=false first so both start stopping)
464 //m_emergethread.setRun(false);
466 //m_emergethread.stop();
468 infostream<<"Server: Threads stopped"<<std::endl;
471 void Server::step(float dtime)
473 DSTACK(__FUNCTION_NAME);
478 JMutexAutoLock lock(m_step_dtime_mutex);
479 m_step_dtime += dtime;
481 // Throw if fatal error occurred in thread
482 std::string async_err = m_async_fatal_error.get();
483 if(async_err != "") {
484 if (m_simple_singleplayer_mode) {
485 throw ServerError(async_err);
488 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
489 << "Please fix the following error:" << std::endl
490 << async_err << std::endl;
491 FATAL_ERROR(async_err.c_str());
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
538 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
541 Send to clients at constant intervals
544 m_time_of_day_send_timer -= dtime;
545 if(m_time_of_day_send_timer < 0.0) {
546 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
547 u16 time = m_env->getTimeOfDay();
548 float time_speed = g_settings->getFloat("time_speed");
549 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
553 JMutexAutoLock lock(m_env_mutex);
554 // Figure out and report maximum lag to environment
555 float max_lag = m_env->getMaxLagEstimate();
556 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
558 if(dtime > 0.1 && dtime > max_lag * 2.0)
559 infostream<<"Server: Maximum lag peaked to "<<dtime
563 m_env->reportMaxLagEstimate(max_lag);
565 ScopeProfiler sp(g_profiler, "SEnv step");
566 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
570 static const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 JMutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"));
584 /* Transform liquids */
585 m_liquid_transform_timer += dtime;
586 if(m_liquid_transform_timer >= m_liquid_transform_every)
588 m_liquid_transform_timer -= m_liquid_transform_every;
590 JMutexAutoLock lock(m_env_mutex);
592 ScopeProfiler sp(g_profiler, "Server: liquid transform");
594 std::map<v3s16, MapBlock*> modified_blocks;
595 m_env->getMap().transformLiquids(modified_blocks);
600 core::map<v3s16, MapBlock*> lighting_modified_blocks;
601 ServerMap &map = ((ServerMap&)m_env->getMap());
602 map.updateLighting(modified_blocks, lighting_modified_blocks);
604 // Add blocks modified by lighting to modified_blocks
605 for(core::map<v3s16, MapBlock*>::Iterator
606 i = lighting_modified_blocks.getIterator();
607 i.atEnd() == false; i++)
609 MapBlock *block = i.getNode()->getValue();
610 modified_blocks.insert(block->getPos(), block);
614 Set the modified blocks unsent for all the clients
616 if(!modified_blocks.empty())
618 SetBlocksNotSent(modified_blocks);
621 m_clients.step(dtime);
623 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
625 // send masterserver announce
627 float &counter = m_masterserver_timer;
628 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
629 g_settings->getBool("server_announce"))
631 ServerList::sendAnnounce(counter ? "update" : "start",
632 m_bind_addr.getPort(),
633 m_clients.getPlayerNames(),
635 m_env->getGameTime(),
638 m_emerge->params.mg_name,
647 Check added and deleted active objects
650 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
651 JMutexAutoLock envlock(m_env_mutex);
654 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
655 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
657 // Radius inside which objects are active
658 s16 radius = g_settings->getS16("active_object_send_range_blocks");
659 s16 player_radius = g_settings->getS16("player_transfer_distance");
661 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
662 !g_settings->getBool("unlimited_player_transfer_distance"))
663 player_radius = radius;
665 radius *= MAP_BLOCKSIZE;
666 player_radius *= MAP_BLOCKSIZE;
668 for(std::map<u16, RemoteClient*>::iterator
670 i != clients.end(); ++i)
672 RemoteClient *client = i->second;
674 // If definitions and textures have not been sent, don't
675 // send objects either
676 if (client->getState() < CS_DefinitionsSent)
679 Player *player = m_env->getPlayer(client->peer_id);
682 // This can happen if the client timeouts somehow
683 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
685 <<" has no associated player"<<std::endl;*/
688 v3s16 pos = floatToInt(player->getPosition(), BS);
690 std::set<u16> removed_objects;
691 std::set<u16> added_objects;
692 m_env->getRemovedActiveObjects(pos, radius, player_radius,
693 client->m_known_objects, removed_objects);
694 m_env->getAddedActiveObjects(pos, radius, player_radius,
695 client->m_known_objects, added_objects);
697 // Ignore if nothing happened
698 if(removed_objects.empty() && added_objects.empty())
700 //infostream<<"active objects: none changed"<<std::endl;
704 std::string data_buffer;
708 // Handle removed objects
709 writeU16((u8*)buf, removed_objects.size());
710 data_buffer.append(buf, 2);
711 for(std::set<u16>::iterator
712 i = removed_objects.begin();
713 i != removed_objects.end(); ++i)
717 ServerActiveObject* obj = m_env->getActiveObject(id);
719 // Add to data buffer for sending
720 writeU16((u8*)buf, id);
721 data_buffer.append(buf, 2);
723 // Remove from known objects
724 client->m_known_objects.erase(id);
726 if(obj && obj->m_known_by_count > 0)
727 obj->m_known_by_count--;
730 // Handle added objects
731 writeU16((u8*)buf, added_objects.size());
732 data_buffer.append(buf, 2);
733 for(std::set<u16>::iterator
734 i = added_objects.begin();
735 i != added_objects.end(); ++i)
739 ServerActiveObject* obj = m_env->getActiveObject(id);
742 u8 type = ACTIVEOBJECT_TYPE_INVALID;
744 infostream<<"WARNING: "<<__FUNCTION_NAME
745 <<": NULL object"<<std::endl;
747 type = obj->getSendType();
749 // Add to data buffer for sending
750 writeU16((u8*)buf, id);
751 data_buffer.append(buf, 2);
752 writeU8((u8*)buf, type);
753 data_buffer.append(buf, 1);
756 data_buffer.append(serializeLongString(
757 obj->getClientInitializationData(client->net_proto_version)));
759 data_buffer.append(serializeLongString(""));
761 // Add to known objects
762 client->m_known_objects.insert(id);
765 obj->m_known_by_count++;
768 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
769 verbosestream << "Server: Sent object remove/add: "
770 << removed_objects.size() << " removed, "
771 << added_objects.size() << " added, "
772 << "packet size is " << pktSize << std::endl;
781 JMutexAutoLock envlock(m_env_mutex);
782 ScopeProfiler sp(g_profiler, "Server: sending object messages");
785 // Value = data sent by object
786 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
788 // Get active object messages from environment
790 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
794 std::vector<ActiveObjectMessage>* message_list = NULL;
795 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
796 n = buffered_messages.find(aom.id);
797 if (n == buffered_messages.end()) {
798 message_list = new std::vector<ActiveObjectMessage>;
799 buffered_messages[aom.id] = message_list;
802 message_list = n->second;
804 message_list->push_back(aom);
808 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
809 // Route data to every client
810 for (std::map<u16, RemoteClient*>::iterator
812 i != clients.end(); ++i) {
813 RemoteClient *client = i->second;
814 std::string reliable_data;
815 std::string unreliable_data;
816 // Go through all objects in message buffer
817 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
818 j = buffered_messages.begin();
819 j != buffered_messages.end(); ++j) {
820 // If object is not known by client, skip it
822 if (client->m_known_objects.find(id) == client->m_known_objects.end())
825 // Get message list of object
826 std::vector<ActiveObjectMessage>* list = j->second;
827 // Go through every message
828 for (std::vector<ActiveObjectMessage>::iterator
829 k = list->begin(); k != list->end(); ++k) {
830 // Compose the full new data with header
831 ActiveObjectMessage aom = *k;
832 std::string new_data;
835 writeU16((u8*)&buf[0], aom.id);
836 new_data.append(buf, 2);
838 new_data += serializeString(aom.datastring);
839 // Add data to buffer
841 reliable_data += new_data;
843 unreliable_data += new_data;
847 reliable_data and unreliable_data are now ready.
850 if(reliable_data.size() > 0) {
851 SendActiveObjectMessages(client->peer_id, reliable_data);
854 if(unreliable_data.size() > 0) {
855 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
860 // Clear buffered_messages
861 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
862 i = buffered_messages.begin();
863 i != buffered_messages.end(); ++i) {
869 Send queued-for-sending map edit events.
872 // We will be accessing the environment
873 JMutexAutoLock lock(m_env_mutex);
875 // Don't send too many at a time
878 // Single change sending is disabled if queue size is not small
879 bool disable_single_change_sending = false;
880 if(m_unsent_map_edit_queue.size() >= 4)
881 disable_single_change_sending = true;
883 int event_count = m_unsent_map_edit_queue.size();
885 // We'll log the amount of each
888 while(m_unsent_map_edit_queue.size() != 0)
890 MapEditEvent* event = m_unsent_map_edit_queue.front();
891 m_unsent_map_edit_queue.pop();
893 // Players far away from the change are stored here.
894 // Instead of sending the changes, MapBlocks are set not sent
896 std::vector<u16> far_players;
898 switch (event->type) {
901 prof.add("MEET_ADDNODE", 1);
902 sendAddNode(event->p, event->n, event->already_known_by_peer,
903 &far_players, disable_single_change_sending ? 5 : 30,
904 event->type == MEET_ADDNODE);
906 case MEET_REMOVENODE:
907 prof.add("MEET_REMOVENODE", 1);
908 sendRemoveNode(event->p, event->already_known_by_peer,
909 &far_players, disable_single_change_sending ? 5 : 30);
911 case MEET_BLOCK_NODE_METADATA_CHANGED:
912 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
913 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
914 setBlockNotSent(event->p);
917 infostream << "Server: MEET_OTHER" << std::endl;
918 prof.add("MEET_OTHER", 1);
919 for(std::set<v3s16>::iterator
920 i = event->modified_blocks.begin();
921 i != event->modified_blocks.end(); ++i) {
926 prof.add("unknown", 1);
927 infostream << "WARNING: Server: Unknown MapEditEvent "
928 << ((u32)event->type) << std::endl;
933 Set blocks not sent to far players
935 if(!far_players.empty()) {
936 // Convert list format to that wanted by SetBlocksNotSent
937 std::map<v3s16, MapBlock*> modified_blocks2;
938 for(std::set<v3s16>::iterator
939 i = event->modified_blocks.begin();
940 i != event->modified_blocks.end(); ++i) {
941 modified_blocks2[*i] =
942 m_env->getMap().getBlockNoCreateNoEx(*i);
945 // Set blocks not sent
946 for(std::vector<u16>::iterator
947 i = far_players.begin();
948 i != far_players.end(); ++i) {
949 if(RemoteClient *client = getClient(*i))
950 client->SetBlocksNotSent(modified_blocks2);
956 /*// Don't send too many at a time
958 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
962 if(event_count >= 5){
963 infostream<<"Server: MapEditEvents:"<<std::endl;
964 prof.print(infostream);
965 } else if(event_count != 0){
966 verbosestream<<"Server: MapEditEvents:"<<std::endl;
967 prof.print(verbosestream);
973 Trigger emergethread (it somehow gets to a non-triggered but
974 bysy state sometimes)
977 float &counter = m_emergethread_trigger_timer;
983 m_emerge->startThreads();
987 // Save map, players and auth stuff
989 float &counter = m_savemap_timer;
991 if(counter >= g_settings->getFloat("server_map_save_interval"))
994 JMutexAutoLock lock(m_env_mutex);
996 ScopeProfiler sp(g_profiler, "Server: saving stuff");
999 if (m_banmanager->isModified()) {
1000 m_banmanager->save();
1003 // Save changed parts of map
1004 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1007 m_env->saveLoadedPlayers();
1009 // Save environment metadata
1015 void Server::Receive()
1017 DSTACK(__FUNCTION_NAME);
1018 SharedBuffer<u8> data;
1022 m_con.Receive(&pkt);
1023 peer_id = pkt.getPeerId();
1026 catch(con::InvalidIncomingDataException &e) {
1027 infostream<<"Server::Receive(): "
1028 "InvalidIncomingDataException: what()="
1029 <<e.what()<<std::endl;
1031 catch(SerializationError &e) {
1032 infostream<<"Server::Receive(): "
1033 "SerializationError: what()="
1034 <<e.what()<<std::endl;
1036 catch(ClientStateError &e) {
1037 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1038 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1039 L"Try reconnecting or updating your client");
1041 catch(con::PeerNotFoundException &e) {
1046 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1048 std::string playername = "";
1049 PlayerSAO *playersao = NULL;
1052 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1053 if (client != NULL) {
1054 playername = client->getName();
1055 playersao = emergePlayer(playername.c_str(), peer_id);
1057 } catch (std::exception &e) {
1063 RemotePlayer *player =
1064 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1066 // If failed, cancel
1067 if((playersao == NULL) || (player == NULL)) {
1068 if(player && player->peer_id != 0) {
1069 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1070 <<" (player allocated to an another client)"<<std::endl;
1071 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1072 L"name. If your client closed unexpectedly, try again in "
1075 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1077 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1083 Send complete position information
1085 SendMovePlayer(peer_id);
1088 SendPlayerPrivileges(peer_id);
1090 // Send inventory formspec
1091 SendPlayerInventoryFormspec(peer_id);
1094 SendInventory(playersao);
1097 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1100 SendPlayerBreath(peer_id);
1102 // Show death screen if necessary
1103 if(player->isDead())
1104 SendDeathscreen(peer_id, false, v3f(0,0,0));
1106 // Note things in chat if not in simple singleplayer mode
1107 if(!m_simple_singleplayer_mode) {
1108 // Send information about server to player in chat
1109 SendChatMessage(peer_id, getStatusString());
1111 // Send information about joining in chat
1113 std::wstring name = L"unknown";
1114 Player *player = m_env->getPlayer(peer_id);
1116 name = narrow_to_wide(player->getName());
1118 std::wstring message;
1121 message += L" joined the game.";
1122 SendChatMessage(PEER_ID_INEXISTENT,message);
1125 Address addr = getPeerAddress(player->peer_id);
1126 std::string ip_str = addr.serializeString();
1127 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1132 std::vector<std::string> names = m_clients.getPlayerNames();
1134 actionstream<<player->getName() <<" joins game. List of players: ";
1136 for (std::vector<std::string>::iterator i = names.begin();
1137 i != names.end(); i++) {
1138 actionstream << *i << " ";
1141 actionstream << player->getName() <<std::endl;
1146 inline void Server::handleCommand(NetworkPacket* pkt)
1148 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1149 (this->*opHandle.handler)(pkt);
1152 void Server::ProcessData(NetworkPacket *pkt)
1154 DSTACK(__FUNCTION_NAME);
1155 // Environment is locked first.
1156 JMutexAutoLock envlock(m_env_mutex);
1158 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1159 u32 peer_id = pkt->getPeerId();
1162 Address address = getPeerAddress(peer_id);
1163 std::string addr_s = address.serializeString();
1165 if(m_banmanager->isIpBanned(addr_s)) {
1166 std::string ban_name = m_banmanager->getBanName(addr_s);
1167 infostream << "Server: A banned client tried to connect from "
1168 << addr_s << "; banned name was "
1169 << ban_name << std::endl;
1170 // This actually doesn't seem to transfer to the client
1171 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1172 + narrow_to_wide(ban_name));
1176 catch(con::PeerNotFoundException &e) {
1178 * no peer for this packet found
1179 * most common reason is peer timeout, e.g. peer didn't
1180 * respond for some time, your server was overloaded or
1183 infostream << "Server::ProcessData(): Canceling: peer "
1184 << peer_id << " not found" << std::endl;
1189 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1191 // Command must be handled into ToServerCommandHandler
1192 if (command >= TOSERVER_NUM_MSG_TYPES) {
1193 infostream << "Server: Ignoring unknown command "
1194 << command << std::endl;
1197 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1202 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1204 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1205 errorstream << "Server::ProcessData(): Cancelling: Peer"
1206 " serialization format invalid or not initialized."
1207 " Skipping incoming command=" << command << std::endl;
1211 /* Handle commands related to client startup */
1212 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1217 if (m_clients.getClientState(peer_id) < CS_Active) {
1218 if (command == TOSERVER_PLAYERPOS) return;
1220 errorstream << "Got packet command: " << command << " for peer id "
1221 << peer_id << " but client isn't active yet. Dropping packet "
1228 catch(SendFailedException &e) {
1229 errorstream << "Server::ProcessData(): SendFailedException: "
1230 << "what=" << e.what()
1235 void Server::setTimeOfDay(u32 time)
1237 m_env->setTimeOfDay(time);
1238 m_time_of_day_send_timer = 0;
1241 void Server::onMapEditEvent(MapEditEvent *event)
1243 if(m_ignore_map_edit_events)
1245 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1247 MapEditEvent *e = event->clone();
1248 m_unsent_map_edit_queue.push(e);
1251 Inventory* Server::getInventory(const InventoryLocation &loc)
1254 case InventoryLocation::UNDEFINED:
1255 case InventoryLocation::CURRENT_PLAYER:
1257 case InventoryLocation::PLAYER:
1259 Player *player = m_env->getPlayer(loc.name.c_str());
1262 PlayerSAO *playersao = player->getPlayerSAO();
1265 return playersao->getInventory();
1268 case InventoryLocation::NODEMETA:
1270 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1273 return meta->getInventory();
1276 case InventoryLocation::DETACHED:
1278 if(m_detached_inventories.count(loc.name) == 0)
1280 return m_detached_inventories[loc.name];
1284 sanity_check(false); // abort
1289 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1292 case InventoryLocation::UNDEFINED:
1294 case InventoryLocation::PLAYER:
1299 Player *player = m_env->getPlayer(loc.name.c_str());
1302 PlayerSAO *playersao = player->getPlayerSAO();
1306 SendInventory(playersao);
1309 case InventoryLocation::NODEMETA:
1311 v3s16 blockpos = getNodeBlockPos(loc.p);
1313 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1315 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1317 setBlockNotSent(blockpos);
1320 case InventoryLocation::DETACHED:
1322 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1326 sanity_check(false); // abort
1331 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1333 std::vector<u16> clients = m_clients.getClientIDs();
1335 // Set the modified blocks unsent for all the clients
1336 for (std::vector<u16>::iterator i = clients.begin();
1337 i != clients.end(); ++i) {
1338 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1339 client->SetBlocksNotSent(block);
1344 void Server::peerAdded(con::Peer *peer)
1346 DSTACK(__FUNCTION_NAME);
1347 verbosestream<<"Server::peerAdded(): peer->id="
1348 <<peer->id<<std::endl;
1351 c.type = con::PEER_ADDED;
1352 c.peer_id = peer->id;
1354 m_peer_change_queue.push(c);
1357 void Server::deletingPeer(con::Peer *peer, bool timeout)
1359 DSTACK(__FUNCTION_NAME);
1360 verbosestream<<"Server::deletingPeer(): peer->id="
1361 <<peer->id<<", timeout="<<timeout<<std::endl;
1363 m_clients.event(peer->id, CSE_Disconnect);
1365 c.type = con::PEER_REMOVED;
1366 c.peer_id = peer->id;
1367 c.timeout = timeout;
1368 m_peer_change_queue.push(c);
1371 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1373 *retval = m_con.getPeerStat(peer_id,type);
1374 if (*retval == -1) return false;
1378 bool Server::getClientInfo(
1387 std::string* vers_string
1390 *state = m_clients.getClientState(peer_id);
1392 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1394 if (client == NULL) {
1399 *uptime = client->uptime();
1400 *ser_vers = client->serialization_version;
1401 *prot_vers = client->net_proto_version;
1403 *major = client->getMajor();
1404 *minor = client->getMinor();
1405 *patch = client->getPatch();
1406 *vers_string = client->getPatch();
1413 void Server::handlePeerChanges()
1415 while(m_peer_change_queue.size() > 0)
1417 con::PeerChange c = m_peer_change_queue.front();
1418 m_peer_change_queue.pop();
1420 verbosestream<<"Server: Handling peer change: "
1421 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1426 case con::PEER_ADDED:
1427 m_clients.CreateClient(c.peer_id);
1430 case con::PEER_REMOVED:
1431 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1435 FATAL_ERROR("Invalid peer change event received!");
1441 void Server::Send(NetworkPacket* pkt)
1443 m_clients.send(pkt->getPeerId(),
1444 clientCommandFactoryTable[pkt->getCommand()].channel,
1446 clientCommandFactoryTable[pkt->getCommand()].reliable);
1449 void Server::SendMovement(u16 peer_id)
1451 DSTACK(__FUNCTION_NAME);
1452 std::ostringstream os(std::ios_base::binary);
1454 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1456 pkt << g_settings->getFloat("movement_acceleration_default");
1457 pkt << g_settings->getFloat("movement_acceleration_air");
1458 pkt << g_settings->getFloat("movement_acceleration_fast");
1459 pkt << g_settings->getFloat("movement_speed_walk");
1460 pkt << g_settings->getFloat("movement_speed_crouch");
1461 pkt << g_settings->getFloat("movement_speed_fast");
1462 pkt << g_settings->getFloat("movement_speed_climb");
1463 pkt << g_settings->getFloat("movement_speed_jump");
1464 pkt << g_settings->getFloat("movement_liquid_fluidity");
1465 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1466 pkt << g_settings->getFloat("movement_liquid_sink");
1467 pkt << g_settings->getFloat("movement_gravity");
1472 void Server::SendHP(u16 peer_id, u8 hp)
1474 DSTACK(__FUNCTION_NAME);
1476 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1481 void Server::SendBreath(u16 peer_id, u16 breath)
1483 DSTACK(__FUNCTION_NAME);
1485 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1486 pkt << (u16) breath;
1490 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
1492 DSTACK(__FUNCTION_NAME);
1494 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1497 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1498 pkt << custom_reason;
1503 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1505 DSTACK(__FUNCTION_NAME);
1507 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1512 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1513 v3f camera_point_target)
1515 DSTACK(__FUNCTION_NAME);
1517 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1518 pkt << set_camera_point_target << camera_point_target;
1522 void Server::SendItemDef(u16 peer_id,
1523 IItemDefManager *itemdef, u16 protocol_version)
1525 DSTACK(__FUNCTION_NAME);
1527 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1531 u32 length of the next item
1532 zlib-compressed serialized ItemDefManager
1534 std::ostringstream tmp_os(std::ios::binary);
1535 itemdef->serialize(tmp_os, protocol_version);
1536 std::ostringstream tmp_os2(std::ios::binary);
1537 compressZlib(tmp_os.str(), tmp_os2);
1538 pkt.putLongString(tmp_os2.str());
1541 verbosestream << "Server: Sending item definitions to id(" << peer_id
1542 << "): size=" << pkt.getSize() << std::endl;
1547 void Server::SendNodeDef(u16 peer_id,
1548 INodeDefManager *nodedef, u16 protocol_version)
1550 DSTACK(__FUNCTION_NAME);
1552 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1556 u32 length of the next item
1557 zlib-compressed serialized NodeDefManager
1559 std::ostringstream tmp_os(std::ios::binary);
1560 nodedef->serialize(tmp_os, protocol_version);
1561 std::ostringstream tmp_os2(std::ios::binary);
1562 compressZlib(tmp_os.str(), tmp_os2);
1564 pkt.putLongString(tmp_os2.str());
1567 verbosestream << "Server: Sending node definitions to id(" << peer_id
1568 << "): size=" << pkt.getSize() << std::endl;
1574 Non-static send methods
1577 void Server::SendInventory(PlayerSAO* playerSAO)
1579 DSTACK(__FUNCTION_NAME);
1581 UpdateCrafting(playerSAO->getPlayer());
1587 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1589 std::ostringstream os;
1590 playerSAO->getInventory()->serialize(os);
1592 std::string s = os.str();
1594 pkt.putRawString(s.c_str(), s.size());
1598 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1600 DSTACK(__FUNCTION_NAME);
1602 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1605 if (peer_id != PEER_ID_INEXISTENT) {
1609 m_clients.sendToAll(0, &pkt, true);
1613 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1614 const std::string &formname)
1616 DSTACK(__FUNCTION_NAME);
1618 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1620 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1626 // Spawns a particle on peer with peer_id
1627 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1628 float expirationtime, float size, bool collisiondetection,
1629 bool vertical, std::string texture)
1631 DSTACK(__FUNCTION_NAME);
1633 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1635 pkt << pos << velocity << acceleration << expirationtime
1636 << size << collisiondetection;
1637 pkt.putLongString(texture);
1640 if (peer_id != PEER_ID_INEXISTENT) {
1644 m_clients.sendToAll(0, &pkt, true);
1648 // Adds a ParticleSpawner on peer with peer_id
1649 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1650 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1651 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1653 DSTACK(__FUNCTION_NAME);
1655 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1657 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1658 << minacc << maxacc << minexptime << maxexptime << minsize
1659 << maxsize << collisiondetection;
1661 pkt.putLongString(texture);
1663 pkt << id << vertical;
1665 if (peer_id != PEER_ID_INEXISTENT) {
1669 m_clients.sendToAll(0, &pkt, true);
1673 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1675 DSTACK(__FUNCTION_NAME);
1677 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1679 // Ugly error in this packet
1682 if (peer_id != PEER_ID_INEXISTENT) {
1686 m_clients.sendToAll(0, &pkt, true);
1691 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1693 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1695 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1696 << form->text << form->number << form->item << form->dir
1697 << form->align << form->offset << form->world_pos << form->size;
1702 void Server::SendHUDRemove(u16 peer_id, u32 id)
1704 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1709 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1711 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1712 pkt << id << (u8) stat;
1716 case HUD_STAT_SCALE:
1717 case HUD_STAT_ALIGN:
1718 case HUD_STAT_OFFSET:
1719 pkt << *(v2f *) value;
1723 pkt << *(std::string *) value;
1725 case HUD_STAT_WORLD_POS:
1726 pkt << *(v3f *) value;
1729 pkt << *(v2s32 *) value;
1731 case HUD_STAT_NUMBER:
1735 pkt << *(u32 *) value;
1742 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1744 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1746 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1748 pkt << flags << mask;
1753 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1755 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1756 pkt << param << value;
1760 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1761 const std::string &type, const std::vector<std::string> ¶ms)
1763 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1764 pkt << bgcolor << type << (u16) params.size();
1766 for(size_t i=0; i<params.size(); i++)
1772 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1775 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1778 pkt << do_override << (u16) (ratio * 65535);
1783 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1785 DSTACK(__FUNCTION_NAME);
1787 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1788 pkt << time << time_speed;
1790 if (peer_id == PEER_ID_INEXISTENT) {
1791 m_clients.sendToAll(0, &pkt, true);
1798 void Server::SendPlayerHP(u16 peer_id)
1800 DSTACK(__FUNCTION_NAME);
1801 PlayerSAO *playersao = getPlayerSAO(peer_id);
1803 SendHP(peer_id, playersao->getHP());
1804 m_script->player_event(playersao,"health_changed");
1806 // Send to other clients
1807 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1808 ActiveObjectMessage aom(playersao->getId(), true, str);
1809 playersao->m_messages_out.push(aom);
1812 void Server::SendPlayerBreath(u16 peer_id)
1814 DSTACK(__FUNCTION_NAME);
1815 PlayerSAO *playersao = getPlayerSAO(peer_id);
1818 m_script->player_event(playersao, "breath_changed");
1819 SendBreath(peer_id, playersao->getBreath());
1822 void Server::SendMovePlayer(u16 peer_id)
1824 DSTACK(__FUNCTION_NAME);
1825 Player *player = m_env->getPlayer(peer_id);
1828 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1829 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1832 v3f pos = player->getPosition();
1833 f32 pitch = player->getPitch();
1834 f32 yaw = player->getYaw();
1835 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1836 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1837 << " pitch=" << pitch
1845 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1847 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1850 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1851 << animation_frames[3] << animation_speed;
1856 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1858 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1859 pkt << first << third;
1862 void Server::SendPlayerPrivileges(u16 peer_id)
1864 Player *player = m_env->getPlayer(peer_id);
1866 if(player->peer_id == PEER_ID_INEXISTENT)
1869 std::set<std::string> privs;
1870 m_script->getAuth(player->getName(), NULL, &privs);
1872 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1873 pkt << (u16) privs.size();
1875 for(std::set<std::string>::const_iterator i = privs.begin();
1876 i != privs.end(); i++) {
1883 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1885 Player *player = m_env->getPlayer(peer_id);
1887 if(player->peer_id == PEER_ID_INEXISTENT)
1890 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1891 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1895 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1897 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, peer_id);
1898 pkt.putRawString(datas.c_str(), datas.size());
1900 return pkt.getSize();
1903 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1905 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1908 pkt.putRawString(datas.c_str(), datas.size());
1910 m_clients.send(pkt.getPeerId(),
1911 clientCommandFactoryTable[pkt.getCommand()].channel,
1916 s32 Server::playSound(const SimpleSoundSpec &spec,
1917 const ServerSoundParams ¶ms)
1919 // Find out initial position of sound
1920 bool pos_exists = false;
1921 v3f pos = params.getPos(m_env, &pos_exists);
1922 // If position is not found while it should be, cancel sound
1923 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1926 // Filter destination clients
1927 std::vector<u16> dst_clients;
1928 if(params.to_player != "")
1930 Player *player = m_env->getPlayer(params.to_player.c_str());
1932 infostream<<"Server::playSound: Player \""<<params.to_player
1933 <<"\" not found"<<std::endl;
1936 if(player->peer_id == PEER_ID_INEXISTENT){
1937 infostream<<"Server::playSound: Player \""<<params.to_player
1938 <<"\" not connected"<<std::endl;
1941 dst_clients.push_back(player->peer_id);
1944 std::vector<u16> clients = m_clients.getClientIDs();
1946 for(std::vector<u16>::iterator
1947 i = clients.begin(); i != clients.end(); ++i) {
1948 Player *player = m_env->getPlayer(*i);
1953 if(player->getPosition().getDistanceFrom(pos) >
1954 params.max_hear_distance)
1957 dst_clients.push_back(*i);
1961 if(dst_clients.empty())
1965 s32 id = m_next_sound_id++;
1966 // The sound will exist as a reference in m_playing_sounds
1967 m_playing_sounds[id] = ServerPlayingSound();
1968 ServerPlayingSound &psound = m_playing_sounds[id];
1969 psound.params = params;
1971 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1972 pkt << id << spec.name << (float) (spec.gain * params.gain)
1973 << (u8) params.type << pos << params.object << params.loop;
1975 for(std::vector<u16>::iterator i = dst_clients.begin();
1976 i != dst_clients.end(); i++) {
1977 psound.clients.insert(*i);
1978 m_clients.send(*i, 0, &pkt, true);
1982 void Server::stopSound(s32 handle)
1984 // Get sound reference
1985 std::map<s32, ServerPlayingSound>::iterator i =
1986 m_playing_sounds.find(handle);
1987 if(i == m_playing_sounds.end())
1989 ServerPlayingSound &psound = i->second;
1991 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
1994 for(std::set<u16>::iterator i = psound.clients.begin();
1995 i != psound.clients.end(); i++) {
1997 m_clients.send(*i, 0, &pkt, true);
1999 // Remove sound reference
2000 m_playing_sounds.erase(i);
2003 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2004 std::vector<u16> *far_players, float far_d_nodes)
2006 float maxd = far_d_nodes*BS;
2007 v3f p_f = intToFloat(p, BS);
2009 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2012 std::vector<u16> clients = m_clients.getClientIDs();
2013 for(std::vector<u16>::iterator i = clients.begin();
2014 i != clients.end(); ++i) {
2017 if(Player *player = m_env->getPlayer(*i)) {
2018 // If player is far away, only set modified blocks not sent
2019 v3f player_pos = player->getPosition();
2020 if(player_pos.getDistanceFrom(p_f) > maxd) {
2021 far_players->push_back(*i);
2028 m_clients.send(*i, 0, &pkt, true);
2032 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2033 std::vector<u16> *far_players, float far_d_nodes,
2034 bool remove_metadata)
2036 float maxd = far_d_nodes*BS;
2037 v3f p_f = intToFloat(p, BS);
2039 std::vector<u16> clients = m_clients.getClientIDs();
2040 for(std::vector<u16>::iterator i = clients.begin();
2041 i != clients.end(); ++i) {
2045 if(Player *player = m_env->getPlayer(*i)) {
2046 // If player is far away, only set modified blocks not sent
2047 v3f player_pos = player->getPosition();
2048 if(player_pos.getDistanceFrom(p_f) > maxd) {
2049 far_players->push_back(*i);
2055 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2057 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2059 pkt << p << n.param0 << n.param1 << n.param2
2060 << (u8) (remove_metadata ? 0 : 1);
2062 if (!remove_metadata) {
2063 if (client->net_proto_version <= 21) {
2064 // Old clients always clear metadata; fix it
2065 // by sending the full block again.
2066 client->SetBlockNotSent(p);
2073 if (pkt.getSize() > 0)
2074 m_clients.send(*i, 0, &pkt, true);
2078 void Server::setBlockNotSent(v3s16 p)
2080 std::vector<u16> clients = m_clients.getClientIDs();
2082 for(std::vector<u16>::iterator i = clients.begin();
2083 i != clients.end(); ++i) {
2084 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2085 client->SetBlockNotSent(p);
2090 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2092 DSTACK(__FUNCTION_NAME);
2094 v3s16 p = block->getPos();
2097 Create a packet with the block in the right format
2100 std::ostringstream os(std::ios_base::binary);
2101 block->serialize(os, ver, false);
2102 block->serializeNetworkSpecific(os, net_proto_version);
2103 std::string s = os.str();
2105 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 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);
2309 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2310 pkt << (u16) file_announcements.size();
2312 for (std::vector<SendableMediaAnnouncement>::iterator
2313 j = file_announcements.begin();
2314 j != file_announcements.end(); ++j) {
2315 pkt << j->name << j->sha1_digest;
2318 pkt << g_settings->get("remote_media");
2322 struct SendableMedia
2328 SendableMedia(const std::string &name_="", const std::string &path_="",
2329 const std::string &data_=""):
2336 void Server::sendRequestedMedia(u16 peer_id,
2337 const std::vector<std::string> &tosend)
2339 DSTACK(__FUNCTION_NAME);
2341 verbosestream<<"Server::sendRequestedMedia(): "
2342 <<"Sending files to client"<<std::endl;
2346 // Put 5kB in one bunch (this is not accurate)
2347 u32 bytes_per_bunch = 5000;
2349 std::vector< std::vector<SendableMedia> > file_bunches;
2350 file_bunches.push_back(std::vector<SendableMedia>());
2352 u32 file_size_bunch_total = 0;
2354 for(std::vector<std::string>::const_iterator i = tosend.begin();
2355 i != tosend.end(); ++i) {
2356 const std::string &name = *i;
2358 if(m_media.find(name) == m_media.end()) {
2359 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2360 <<"unknown file \""<<(name)<<"\""<<std::endl;
2364 //TODO get path + name
2365 std::string tpath = m_media[name].path;
2368 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2369 if(fis.good() == false){
2370 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2371 <<tpath<<"\" for reading"<<std::endl;
2374 std::ostringstream tmp_os(std::ios_base::binary);
2378 fis.read(buf, 1024);
2379 std::streamsize len = fis.gcount();
2380 tmp_os.write(buf, len);
2381 file_size_bunch_total += len;
2390 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2391 <<name<<"\""<<std::endl;
2394 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2395 <<tname<<"\""<<std::endl;*/
2397 file_bunches[file_bunches.size()-1].push_back(
2398 SendableMedia(name, tpath, tmp_os.str()));
2400 // Start next bunch if got enough data
2401 if(file_size_bunch_total >= bytes_per_bunch) {
2402 file_bunches.push_back(std::vector<SendableMedia>());
2403 file_size_bunch_total = 0;
2408 /* Create and send packets */
2410 u16 num_bunches = file_bunches.size();
2411 for(u16 i = 0; i < num_bunches; i++) {
2414 u16 total number of texture bunches
2415 u16 index of this bunch
2416 u32 number of files in this bunch
2425 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2426 pkt << num_bunches << i << (u32) file_bunches[i].size();
2428 for(std::vector<SendableMedia>::iterator
2429 j = file_bunches[i].begin();
2430 j != file_bunches[i].end(); ++j) {
2432 pkt.putLongString(j->data);
2435 verbosestream << "Server::sendRequestedMedia(): bunch "
2436 << i << "/" << num_bunches
2437 << " files=" << file_bunches[i].size()
2438 << " size=" << pkt.getSize() << std::endl;
2443 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2445 if(m_detached_inventories.count(name) == 0) {
2446 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2449 Inventory *inv = m_detached_inventories[name];
2450 std::ostringstream os(std::ios_base::binary);
2452 os << serializeString(name);
2456 std::string s = os.str();
2458 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2459 pkt.putRawString(s.c_str(), s.size());
2461 if (peer_id != PEER_ID_INEXISTENT) {
2465 m_clients.sendToAll(0, &pkt, true);
2469 void Server::sendDetachedInventories(u16 peer_id)
2471 DSTACK(__FUNCTION_NAME);
2473 for(std::map<std::string, Inventory*>::iterator
2474 i = m_detached_inventories.begin();
2475 i != m_detached_inventories.end(); i++) {
2476 const std::string &name = i->first;
2477 //Inventory *inv = i->second;
2478 sendDetachedInventory(name, peer_id);
2486 void Server::DiePlayer(u16 peer_id)
2488 DSTACK(__FUNCTION_NAME);
2490 PlayerSAO *playersao = getPlayerSAO(peer_id);
2493 infostream << "Server::DiePlayer(): Player "
2494 << playersao->getPlayer()->getName()
2495 << " dies" << std::endl;
2497 playersao->setHP(0);
2499 // Trigger scripted stuff
2500 m_script->on_dieplayer(playersao);
2502 SendPlayerHP(peer_id);
2503 SendDeathscreen(peer_id, false, v3f(0,0,0));
2506 void Server::RespawnPlayer(u16 peer_id)
2508 DSTACK(__FUNCTION_NAME);
2510 PlayerSAO *playersao = getPlayerSAO(peer_id);
2513 infostream << "Server::RespawnPlayer(): Player "
2514 << playersao->getPlayer()->getName()
2515 << " respawns" << std::endl;
2517 playersao->setHP(PLAYER_MAX_HP);
2518 playersao->setBreath(PLAYER_MAX_BREATH);
2520 SendPlayerHP(peer_id);
2521 SendPlayerBreath(peer_id);
2523 bool repositioned = m_script->on_respawnplayer(playersao);
2525 v3f pos = findSpawnPos(m_env->getServerMap());
2526 // setPos will send the new position to client
2527 playersao->setPos(pos);
2531 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2533 DSTACK(__FUNCTION_NAME);
2535 SendAccessDenied(peer_id, reason, custom_reason);
2536 m_clients.event(peer_id, CSE_SetDenied);
2537 m_con.DisconnectPeer(peer_id);
2540 // 13/03/15: remove this function when protocol version 25 will become
2541 // the minimum version for MT users, maybe in 1 year
2542 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2544 DSTACK(__FUNCTION_NAME);
2546 SendAccessDenied_Legacy(peer_id, reason);
2547 m_clients.event(peer_id, CSE_SetDenied);
2548 m_con.DisconnectPeer(peer_id);
2551 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2553 DSTACK(__FUNCTION_NAME);
2554 std::wstring message;
2557 Clear references to playing sounds
2559 for(std::map<s32, ServerPlayingSound>::iterator
2560 i = m_playing_sounds.begin();
2561 i != m_playing_sounds.end();)
2563 ServerPlayingSound &psound = i->second;
2564 psound.clients.erase(peer_id);
2565 if(psound.clients.empty())
2566 m_playing_sounds.erase(i++);
2571 Player *player = m_env->getPlayer(peer_id);
2573 // Collect information about leaving in chat
2575 if(player != NULL && reason != CDR_DENY)
2577 std::wstring name = narrow_to_wide(player->getName());
2580 message += L" left the game.";
2581 if(reason == CDR_TIMEOUT)
2582 message += L" (timed out)";
2586 /* Run scripts and remove from environment */
2590 PlayerSAO *playersao = player->getPlayerSAO();
2593 m_script->on_leaveplayer(playersao);
2595 playersao->disconnected();
2603 if(player != NULL && reason != CDR_DENY) {
2604 std::ostringstream os(std::ios_base::binary);
2605 std::vector<u16> clients = m_clients.getClientIDs();
2607 for(std::vector<u16>::iterator i = clients.begin();
2608 i != clients.end(); ++i) {
2610 Player *player = m_env->getPlayer(*i);
2614 // Get name of player
2615 os << player->getName() << " ";
2618 actionstream << player->getName() << " "
2619 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2620 << " List of players: " << os.str() << std::endl;
2624 JMutexAutoLock env_lock(m_env_mutex);
2625 m_clients.DeleteClient(peer_id);
2629 // Send leave chat message to all remaining clients
2630 if(message.length() != 0)
2631 SendChatMessage(PEER_ID_INEXISTENT,message);
2634 void Server::UpdateCrafting(Player* player)
2636 DSTACK(__FUNCTION_NAME);
2638 // Get a preview for crafting
2640 InventoryLocation loc;
2641 loc.setPlayer(player->getName());
2642 getCraftingResult(&player->inventory, preview, false, this);
2643 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2645 // Put the new preview in
2646 InventoryList *plist = player->inventory.getList("craftpreview");
2647 sanity_check(plist);
2648 sanity_check(plist->getSize() >= 1);
2649 plist->changeItem(0, preview);
2652 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2654 RemoteClient *client = getClientNoEx(peer_id,state_min);
2656 throw ClientNotFoundException("Client not found");
2660 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2662 return m_clients.getClientNoEx(peer_id, state_min);
2665 std::string Server::getPlayerName(u16 peer_id)
2667 Player *player = m_env->getPlayer(peer_id);
2669 return "[id="+itos(peer_id)+"]";
2670 return player->getName();
2673 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2675 Player *player = m_env->getPlayer(peer_id);
2678 return player->getPlayerSAO();
2681 std::wstring Server::getStatusString()
2683 std::wostringstream os(std::ios_base::binary);
2686 os<<L"version="<<narrow_to_wide(g_version_string);
2688 os<<L", uptime="<<m_uptime.get();
2690 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2691 // Information about clients
2694 std::vector<u16> clients = m_clients.getClientIDs();
2695 for(std::vector<u16>::iterator i = clients.begin();
2696 i != clients.end(); ++i) {
2698 Player *player = m_env->getPlayer(*i);
2699 // Get name of player
2700 std::wstring name = L"unknown";
2702 name = narrow_to_wide(player->getName());
2703 // Add name to information string
2711 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2712 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2713 if(g_settings->get("motd") != "")
2714 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2718 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2720 std::set<std::string> privs;
2721 m_script->getAuth(name, NULL, &privs);
2725 bool Server::checkPriv(const std::string &name, const std::string &priv)
2727 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2728 return (privs.count(priv) != 0);
2731 void Server::reportPrivsModified(const std::string &name)
2734 std::vector<u16> clients = m_clients.getClientIDs();
2735 for(std::vector<u16>::iterator i = clients.begin();
2736 i != clients.end(); ++i) {
2737 Player *player = m_env->getPlayer(*i);
2738 reportPrivsModified(player->getName());
2741 Player *player = m_env->getPlayer(name.c_str());
2744 SendPlayerPrivileges(player->peer_id);
2745 PlayerSAO *sao = player->getPlayerSAO();
2748 sao->updatePrivileges(
2749 getPlayerEffectivePrivs(name),
2754 void Server::reportInventoryFormspecModified(const std::string &name)
2756 Player *player = m_env->getPlayer(name.c_str());
2759 SendPlayerInventoryFormspec(player->peer_id);
2762 void Server::setIpBanned(const std::string &ip, const std::string &name)
2764 m_banmanager->add(ip, name);
2767 void Server::unsetIpBanned(const std::string &ip_or_name)
2769 m_banmanager->remove(ip_or_name);
2772 std::string Server::getBanDescription(const std::string &ip_or_name)
2774 return m_banmanager->getBanDescription(ip_or_name);
2777 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2779 Player *player = m_env->getPlayer(name);
2783 if (player->peer_id == PEER_ID_INEXISTENT)
2786 SendChatMessage(player->peer_id, msg);
2789 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2791 Player *player = m_env->getPlayer(playername);
2795 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2799 SendShowFormspecMessage(player->peer_id, formspec, formname);
2803 u32 Server::hudAdd(Player *player, HudElement *form) {
2807 u32 id = player->addHud(form);
2809 SendHUDAdd(player->peer_id, id, form);
2814 bool Server::hudRemove(Player *player, u32 id) {
2818 HudElement* todel = player->removeHud(id);
2825 SendHUDRemove(player->peer_id, id);
2829 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2833 SendHUDChange(player->peer_id, id, stat, data);
2837 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2841 SendHUDSetFlags(player->peer_id, flags, mask);
2842 player->hud_flags = flags;
2844 PlayerSAO* playersao = player->getPlayerSAO();
2846 if (playersao == NULL)
2849 m_script->player_event(playersao, "hud_changed");
2853 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2856 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2859 std::ostringstream os(std::ios::binary);
2860 writeS32(os, hotbar_itemcount);
2861 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2865 void Server::hudSetHotbarImage(Player *player, std::string name) {
2869 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2872 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2876 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2879 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2884 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2888 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2893 SendEyeOffset(player->peer_id, first, third);
2897 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2898 const std::string &type, const std::vector<std::string> ¶ms)
2903 SendSetSky(player->peer_id, bgcolor, type, params);
2907 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2913 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2917 void Server::notifyPlayers(const std::wstring &msg)
2919 SendChatMessage(PEER_ID_INEXISTENT,msg);
2922 void Server::spawnParticle(const char *playername, v3f pos,
2923 v3f velocity, v3f acceleration,
2924 float expirationtime, float size, bool
2925 collisiondetection, bool vertical, std::string texture)
2927 Player *player = m_env->getPlayer(playername);
2930 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2931 expirationtime, size, collisiondetection, vertical, texture);
2934 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2935 float expirationtime, float size,
2936 bool collisiondetection, bool vertical, std::string texture)
2938 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2939 expirationtime, size, collisiondetection, vertical, texture);
2942 u32 Server::addParticleSpawner(const char *playername,
2943 u16 amount, float spawntime,
2944 v3f minpos, v3f maxpos,
2945 v3f minvel, v3f maxvel,
2946 v3f minacc, v3f maxacc,
2947 float minexptime, float maxexptime,
2948 float minsize, float maxsize,
2949 bool collisiondetection, bool vertical, std::string texture)
2951 Player *player = m_env->getPlayer(playername);
2956 for(;;) // look for unused particlespawner id
2959 if (std::find(m_particlespawner_ids.begin(),
2960 m_particlespawner_ids.end(), id)
2961 == m_particlespawner_ids.end())
2963 m_particlespawner_ids.push_back(id);
2968 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2969 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2970 minexptime, maxexptime, minsize, maxsize,
2971 collisiondetection, vertical, texture, id);
2976 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2977 v3f minpos, v3f maxpos,
2978 v3f minvel, v3f maxvel,
2979 v3f minacc, v3f maxacc,
2980 float minexptime, float maxexptime,
2981 float minsize, float maxsize,
2982 bool collisiondetection, bool vertical, std::string texture)
2985 for(;;) // look for unused particlespawner id
2988 if (std::find(m_particlespawner_ids.begin(),
2989 m_particlespawner_ids.end(), id)
2990 == m_particlespawner_ids.end())
2992 m_particlespawner_ids.push_back(id);
2997 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2998 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2999 minexptime, maxexptime, minsize, maxsize,
3000 collisiondetection, vertical, texture, id);
3005 void Server::deleteParticleSpawner(const char *playername, u32 id)
3007 Player *player = m_env->getPlayer(playername);
3011 m_particlespawner_ids.erase(
3012 std::remove(m_particlespawner_ids.begin(),
3013 m_particlespawner_ids.end(), id),
3014 m_particlespawner_ids.end());
3015 SendDeleteParticleSpawner(player->peer_id, id);
3018 void Server::deleteParticleSpawnerAll(u32 id)
3020 m_particlespawner_ids.erase(
3021 std::remove(m_particlespawner_ids.begin(),
3022 m_particlespawner_ids.end(), id),
3023 m_particlespawner_ids.end());
3024 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3027 Inventory* Server::createDetachedInventory(const std::string &name)
3029 if(m_detached_inventories.count(name) > 0){
3030 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3031 delete m_detached_inventories[name];
3033 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3035 Inventory *inv = new Inventory(m_itemdef);
3037 m_detached_inventories[name] = inv;
3038 //TODO find a better way to do this
3039 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3046 BoolScopeSet(bool *dst, bool val):
3049 m_orig_state = *m_dst;
3054 *m_dst = m_orig_state;
3061 // actions: time-reversed list
3062 // Return value: success/failure
3063 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3064 std::list<std::string> *log)
3066 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3067 ServerMap *map = (ServerMap*)(&m_env->getMap());
3069 // Fail if no actions to handle
3070 if(actions.empty()){
3071 log->push_back("Nothing to do.");
3078 for(std::list<RollbackAction>::const_iterator
3079 i = actions.begin();
3080 i != actions.end(); i++)
3082 const RollbackAction &action = *i;
3084 bool success = action.applyRevert(map, this, this);
3087 std::ostringstream os;
3088 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3089 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3091 log->push_back(os.str());
3093 std::ostringstream os;
3094 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3095 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3097 log->push_back(os.str());
3101 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3102 <<" failed"<<std::endl;
3104 // Call it done if less than half failed
3105 return num_failed <= num_tried/2;
3108 // IGameDef interface
3110 IItemDefManager* Server::getItemDefManager()
3114 INodeDefManager* Server::getNodeDefManager()
3118 ICraftDefManager* Server::getCraftDefManager()
3122 ITextureSource* Server::getTextureSource()
3126 IShaderSource* Server::getShaderSource()
3130 scene::ISceneManager* Server::getSceneManager()
3135 u16 Server::allocateUnknownNodeId(const std::string &name)
3137 return m_nodedef->allocateDummy(name);
3139 ISoundManager* Server::getSoundManager()
3141 return &dummySoundManager;
3143 MtEventManager* Server::getEventManager()
3148 IWritableItemDefManager* Server::getWritableItemDefManager()
3152 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3156 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3161 const ModSpec* Server::getModSpec(const std::string &modname)
3163 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3164 i != m_mods.end(); i++){
3165 const ModSpec &mod = *i;
3166 if(mod.name == modname)
3171 void Server::getModNames(std::vector<std::string> &modlist)
3173 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3174 modlist.push_back(i->name);
3177 std::string Server::getBuiltinLuaPath()
3179 return porting::path_share + DIR_DELIM + "builtin";
3182 v3f findSpawnPos(ServerMap &map)
3184 //return v3f(50,50,50)*BS;
3189 nodepos = v2s16(0,0);
3194 s16 water_level = map.getWaterLevel();
3196 // Try to find a good place a few times
3197 for(s32 i=0; i<1000; i++)
3200 // We're going to try to throw the player to this position
3201 v2s16 nodepos2d = v2s16(
3202 -range + (myrand() % (range * 2)),
3203 -range + (myrand() % (range * 2)));
3205 // Get ground height at point
3206 s16 groundheight = map.findGroundLevel(nodepos2d);
3207 if (groundheight <= water_level) // Don't go underwater
3209 if (groundheight > water_level + 6) // Don't go to high places
3212 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3213 bool is_good = false;
3215 for (s32 i = 0; i < 10; i++) {
3216 v3s16 blockpos = getNodeBlockPos(nodepos);
3217 map.emergeBlock(blockpos, true);
3218 content_t c = map.getNodeNoEx(nodepos).getContent();
3219 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3221 if (air_count >= 2){
3229 // Found a good place
3230 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3236 return intToFloat(nodepos, BS);
3239 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3241 bool newplayer = false;
3244 Try to get an existing player
3246 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3248 // If player is already connected, cancel
3249 if(player != NULL && player->peer_id != 0)
3251 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3256 If player with the wanted peer_id already exists, cancel.
3258 if(m_env->getPlayer(peer_id) != NULL)
3260 infostream<<"emergePlayer(): Player with wrong name but same"
3261 " peer_id already exists"<<std::endl;
3265 // Load player if it isn't already loaded
3267 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3270 // Create player if it doesn't exist
3273 player = new RemotePlayer(this, name);
3274 // Set player position
3275 infostream<<"Server: Finding spawn place for player \""
3276 <<name<<"\""<<std::endl;
3277 v3f pos = findSpawnPos(m_env->getServerMap());
3278 player->setPosition(pos);
3280 // Make sure the player is saved
3281 player->setModified(true);
3283 // Add player to environment
3284 m_env->addPlayer(player);
3287 // Create a new player active object
3288 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3289 getPlayerEffectivePrivs(player->getName()),
3292 /* Clean up old HUD elements from previous sessions */
3295 /* Add object to environment */
3296 m_env->addActiveObject(playersao);
3300 m_script->on_newplayer(playersao);
3306 void dedicated_server_loop(Server &server, bool &kill)
3308 DSTACK(__FUNCTION_NAME);
3310 verbosestream<<"dedicated_server_loop()"<<std::endl;
3312 IntervalLimiter m_profiler_interval;
3316 float steplen = g_settings->getFloat("dedicated_server_step");
3317 // This is kind of a hack but can be done like this
3318 // because server.step() is very light
3320 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3321 sleep_ms((int)(steplen*1000.0));
3323 server.step(steplen);
3325 if(server.getShutdownRequested() || kill)
3327 infostream<<"Dedicated server quitting"<<std::endl;
3329 if(g_settings->getBool("server_announce"))
3330 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3338 float profiler_print_interval =
3339 g_settings->getFloat("profiler_print_interval");
3340 if(profiler_print_interval != 0)
3342 if(m_profiler_interval.step(steplen, profiler_print_interval))
3344 infostream<<"Profiler:"<<std::endl;
3345 g_profiler->print(infostream);
3346 g_profiler->clear();