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()) {
243 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
244 it != unsatisfied_mods.end(); ++it) {
246 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
247 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
248 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
249 errorstream << " \"" << *dep_it << "\"";
250 errorstream << std::endl;
254 Settings worldmt_settings;
255 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
256 worldmt_settings.readConfigFile(worldmt.c_str());
257 std::vector<std::string> names = worldmt_settings.getNames();
258 std::set<std::string> load_mod_names;
259 for(std::vector<std::string>::iterator it = names.begin();
260 it != names.end(); ++it) {
261 std::string name = *it;
262 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
263 load_mod_names.insert(name.substr(9));
265 // complain about mods declared to be loaded, but not found
266 for(std::vector<ModSpec>::iterator it = m_mods.begin();
267 it != m_mods.end(); ++it)
268 load_mod_names.erase((*it).name);
269 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
270 it != unsatisfied_mods.end(); ++it)
271 load_mod_names.erase((*it).name);
272 if(!load_mod_names.empty()) {
273 errorstream << "The following mods could not be found:";
274 for(std::set<std::string>::iterator it = load_mod_names.begin();
275 it != load_mod_names.end(); ++it)
276 errorstream << " \"" << (*it) << "\"";
277 errorstream << std::endl;
281 JMutexAutoLock envlock(m_env_mutex);
283 // Load mapgen params from Settings
284 m_emerge->loadMapgenParams();
286 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
287 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
289 // Initialize scripting
290 infostream<<"Server: Initializing Lua"<<std::endl;
292 m_script = new GameScripting(this);
294 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
295 std::string error_msg;
297 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
298 throw ModError("Failed to load and run " + script_path
299 + "\nError from Lua:\n" + error_msg);
302 infostream << "Server: Loading mods: ";
303 for(std::vector<ModSpec>::iterator i = m_mods.begin();
304 i != m_mods.end(); i++) {
305 const ModSpec &mod = *i;
306 infostream << mod.name << " ";
308 infostream << std::endl;
309 // Load and run "mod" scripts
310 for (std::vector<ModSpec>::iterator i = m_mods.begin();
311 i != m_mods.end(); i++) {
312 const ModSpec &mod = *i;
313 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
314 std::ostringstream err;
315 err << "Error loading mod \"" << mod.name
316 << "\": mod_name does not follow naming conventions: "
317 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
318 errorstream << err.str().c_str();
319 throw ModError(err.str());
321 std::string script_path = mod.path + DIR_DELIM "init.lua";
322 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
323 << script_path << "\"]" << std::endl;
324 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
325 errorstream << "Server: Failed to load and run "
326 << script_path << std::endl;
327 throw ModError("Failed to load and run " + script_path
328 + "\nError from Lua:\n" + error_msg);
332 // Read Textures and calculate sha1 sums
335 // Apply item aliases in the node definition manager
336 m_nodedef->updateAliases(m_itemdef);
338 // Apply texture overrides from texturepack/override.txt
339 std::string texture_path = g_settings->get("texture_path");
340 if (texture_path != "" && fs::IsDir(texture_path))
341 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
343 m_nodedef->setNodeRegistrationStatus(true);
345 // Perform pending node name resolutions
346 m_nodedef->runNodeResolveCallbacks();
348 // init the recipe hashes to speed up crafting
349 m_craftdef->initHashes(this);
351 // Initialize Environment
352 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
354 m_clients.setEnv(m_env);
356 // Initialize mapgens
357 m_emerge->initMapgens();
359 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
360 if (m_enable_rollback_recording) {
361 // Create rollback manager
362 m_rollback = new RollbackManager(m_path_world, this);
365 // Give environment reference to scripting api
366 m_script->initializeEnvironment(m_env);
368 // Register us to receive map edit events
369 servermap->addEventReceiver(this);
371 // If file exists, load environment metadata
372 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
374 infostream<<"Server: Loading environment metadata"<<std::endl;
378 // Add some test ActiveBlockModifiers to environment
379 add_legacy_abms(m_env, m_nodedef);
381 m_liquid_transform_every = g_settings->getFloat("liquid_update");
386 infostream<<"Server destructing"<<std::endl;
388 // Send shutdown message
389 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
392 JMutexAutoLock envlock(m_env_mutex);
394 // Execute script shutdown hooks
395 m_script->on_shutdown();
397 infostream << "Server: Saving players" << std::endl;
398 m_env->saveLoadedPlayers();
400 infostream << "Server: Kicking players" << std::endl;
401 m_env->kickAllPlayers(g_settings->get("kick_msg_shutdown"));
403 infostream << "Server: Saving environment metadata" << std::endl;
411 // stop all emerge threads before deleting players that may have
412 // requested blocks to be emerged
413 m_emerge->stopThreads();
415 // Delete things in the reverse order of creation
418 // N.B. the EmergeManager should be deleted after the Environment since Map
419 // depends on EmergeManager to write its current params to the map meta
428 // Deinitialize scripting
429 infostream<<"Server: Deinitializing scripting"<<std::endl;
432 // Delete detached inventories
433 for (std::map<std::string, Inventory*>::iterator
434 i = m_detached_inventories.begin();
435 i != m_detached_inventories.end(); i++) {
440 void Server::start(Address bind_addr)
442 DSTACK(__FUNCTION_NAME);
444 m_bind_addr = bind_addr;
446 infostream<<"Starting server on "
447 << bind_addr.serializeString() <<"..."<<std::endl;
449 // Stop thread if already running
452 // Initialize connection
453 m_con.SetTimeoutMs(30);
454 m_con.Serve(bind_addr);
459 // ASCII art for the win!
461 <<" .__ __ __ "<<std::endl
462 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
463 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
464 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
465 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
466 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
467 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
468 actionstream<<"Server for gameid=\""<<m_gamespec.id
469 <<"\" listening on "<<bind_addr.serializeString()<<":"
470 <<bind_addr.getPort() << "."<<std::endl;
475 DSTACK(__FUNCTION_NAME);
477 infostream<<"Server: Stopping and waiting threads"<<std::endl;
479 // Stop threads (set run=false first so both start stopping)
481 //m_emergethread.setRun(false);
483 //m_emergethread.stop();
485 infostream<<"Server: Threads stopped"<<std::endl;
488 void Server::step(float dtime)
490 DSTACK(__FUNCTION_NAME);
495 JMutexAutoLock lock(m_step_dtime_mutex);
496 m_step_dtime += dtime;
498 // Throw if fatal error occurred in thread
499 std::string async_err = m_async_fatal_error.get();
500 if(async_err != "") {
501 if (m_simple_singleplayer_mode) {
502 throw ServerError(async_err);
505 m_env->kickAllPlayers(g_settings->get("kick_msg_crash"));
506 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
507 << "Please fix the following error:" << std::endl
508 << async_err << std::endl;
509 FATAL_ERROR(async_err.c_str());
514 void Server::AsyncRunStep(bool initial_step)
516 DSTACK(__FUNCTION_NAME);
518 g_profiler->add("Server::AsyncRunStep (num)", 1);
522 JMutexAutoLock lock1(m_step_dtime_mutex);
523 dtime = m_step_dtime;
527 // Send blocks to clients
531 if((dtime < 0.001) && (initial_step == false))
534 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
536 //infostream<<"Server steps "<<dtime<<std::endl;
537 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
540 JMutexAutoLock lock1(m_step_dtime_mutex);
541 m_step_dtime -= dtime;
548 m_uptime.set(m_uptime.get() + dtime);
554 Update time of day and overall game time
556 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
559 Send to clients at constant intervals
562 m_time_of_day_send_timer -= dtime;
563 if(m_time_of_day_send_timer < 0.0) {
564 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
565 u16 time = m_env->getTimeOfDay();
566 float time_speed = g_settings->getFloat("time_speed");
567 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
571 JMutexAutoLock lock(m_env_mutex);
572 // Figure out and report maximum lag to environment
573 float max_lag = m_env->getMaxLagEstimate();
574 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
576 if(dtime > 0.1 && dtime > max_lag * 2.0)
577 infostream<<"Server: Maximum lag peaked to "<<dtime
581 m_env->reportMaxLagEstimate(max_lag);
583 ScopeProfiler sp(g_profiler, "SEnv step");
584 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
588 static const float map_timer_and_unload_dtime = 2.92;
589 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
591 JMutexAutoLock lock(m_env_mutex);
592 // Run Map's timers and unload unused data
593 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
594 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
595 g_settings->getFloat("server_unload_unused_data_timeout"));
602 /* Transform liquids */
603 m_liquid_transform_timer += dtime;
604 if(m_liquid_transform_timer >= m_liquid_transform_every)
606 m_liquid_transform_timer -= m_liquid_transform_every;
608 JMutexAutoLock lock(m_env_mutex);
610 ScopeProfiler sp(g_profiler, "Server: liquid transform");
612 std::map<v3s16, MapBlock*> modified_blocks;
613 m_env->getMap().transformLiquids(modified_blocks);
618 core::map<v3s16, MapBlock*> lighting_modified_blocks;
619 ServerMap &map = ((ServerMap&)m_env->getMap());
620 map.updateLighting(modified_blocks, lighting_modified_blocks);
622 // Add blocks modified by lighting to modified_blocks
623 for(core::map<v3s16, MapBlock*>::Iterator
624 i = lighting_modified_blocks.getIterator();
625 i.atEnd() == false; i++)
627 MapBlock *block = i.getNode()->getValue();
628 modified_blocks.insert(block->getPos(), block);
632 Set the modified blocks unsent for all the clients
634 if(!modified_blocks.empty())
636 SetBlocksNotSent(modified_blocks);
639 m_clients.step(dtime);
641 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
643 // send masterserver announce
645 float &counter = m_masterserver_timer;
646 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
647 g_settings->getBool("server_announce"))
649 ServerList::sendAnnounce(counter ? "update" : "start",
650 m_bind_addr.getPort(),
651 m_clients.getPlayerNames(),
653 m_env->getGameTime(),
656 m_emerge->params.mg_name,
665 Check added and deleted active objects
668 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
669 JMutexAutoLock envlock(m_env_mutex);
672 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
673 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
675 // Radius inside which objects are active
676 s16 radius = g_settings->getS16("active_object_send_range_blocks");
677 s16 player_radius = g_settings->getS16("player_transfer_distance");
679 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
680 !g_settings->getBool("unlimited_player_transfer_distance"))
681 player_radius = radius;
683 radius *= MAP_BLOCKSIZE;
684 player_radius *= MAP_BLOCKSIZE;
686 for(std::map<u16, RemoteClient*>::iterator
688 i != clients.end(); ++i)
690 RemoteClient *client = i->second;
692 // If definitions and textures have not been sent, don't
693 // send objects either
694 if (client->getState() < CS_DefinitionsSent)
697 Player *player = m_env->getPlayer(client->peer_id);
700 // This can happen if the client timeouts somehow
701 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
703 <<" has no associated player"<<std::endl;*/
706 v3s16 pos = floatToInt(player->getPosition(), BS);
708 std::set<u16> removed_objects;
709 std::set<u16> added_objects;
710 m_env->getRemovedActiveObjects(pos, radius, player_radius,
711 client->m_known_objects, removed_objects);
712 m_env->getAddedActiveObjects(pos, radius, player_radius,
713 client->m_known_objects, added_objects);
715 // Ignore if nothing happened
716 if(removed_objects.empty() && added_objects.empty())
718 //infostream<<"active objects: none changed"<<std::endl;
722 std::string data_buffer;
726 // Handle removed objects
727 writeU16((u8*)buf, removed_objects.size());
728 data_buffer.append(buf, 2);
729 for(std::set<u16>::iterator
730 i = removed_objects.begin();
731 i != removed_objects.end(); ++i)
735 ServerActiveObject* obj = m_env->getActiveObject(id);
737 // Add to data buffer for sending
738 writeU16((u8*)buf, id);
739 data_buffer.append(buf, 2);
741 // Remove from known objects
742 client->m_known_objects.erase(id);
744 if(obj && obj->m_known_by_count > 0)
745 obj->m_known_by_count--;
748 // Handle added objects
749 writeU16((u8*)buf, added_objects.size());
750 data_buffer.append(buf, 2);
751 for(std::set<u16>::iterator
752 i = added_objects.begin();
753 i != added_objects.end(); ++i)
757 ServerActiveObject* obj = m_env->getActiveObject(id);
760 u8 type = ACTIVEOBJECT_TYPE_INVALID;
762 infostream<<"WARNING: "<<__FUNCTION_NAME
763 <<": NULL object"<<std::endl;
765 type = obj->getSendType();
767 // Add to data buffer for sending
768 writeU16((u8*)buf, id);
769 data_buffer.append(buf, 2);
770 writeU8((u8*)buf, type);
771 data_buffer.append(buf, 1);
774 data_buffer.append(serializeLongString(
775 obj->getClientInitializationData(client->net_proto_version)));
777 data_buffer.append(serializeLongString(""));
779 // Add to known objects
780 client->m_known_objects.insert(id);
783 obj->m_known_by_count++;
786 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
787 verbosestream << "Server: Sent object remove/add: "
788 << removed_objects.size() << " removed, "
789 << added_objects.size() << " added, "
790 << "packet size is " << pktSize << std::endl;
799 JMutexAutoLock envlock(m_env_mutex);
800 ScopeProfiler sp(g_profiler, "Server: sending object messages");
803 // Value = data sent by object
804 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
806 // Get active object messages from environment
808 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
812 std::vector<ActiveObjectMessage>* message_list = NULL;
813 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
814 n = buffered_messages.find(aom.id);
815 if (n == buffered_messages.end()) {
816 message_list = new std::vector<ActiveObjectMessage>;
817 buffered_messages[aom.id] = message_list;
820 message_list = n->second;
822 message_list->push_back(aom);
826 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
827 // Route data to every client
828 for (std::map<u16, RemoteClient*>::iterator
830 i != clients.end(); ++i) {
831 RemoteClient *client = i->second;
832 std::string reliable_data;
833 std::string unreliable_data;
834 // Go through all objects in message buffer
835 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
836 j = buffered_messages.begin();
837 j != buffered_messages.end(); ++j) {
838 // If object is not known by client, skip it
840 if (client->m_known_objects.find(id) == client->m_known_objects.end())
843 // Get message list of object
844 std::vector<ActiveObjectMessage>* list = j->second;
845 // Go through every message
846 for (std::vector<ActiveObjectMessage>::iterator
847 k = list->begin(); k != list->end(); ++k) {
848 // Compose the full new data with header
849 ActiveObjectMessage aom = *k;
850 std::string new_data;
853 writeU16((u8*)&buf[0], aom.id);
854 new_data.append(buf, 2);
856 new_data += serializeString(aom.datastring);
857 // Add data to buffer
859 reliable_data += new_data;
861 unreliable_data += new_data;
865 reliable_data and unreliable_data are now ready.
868 if(reliable_data.size() > 0) {
869 SendActiveObjectMessages(client->peer_id, reliable_data);
872 if(unreliable_data.size() > 0) {
873 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
878 // Clear buffered_messages
879 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
880 i = buffered_messages.begin();
881 i != buffered_messages.end(); ++i) {
887 Send queued-for-sending map edit events.
890 // We will be accessing the environment
891 JMutexAutoLock lock(m_env_mutex);
893 // Don't send too many at a time
896 // Single change sending is disabled if queue size is not small
897 bool disable_single_change_sending = false;
898 if(m_unsent_map_edit_queue.size() >= 4)
899 disable_single_change_sending = true;
901 int event_count = m_unsent_map_edit_queue.size();
903 // We'll log the amount of each
906 while(m_unsent_map_edit_queue.size() != 0)
908 MapEditEvent* event = m_unsent_map_edit_queue.front();
909 m_unsent_map_edit_queue.pop();
911 // Players far away from the change are stored here.
912 // Instead of sending the changes, MapBlocks are set not sent
914 std::vector<u16> far_players;
916 switch (event->type) {
919 prof.add("MEET_ADDNODE", 1);
920 sendAddNode(event->p, event->n, event->already_known_by_peer,
921 &far_players, disable_single_change_sending ? 5 : 30,
922 event->type == MEET_ADDNODE);
924 case MEET_REMOVENODE:
925 prof.add("MEET_REMOVENODE", 1);
926 sendRemoveNode(event->p, event->already_known_by_peer,
927 &far_players, disable_single_change_sending ? 5 : 30);
929 case MEET_BLOCK_NODE_METADATA_CHANGED:
930 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
931 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
932 setBlockNotSent(event->p);
935 infostream << "Server: MEET_OTHER" << std::endl;
936 prof.add("MEET_OTHER", 1);
937 for(std::set<v3s16>::iterator
938 i = event->modified_blocks.begin();
939 i != event->modified_blocks.end(); ++i) {
944 prof.add("unknown", 1);
945 infostream << "WARNING: Server: Unknown MapEditEvent "
946 << ((u32)event->type) << std::endl;
951 Set blocks not sent to far players
953 if(!far_players.empty()) {
954 // Convert list format to that wanted by SetBlocksNotSent
955 std::map<v3s16, MapBlock*> modified_blocks2;
956 for(std::set<v3s16>::iterator
957 i = event->modified_blocks.begin();
958 i != event->modified_blocks.end(); ++i) {
959 modified_blocks2[*i] =
960 m_env->getMap().getBlockNoCreateNoEx(*i);
963 // Set blocks not sent
964 for(std::vector<u16>::iterator
965 i = far_players.begin();
966 i != far_players.end(); ++i) {
967 if(RemoteClient *client = getClient(*i))
968 client->SetBlocksNotSent(modified_blocks2);
974 /*// Don't send too many at a time
976 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
980 if(event_count >= 5){
981 infostream<<"Server: MapEditEvents:"<<std::endl;
982 prof.print(infostream);
983 } else if(event_count != 0){
984 verbosestream<<"Server: MapEditEvents:"<<std::endl;
985 prof.print(verbosestream);
991 Trigger emergethread (it somehow gets to a non-triggered but
992 bysy state sometimes)
995 float &counter = m_emergethread_trigger_timer;
1001 m_emerge->startThreads();
1005 // Save map, players and auth stuff
1007 float &counter = m_savemap_timer;
1009 if(counter >= g_settings->getFloat("server_map_save_interval"))
1012 JMutexAutoLock lock(m_env_mutex);
1014 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1017 if (m_banmanager->isModified()) {
1018 m_banmanager->save();
1021 // Save changed parts of map
1022 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1025 m_env->saveLoadedPlayers();
1027 // Save environment metadata
1033 void Server::Receive()
1035 DSTACK(__FUNCTION_NAME);
1036 SharedBuffer<u8> data;
1040 m_con.Receive(&pkt);
1041 peer_id = pkt.getPeerId();
1044 catch(con::InvalidIncomingDataException &e) {
1045 infostream<<"Server::Receive(): "
1046 "InvalidIncomingDataException: what()="
1047 <<e.what()<<std::endl;
1049 catch(SerializationError &e) {
1050 infostream<<"Server::Receive(): "
1051 "SerializationError: what()="
1052 <<e.what()<<std::endl;
1054 catch(ClientStateError &e) {
1055 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1056 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1057 L"Try reconnecting or updating your client");
1059 catch(con::PeerNotFoundException &e) {
1064 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1066 std::string playername = "";
1067 PlayerSAO *playersao = NULL;
1070 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1071 if (client != NULL) {
1072 playername = client->getName();
1073 playersao = emergePlayer(playername.c_str(), peer_id);
1075 } catch (std::exception &e) {
1081 RemotePlayer *player =
1082 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1084 // If failed, cancel
1085 if ((playersao == NULL) || (player == NULL)) {
1086 if (player && player->peer_id != 0) {
1087 actionstream << "Server: Failed to emerge player \"" << playername
1088 << "\" (player allocated to an another client)" << std::endl;
1089 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1090 L"name. If your client closed unexpectedly, try again in "
1093 errorstream << "Server: " << playername << ": Failed to emerge player"
1095 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1101 Send complete position information
1103 SendMovePlayer(peer_id);
1106 SendPlayerPrivileges(peer_id);
1108 // Send inventory formspec
1109 SendPlayerInventoryFormspec(peer_id);
1112 SendInventory(playersao);
1115 SendPlayerHPOrDie(playersao);
1118 SendPlayerBreath(peer_id);
1120 // Show death screen if necessary
1121 if(player->isDead())
1122 SendDeathscreen(peer_id, false, v3f(0,0,0));
1124 // Note things in chat if not in simple singleplayer mode
1125 if(!m_simple_singleplayer_mode) {
1126 // Send information about server to player in chat
1127 SendChatMessage(peer_id, getStatusString());
1129 // Send information about joining in chat
1131 std::wstring name = L"unknown";
1132 Player *player = m_env->getPlayer(peer_id);
1134 name = narrow_to_wide(player->getName());
1136 std::wstring message;
1139 message += L" joined the game.";
1140 SendChatMessage(PEER_ID_INEXISTENT,message);
1143 Address addr = getPeerAddress(player->peer_id);
1144 std::string ip_str = addr.serializeString();
1145 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1150 std::vector<std::string> names = m_clients.getPlayerNames();
1152 actionstream<<player->getName() <<" joins game. List of players: ";
1154 for (std::vector<std::string>::iterator i = names.begin();
1155 i != names.end(); i++) {
1156 actionstream << *i << " ";
1159 actionstream << player->getName() <<std::endl;
1164 inline void Server::handleCommand(NetworkPacket* pkt)
1166 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1167 (this->*opHandle.handler)(pkt);
1170 void Server::ProcessData(NetworkPacket *pkt)
1172 DSTACK(__FUNCTION_NAME);
1173 // Environment is locked first.
1174 JMutexAutoLock envlock(m_env_mutex);
1176 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1177 u32 peer_id = pkt->getPeerId();
1180 Address address = getPeerAddress(peer_id);
1181 std::string addr_s = address.serializeString();
1183 if(m_banmanager->isIpBanned(addr_s)) {
1184 std::string ban_name = m_banmanager->getBanName(addr_s);
1185 infostream << "Server: A banned client tried to connect from "
1186 << addr_s << "; banned name was "
1187 << ban_name << std::endl;
1188 // This actually doesn't seem to transfer to the client
1189 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1190 + utf8_to_wide(ban_name));
1194 catch(con::PeerNotFoundException &e) {
1196 * no peer for this packet found
1197 * most common reason is peer timeout, e.g. peer didn't
1198 * respond for some time, your server was overloaded or
1201 infostream << "Server::ProcessData(): Canceling: peer "
1202 << peer_id << " not found" << std::endl;
1207 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1209 // Command must be handled into ToServerCommandHandler
1210 if (command >= TOSERVER_NUM_MSG_TYPES) {
1211 infostream << "Server: Ignoring unknown command "
1212 << command << std::endl;
1216 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1221 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1223 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1224 errorstream << "Server::ProcessData(): Cancelling: Peer"
1225 " serialization format invalid or not initialized."
1226 " Skipping incoming command=" << command << std::endl;
1230 /* Handle commands related to client startup */
1231 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1236 if (m_clients.getClientState(peer_id) < CS_Active) {
1237 if (command == TOSERVER_PLAYERPOS) return;
1239 errorstream << "Got packet command: " << command << " for peer id "
1240 << peer_id << " but client isn't active yet. Dropping packet "
1246 } catch (SendFailedException &e) {
1247 errorstream << "Server::ProcessData(): SendFailedException: "
1248 << "what=" << e.what()
1250 } catch (PacketError &e) {
1251 actionstream << "Server::ProcessData(): PacketError: "
1252 << "what=" << e.what()
1257 void Server::setTimeOfDay(u32 time)
1259 m_env->setTimeOfDay(time);
1260 m_time_of_day_send_timer = 0;
1263 void Server::onMapEditEvent(MapEditEvent *event)
1265 if(m_ignore_map_edit_events)
1267 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1269 MapEditEvent *e = event->clone();
1270 m_unsent_map_edit_queue.push(e);
1273 Inventory* Server::getInventory(const InventoryLocation &loc)
1276 case InventoryLocation::UNDEFINED:
1277 case InventoryLocation::CURRENT_PLAYER:
1279 case InventoryLocation::PLAYER:
1281 Player *player = m_env->getPlayer(loc.name.c_str());
1284 PlayerSAO *playersao = player->getPlayerSAO();
1287 return playersao->getInventory();
1290 case InventoryLocation::NODEMETA:
1292 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1295 return meta->getInventory();
1298 case InventoryLocation::DETACHED:
1300 if(m_detached_inventories.count(loc.name) == 0)
1302 return m_detached_inventories[loc.name];
1306 sanity_check(false); // abort
1311 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1314 case InventoryLocation::UNDEFINED:
1316 case InventoryLocation::PLAYER:
1321 Player *player = m_env->getPlayer(loc.name.c_str());
1324 PlayerSAO *playersao = player->getPlayerSAO();
1328 SendInventory(playersao);
1331 case InventoryLocation::NODEMETA:
1333 v3s16 blockpos = getNodeBlockPos(loc.p);
1335 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1337 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1339 setBlockNotSent(blockpos);
1342 case InventoryLocation::DETACHED:
1344 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1348 sanity_check(false); // abort
1353 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1355 std::vector<u16> clients = m_clients.getClientIDs();
1357 // Set the modified blocks unsent for all the clients
1358 for (std::vector<u16>::iterator i = clients.begin();
1359 i != clients.end(); ++i) {
1360 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1361 client->SetBlocksNotSent(block);
1366 void Server::peerAdded(con::Peer *peer)
1368 DSTACK(__FUNCTION_NAME);
1369 verbosestream<<"Server::peerAdded(): peer->id="
1370 <<peer->id<<std::endl;
1373 c.type = con::PEER_ADDED;
1374 c.peer_id = peer->id;
1376 m_peer_change_queue.push(c);
1379 void Server::deletingPeer(con::Peer *peer, bool timeout)
1381 DSTACK(__FUNCTION_NAME);
1382 verbosestream<<"Server::deletingPeer(): peer->id="
1383 <<peer->id<<", timeout="<<timeout<<std::endl;
1385 m_clients.event(peer->id, CSE_Disconnect);
1387 c.type = con::PEER_REMOVED;
1388 c.peer_id = peer->id;
1389 c.timeout = timeout;
1390 m_peer_change_queue.push(c);
1393 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1395 *retval = m_con.getPeerStat(peer_id,type);
1396 if (*retval == -1) return false;
1400 bool Server::getClientInfo(
1409 std::string* vers_string
1412 *state = m_clients.getClientState(peer_id);
1414 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1416 if (client == NULL) {
1421 *uptime = client->uptime();
1422 *ser_vers = client->serialization_version;
1423 *prot_vers = client->net_proto_version;
1425 *major = client->getMajor();
1426 *minor = client->getMinor();
1427 *patch = client->getPatch();
1428 *vers_string = client->getPatch();
1435 void Server::handlePeerChanges()
1437 while(m_peer_change_queue.size() > 0)
1439 con::PeerChange c = m_peer_change_queue.front();
1440 m_peer_change_queue.pop();
1442 verbosestream<<"Server: Handling peer change: "
1443 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1448 case con::PEER_ADDED:
1449 m_clients.CreateClient(c.peer_id);
1452 case con::PEER_REMOVED:
1453 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1457 FATAL_ERROR("Invalid peer change event received!");
1463 void Server::Send(NetworkPacket* pkt)
1465 m_clients.send(pkt->getPeerId(),
1466 clientCommandFactoryTable[pkt->getCommand()].channel,
1468 clientCommandFactoryTable[pkt->getCommand()].reliable);
1471 void Server::SendMovement(u16 peer_id)
1473 DSTACK(__FUNCTION_NAME);
1474 std::ostringstream os(std::ios_base::binary);
1476 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1478 pkt << g_settings->getFloat("movement_acceleration_default");
1479 pkt << g_settings->getFloat("movement_acceleration_air");
1480 pkt << g_settings->getFloat("movement_acceleration_fast");
1481 pkt << g_settings->getFloat("movement_speed_walk");
1482 pkt << g_settings->getFloat("movement_speed_crouch");
1483 pkt << g_settings->getFloat("movement_speed_fast");
1484 pkt << g_settings->getFloat("movement_speed_climb");
1485 pkt << g_settings->getFloat("movement_speed_jump");
1486 pkt << g_settings->getFloat("movement_liquid_fluidity");
1487 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1488 pkt << g_settings->getFloat("movement_liquid_sink");
1489 pkt << g_settings->getFloat("movement_gravity");
1494 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1496 if (!g_settings->getBool("enable_damage"))
1499 u16 peer_id = playersao->getPeerID();
1500 bool is_alive = playersao->getHP() > 0;
1503 SendPlayerHP(peer_id);
1508 void Server::SendHP(u16 peer_id, u8 hp)
1510 DSTACK(__FUNCTION_NAME);
1512 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1517 void Server::SendBreath(u16 peer_id, u16 breath)
1519 DSTACK(__FUNCTION_NAME);
1521 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1522 pkt << (u16) breath;
1526 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1528 DSTACK(__FUNCTION_NAME);
1530 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1533 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1534 pkt << custom_reason;
1539 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1541 DSTACK(__FUNCTION_NAME);
1543 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1548 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1549 v3f camera_point_target)
1551 DSTACK(__FUNCTION_NAME);
1553 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1554 pkt << set_camera_point_target << camera_point_target;
1558 void Server::SendItemDef(u16 peer_id,
1559 IItemDefManager *itemdef, u16 protocol_version)
1561 DSTACK(__FUNCTION_NAME);
1563 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1567 u32 length of the next item
1568 zlib-compressed serialized ItemDefManager
1570 std::ostringstream tmp_os(std::ios::binary);
1571 itemdef->serialize(tmp_os, protocol_version);
1572 std::ostringstream tmp_os2(std::ios::binary);
1573 compressZlib(tmp_os.str(), tmp_os2);
1574 pkt.putLongString(tmp_os2.str());
1577 verbosestream << "Server: Sending item definitions to id(" << peer_id
1578 << "): size=" << pkt.getSize() << std::endl;
1583 void Server::SendNodeDef(u16 peer_id,
1584 INodeDefManager *nodedef, u16 protocol_version)
1586 DSTACK(__FUNCTION_NAME);
1588 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1592 u32 length of the next item
1593 zlib-compressed serialized NodeDefManager
1595 std::ostringstream tmp_os(std::ios::binary);
1596 nodedef->serialize(tmp_os, protocol_version);
1597 std::ostringstream tmp_os2(std::ios::binary);
1598 compressZlib(tmp_os.str(), tmp_os2);
1600 pkt.putLongString(tmp_os2.str());
1603 verbosestream << "Server: Sending node definitions to id(" << peer_id
1604 << "): size=" << pkt.getSize() << std::endl;
1610 Non-static send methods
1613 void Server::SendInventory(PlayerSAO* playerSAO)
1615 DSTACK(__FUNCTION_NAME);
1617 UpdateCrafting(playerSAO->getPlayer());
1623 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1625 std::ostringstream os;
1626 playerSAO->getInventory()->serialize(os);
1628 std::string s = os.str();
1630 pkt.putRawString(s.c_str(), s.size());
1634 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1636 DSTACK(__FUNCTION_NAME);
1638 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1641 if (peer_id != PEER_ID_INEXISTENT) {
1645 m_clients.sendToAll(0, &pkt, true);
1649 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1650 const std::string &formname)
1652 DSTACK(__FUNCTION_NAME);
1654 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1656 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1662 // Spawns a particle on peer with peer_id
1663 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1664 float expirationtime, float size, bool collisiondetection,
1665 bool vertical, std::string texture)
1667 DSTACK(__FUNCTION_NAME);
1669 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1671 pkt << pos << velocity << acceleration << expirationtime
1672 << size << collisiondetection;
1673 pkt.putLongString(texture);
1676 if (peer_id != PEER_ID_INEXISTENT) {
1680 m_clients.sendToAll(0, &pkt, true);
1684 // Adds a ParticleSpawner on peer with peer_id
1685 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1686 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1687 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1689 DSTACK(__FUNCTION_NAME);
1691 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1693 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1694 << minacc << maxacc << minexptime << maxexptime << minsize
1695 << maxsize << collisiondetection;
1697 pkt.putLongString(texture);
1699 pkt << id << vertical;
1701 if (peer_id != PEER_ID_INEXISTENT) {
1705 m_clients.sendToAll(0, &pkt, true);
1709 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1711 DSTACK(__FUNCTION_NAME);
1713 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1715 // Ugly error in this packet
1718 if (peer_id != PEER_ID_INEXISTENT) {
1722 m_clients.sendToAll(0, &pkt, true);
1727 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1729 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1731 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1732 << form->text << form->number << form->item << form->dir
1733 << form->align << form->offset << form->world_pos << form->size;
1738 void Server::SendHUDRemove(u16 peer_id, u32 id)
1740 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1745 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1747 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1748 pkt << id << (u8) stat;
1752 case HUD_STAT_SCALE:
1753 case HUD_STAT_ALIGN:
1754 case HUD_STAT_OFFSET:
1755 pkt << *(v2f *) value;
1759 pkt << *(std::string *) value;
1761 case HUD_STAT_WORLD_POS:
1762 pkt << *(v3f *) value;
1765 pkt << *(v2s32 *) value;
1767 case HUD_STAT_NUMBER:
1771 pkt << *(u32 *) value;
1778 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1780 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1782 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1784 pkt << flags << mask;
1789 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1791 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1792 pkt << param << value;
1796 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1797 const std::string &type, const std::vector<std::string> ¶ms)
1799 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1800 pkt << bgcolor << type << (u16) params.size();
1802 for(size_t i=0; i<params.size(); i++)
1808 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1811 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1814 pkt << do_override << (u16) (ratio * 65535);
1819 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1821 DSTACK(__FUNCTION_NAME);
1823 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1824 pkt << time << time_speed;
1826 if (peer_id == PEER_ID_INEXISTENT) {
1827 m_clients.sendToAll(0, &pkt, true);
1834 void Server::SendPlayerHP(u16 peer_id)
1836 DSTACK(__FUNCTION_NAME);
1837 PlayerSAO *playersao = getPlayerSAO(peer_id);
1838 // In some rare case, if the player is disconnected
1839 // while Lua call l_punch, for example, this can be NULL
1843 SendHP(peer_id, playersao->getHP());
1844 m_script->player_event(playersao,"health_changed");
1846 // Send to other clients
1847 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1848 ActiveObjectMessage aom(playersao->getId(), true, str);
1849 playersao->m_messages_out.push(aom);
1852 void Server::SendPlayerBreath(u16 peer_id)
1854 DSTACK(__FUNCTION_NAME);
1855 PlayerSAO *playersao = getPlayerSAO(peer_id);
1858 m_script->player_event(playersao, "breath_changed");
1859 SendBreath(peer_id, playersao->getBreath());
1862 void Server::SendMovePlayer(u16 peer_id)
1864 DSTACK(__FUNCTION_NAME);
1865 Player *player = m_env->getPlayer(peer_id);
1868 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1869 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1872 v3f pos = player->getPosition();
1873 f32 pitch = player->getPitch();
1874 f32 yaw = player->getYaw();
1875 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1876 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1877 << " pitch=" << pitch
1885 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1887 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1890 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1891 << animation_frames[3] << animation_speed;
1896 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1898 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1899 pkt << first << third;
1902 void Server::SendPlayerPrivileges(u16 peer_id)
1904 Player *player = m_env->getPlayer(peer_id);
1906 if(player->peer_id == PEER_ID_INEXISTENT)
1909 std::set<std::string> privs;
1910 m_script->getAuth(player->getName(), NULL, &privs);
1912 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1913 pkt << (u16) privs.size();
1915 for(std::set<std::string>::const_iterator i = privs.begin();
1916 i != privs.end(); i++) {
1923 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1925 Player *player = m_env->getPlayer(peer_id);
1927 if(player->peer_id == PEER_ID_INEXISTENT)
1930 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1931 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1935 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1937 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1938 pkt.putRawString(datas.c_str(), datas.size());
1940 return pkt.getSize();
1943 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1945 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1946 datas.size(), peer_id);
1948 pkt.putRawString(datas.c_str(), datas.size());
1950 m_clients.send(pkt.getPeerId(),
1951 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1956 s32 Server::playSound(const SimpleSoundSpec &spec,
1957 const ServerSoundParams ¶ms)
1959 // Find out initial position of sound
1960 bool pos_exists = false;
1961 v3f pos = params.getPos(m_env, &pos_exists);
1962 // If position is not found while it should be, cancel sound
1963 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1966 // Filter destination clients
1967 std::vector<u16> dst_clients;
1968 if(params.to_player != "")
1970 Player *player = m_env->getPlayer(params.to_player.c_str());
1972 infostream<<"Server::playSound: Player \""<<params.to_player
1973 <<"\" not found"<<std::endl;
1976 if(player->peer_id == PEER_ID_INEXISTENT){
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not connected"<<std::endl;
1981 dst_clients.push_back(player->peer_id);
1984 std::vector<u16> clients = m_clients.getClientIDs();
1986 for(std::vector<u16>::iterator
1987 i = clients.begin(); i != clients.end(); ++i) {
1988 Player *player = m_env->getPlayer(*i);
1993 if(player->getPosition().getDistanceFrom(pos) >
1994 params.max_hear_distance)
1997 dst_clients.push_back(*i);
2001 if(dst_clients.empty())
2005 s32 id = m_next_sound_id++;
2006 // The sound will exist as a reference in m_playing_sounds
2007 m_playing_sounds[id] = ServerPlayingSound();
2008 ServerPlayingSound &psound = m_playing_sounds[id];
2009 psound.params = params;
2011 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2012 pkt << id << spec.name << (float) (spec.gain * params.gain)
2013 << (u8) params.type << pos << params.object << params.loop;
2015 for(std::vector<u16>::iterator i = dst_clients.begin();
2016 i != dst_clients.end(); i++) {
2017 psound.clients.insert(*i);
2018 m_clients.send(*i, 0, &pkt, true);
2022 void Server::stopSound(s32 handle)
2024 // Get sound reference
2025 std::map<s32, ServerPlayingSound>::iterator i =
2026 m_playing_sounds.find(handle);
2027 if(i == m_playing_sounds.end())
2029 ServerPlayingSound &psound = i->second;
2031 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2034 for(std::set<u16>::iterator i = psound.clients.begin();
2035 i != psound.clients.end(); i++) {
2037 m_clients.send(*i, 0, &pkt, true);
2039 // Remove sound reference
2040 m_playing_sounds.erase(i);
2043 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2044 std::vector<u16> *far_players, float far_d_nodes)
2046 float maxd = far_d_nodes*BS;
2047 v3f p_f = intToFloat(p, BS);
2049 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2052 std::vector<u16> clients = m_clients.getClientIDs();
2053 for(std::vector<u16>::iterator i = clients.begin();
2054 i != clients.end(); ++i) {
2057 if(Player *player = m_env->getPlayer(*i)) {
2058 // If player is far away, only set modified blocks not sent
2059 v3f player_pos = player->getPosition();
2060 if(player_pos.getDistanceFrom(p_f) > maxd) {
2061 far_players->push_back(*i);
2068 m_clients.send(*i, 0, &pkt, true);
2072 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2073 std::vector<u16> *far_players, float far_d_nodes,
2074 bool remove_metadata)
2076 float maxd = far_d_nodes*BS;
2077 v3f p_f = intToFloat(p, BS);
2079 std::vector<u16> clients = m_clients.getClientIDs();
2080 for(std::vector<u16>::iterator i = clients.begin();
2081 i != clients.end(); ++i) {
2085 if(Player *player = m_env->getPlayer(*i)) {
2086 // If player is far away, only set modified blocks not sent
2087 v3f player_pos = player->getPosition();
2088 if(player_pos.getDistanceFrom(p_f) > maxd) {
2089 far_players->push_back(*i);
2095 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2097 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2099 pkt << p << n.param0 << n.param1 << n.param2
2100 << (u8) (remove_metadata ? 0 : 1);
2102 if (!remove_metadata) {
2103 if (client->net_proto_version <= 21) {
2104 // Old clients always clear metadata; fix it
2105 // by sending the full block again.
2106 client->SetBlockNotSent(p);
2113 if (pkt.getSize() > 0)
2114 m_clients.send(*i, 0, &pkt, true);
2118 void Server::setBlockNotSent(v3s16 p)
2120 std::vector<u16> clients = m_clients.getClientIDs();
2122 for(std::vector<u16>::iterator i = clients.begin();
2123 i != clients.end(); ++i) {
2124 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2125 client->SetBlockNotSent(p);
2130 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2132 DSTACK(__FUNCTION_NAME);
2134 v3s16 p = block->getPos();
2137 Create a packet with the block in the right format
2140 std::ostringstream os(std::ios_base::binary);
2141 block->serialize(os, ver, false);
2142 block->serializeNetworkSpecific(os, net_proto_version);
2143 std::string s = os.str();
2145 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2148 pkt.putRawString(s.c_str(), s.size());
2152 void Server::SendBlocks(float dtime)
2154 DSTACK(__FUNCTION_NAME);
2156 JMutexAutoLock envlock(m_env_mutex);
2157 //TODO check if one big lock could be faster then multiple small ones
2159 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2161 std::vector<PrioritySortedBlockTransfer> queue;
2163 s32 total_sending = 0;
2166 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2168 std::vector<u16> clients = m_clients.getClientIDs();
2171 for(std::vector<u16>::iterator i = clients.begin();
2172 i != clients.end(); ++i) {
2173 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2178 total_sending += client->SendingCount();
2179 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2185 // Lowest priority number comes first.
2186 // Lowest is most important.
2187 std::sort(queue.begin(), queue.end());
2190 for(u32 i=0; i<queue.size(); i++)
2192 //TODO: Calculate limit dynamically
2193 if(total_sending >= g_settings->getS32
2194 ("max_simultaneous_block_sends_server_total"))
2197 PrioritySortedBlockTransfer q = queue[i];
2199 MapBlock *block = NULL;
2202 block = m_env->getMap().getBlockNoCreate(q.pos);
2204 catch(InvalidPositionException &e)
2209 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2214 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2216 client->SentBlock(q.pos);
2222 void Server::fillMediaCache()
2224 DSTACK(__FUNCTION_NAME);
2226 infostream<<"Server: Calculating media file checksums"<<std::endl;
2228 // Collect all media file paths
2229 std::vector<std::string> paths;
2230 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2231 i != m_mods.end(); i++) {
2232 const ModSpec &mod = *i;
2233 paths.push_back(mod.path + DIR_DELIM + "textures");
2234 paths.push_back(mod.path + DIR_DELIM + "sounds");
2235 paths.push_back(mod.path + DIR_DELIM + "media");
2236 paths.push_back(mod.path + DIR_DELIM + "models");
2238 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2240 // Collect media file information from paths into cache
2241 for(std::vector<std::string>::iterator i = paths.begin();
2242 i != paths.end(); i++) {
2243 std::string mediapath = *i;
2244 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2245 for (u32 j = 0; j < dirlist.size(); j++) {
2246 if (dirlist[j].dir) // Ignode dirs
2248 std::string filename = dirlist[j].name;
2249 // If name contains illegal characters, ignore the file
2250 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2251 infostream<<"Server: ignoring illegal file name: \""
2252 << filename << "\"" << std::endl;
2255 // If name is not in a supported format, ignore it
2256 const char *supported_ext[] = {
2257 ".png", ".jpg", ".bmp", ".tga",
2258 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2260 ".x", ".b3d", ".md2", ".obj",
2263 if (removeStringEnd(filename, supported_ext) == ""){
2264 infostream << "Server: ignoring unsupported file extension: \""
2265 << filename << "\"" << std::endl;
2268 // Ok, attempt to load the file and add to cache
2269 std::string filepath = mediapath + DIR_DELIM + filename;
2271 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2273 errorstream << "Server::fillMediaCache(): Could not open \""
2274 << filename << "\" for reading" << std::endl;
2277 std::ostringstream tmp_os(std::ios_base::binary);
2281 fis.read(buf, 1024);
2282 std::streamsize len = fis.gcount();
2283 tmp_os.write(buf, len);
2292 errorstream<<"Server::fillMediaCache(): Failed to read \""
2293 << filename << "\"" << std::endl;
2296 if(tmp_os.str().length() == 0) {
2297 errorstream << "Server::fillMediaCache(): Empty file \""
2298 << filepath << "\"" << std::endl;
2303 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2305 unsigned char *digest = sha1.getDigest();
2306 std::string sha1_base64 = base64_encode(digest, 20);
2307 std::string sha1_hex = hex_encode((char*)digest, 20);
2311 m_media[filename] = MediaInfo(filepath, sha1_base64);
2312 verbosestream << "Server: " << sha1_hex << " is " << filename
2318 struct SendableMediaAnnouncement
2321 std::string sha1_digest;
2323 SendableMediaAnnouncement(const std::string &name_="",
2324 const std::string &sha1_digest_=""):
2326 sha1_digest(sha1_digest_)
2330 void Server::sendMediaAnnouncement(u16 peer_id)
2332 DSTACK(__FUNCTION_NAME);
2334 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2337 std::vector<SendableMediaAnnouncement> file_announcements;
2339 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2340 i != m_media.end(); i++){
2342 file_announcements.push_back(
2343 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2347 std::ostringstream os(std::ios_base::binary);
2349 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2350 pkt << (u16) file_announcements.size();
2352 for (std::vector<SendableMediaAnnouncement>::iterator
2353 j = file_announcements.begin();
2354 j != file_announcements.end(); ++j) {
2355 pkt << j->name << j->sha1_digest;
2358 pkt << g_settings->get("remote_media");
2362 struct SendableMedia
2368 SendableMedia(const std::string &name_="", const std::string &path_="",
2369 const std::string &data_=""):
2376 void Server::sendRequestedMedia(u16 peer_id,
2377 const std::vector<std::string> &tosend)
2379 DSTACK(__FUNCTION_NAME);
2381 verbosestream<<"Server::sendRequestedMedia(): "
2382 <<"Sending files to client"<<std::endl;
2386 // Put 5kB in one bunch (this is not accurate)
2387 u32 bytes_per_bunch = 5000;
2389 std::vector< std::vector<SendableMedia> > file_bunches;
2390 file_bunches.push_back(std::vector<SendableMedia>());
2392 u32 file_size_bunch_total = 0;
2394 for(std::vector<std::string>::const_iterator i = tosend.begin();
2395 i != tosend.end(); ++i) {
2396 const std::string &name = *i;
2398 if(m_media.find(name) == m_media.end()) {
2399 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2400 <<"unknown file \""<<(name)<<"\""<<std::endl;
2404 //TODO get path + name
2405 std::string tpath = m_media[name].path;
2408 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2409 if(fis.good() == false){
2410 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2411 <<tpath<<"\" for reading"<<std::endl;
2414 std::ostringstream tmp_os(std::ios_base::binary);
2418 fis.read(buf, 1024);
2419 std::streamsize len = fis.gcount();
2420 tmp_os.write(buf, len);
2421 file_size_bunch_total += len;
2430 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2431 <<name<<"\""<<std::endl;
2434 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2435 <<tname<<"\""<<std::endl;*/
2437 file_bunches[file_bunches.size()-1].push_back(
2438 SendableMedia(name, tpath, tmp_os.str()));
2440 // Start next bunch if got enough data
2441 if(file_size_bunch_total >= bytes_per_bunch) {
2442 file_bunches.push_back(std::vector<SendableMedia>());
2443 file_size_bunch_total = 0;
2448 /* Create and send packets */
2450 u16 num_bunches = file_bunches.size();
2451 for(u16 i = 0; i < num_bunches; i++) {
2454 u16 total number of texture bunches
2455 u16 index of this bunch
2456 u32 number of files in this bunch
2465 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2466 pkt << num_bunches << i << (u32) file_bunches[i].size();
2468 for(std::vector<SendableMedia>::iterator
2469 j = file_bunches[i].begin();
2470 j != file_bunches[i].end(); ++j) {
2472 pkt.putLongString(j->data);
2475 verbosestream << "Server::sendRequestedMedia(): bunch "
2476 << i << "/" << num_bunches
2477 << " files=" << file_bunches[i].size()
2478 << " size=" << pkt.getSize() << std::endl;
2483 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2485 if(m_detached_inventories.count(name) == 0) {
2486 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2489 Inventory *inv = m_detached_inventories[name];
2490 std::ostringstream os(std::ios_base::binary);
2492 os << serializeString(name);
2496 std::string s = os.str();
2498 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2499 pkt.putRawString(s.c_str(), s.size());
2501 if (peer_id != PEER_ID_INEXISTENT) {
2505 m_clients.sendToAll(0, &pkt, true);
2509 void Server::sendDetachedInventories(u16 peer_id)
2511 DSTACK(__FUNCTION_NAME);
2513 for(std::map<std::string, Inventory*>::iterator
2514 i = m_detached_inventories.begin();
2515 i != m_detached_inventories.end(); i++) {
2516 const std::string &name = i->first;
2517 //Inventory *inv = i->second;
2518 sendDetachedInventory(name, peer_id);
2526 void Server::DiePlayer(u16 peer_id)
2528 DSTACK(__FUNCTION_NAME);
2530 PlayerSAO *playersao = getPlayerSAO(peer_id);
2533 infostream << "Server::DiePlayer(): Player "
2534 << playersao->getPlayer()->getName()
2535 << " dies" << std::endl;
2537 playersao->setHP(0);
2539 // Trigger scripted stuff
2540 m_script->on_dieplayer(playersao);
2542 SendPlayerHP(peer_id);
2543 SendDeathscreen(peer_id, false, v3f(0,0,0));
2546 void Server::RespawnPlayer(u16 peer_id)
2548 DSTACK(__FUNCTION_NAME);
2550 PlayerSAO *playersao = getPlayerSAO(peer_id);
2553 infostream << "Server::RespawnPlayer(): Player "
2554 << playersao->getPlayer()->getName()
2555 << " respawns" << std::endl;
2557 playersao->setHP(PLAYER_MAX_HP);
2558 playersao->setBreath(PLAYER_MAX_BREATH);
2560 SendPlayerHP(peer_id);
2561 SendPlayerBreath(peer_id);
2563 bool repositioned = m_script->on_respawnplayer(playersao);
2565 v3f pos = findSpawnPos();
2566 // setPos will send the new position to client
2567 playersao->setPos(pos);
2570 void Server::DenySudoAccess(u16 peer_id)
2572 DSTACK(__FUNCTION_NAME);
2574 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2578 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2580 DSTACK(__FUNCTION_NAME);
2582 SendAccessDenied(peer_id, reason, custom_reason);
2583 m_clients.event(peer_id, CSE_SetDenied);
2584 m_con.DisconnectPeer(peer_id);
2587 // 13/03/15: remove this function when protocol version 25 will become
2588 // the minimum version for MT users, maybe in 1 year
2589 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2591 DSTACK(__FUNCTION_NAME);
2593 SendAccessDenied_Legacy(peer_id, reason);
2594 m_clients.event(peer_id, CSE_SetDenied);
2595 m_con.DisconnectPeer(peer_id);
2598 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2600 DSTACK(__FUNCTION_NAME);
2603 RemoteClient* client = getClient(peer_id, CS_Invalid);
2605 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2607 // Right now, the auth mechs don't change between login and sudo mode.
2608 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2609 client->allowed_sudo_mechs = sudo_auth_mechs;
2611 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2612 << g_settings->getFloat("dedicated_server_step")
2616 m_clients.event(peer_id, CSE_AuthAccept);
2618 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2620 // We only support SRP right now
2621 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2623 resp_pkt << sudo_auth_mechs;
2625 m_clients.event(peer_id, CSE_SudoSuccess);
2629 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2631 DSTACK(__FUNCTION_NAME);
2632 std::wstring message;
2635 Clear references to playing sounds
2637 for(std::map<s32, ServerPlayingSound>::iterator
2638 i = m_playing_sounds.begin();
2639 i != m_playing_sounds.end();)
2641 ServerPlayingSound &psound = i->second;
2642 psound.clients.erase(peer_id);
2643 if(psound.clients.empty())
2644 m_playing_sounds.erase(i++);
2649 Player *player = m_env->getPlayer(peer_id);
2651 // Collect information about leaving in chat
2653 if(player != NULL && reason != CDR_DENY)
2655 std::wstring name = narrow_to_wide(player->getName());
2658 message += L" left the game.";
2659 if(reason == CDR_TIMEOUT)
2660 message += L" (timed out)";
2664 /* Run scripts and remove from environment */
2668 PlayerSAO *playersao = player->getPlayerSAO();
2671 m_script->on_leaveplayer(playersao);
2673 playersao->disconnected();
2681 if(player != NULL && reason != CDR_DENY) {
2682 std::ostringstream os(std::ios_base::binary);
2683 std::vector<u16> clients = m_clients.getClientIDs();
2685 for(std::vector<u16>::iterator i = clients.begin();
2686 i != clients.end(); ++i) {
2688 Player *player = m_env->getPlayer(*i);
2692 // Get name of player
2693 os << player->getName() << " ";
2696 actionstream << player->getName() << " "
2697 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2698 << " List of players: " << os.str() << std::endl;
2702 JMutexAutoLock env_lock(m_env_mutex);
2703 m_clients.DeleteClient(peer_id);
2707 // Send leave chat message to all remaining clients
2708 if(message.length() != 0)
2709 SendChatMessage(PEER_ID_INEXISTENT,message);
2712 void Server::UpdateCrafting(Player* player)
2714 DSTACK(__FUNCTION_NAME);
2716 // Get a preview for crafting
2718 InventoryLocation loc;
2719 loc.setPlayer(player->getName());
2720 std::vector<ItemStack> output_replacements;
2721 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2722 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2724 // Put the new preview in
2725 InventoryList *plist = player->inventory.getList("craftpreview");
2726 sanity_check(plist);
2727 sanity_check(plist->getSize() >= 1);
2728 plist->changeItem(0, preview);
2731 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2733 RemoteClient *client = getClientNoEx(peer_id,state_min);
2735 throw ClientNotFoundException("Client not found");
2739 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2741 return m_clients.getClientNoEx(peer_id, state_min);
2744 std::string Server::getPlayerName(u16 peer_id)
2746 Player *player = m_env->getPlayer(peer_id);
2748 return "[id="+itos(peer_id)+"]";
2749 return player->getName();
2752 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2754 Player *player = m_env->getPlayer(peer_id);
2757 return player->getPlayerSAO();
2760 std::wstring Server::getStatusString()
2762 std::wostringstream os(std::ios_base::binary);
2765 os<<L"version="<<narrow_to_wide(g_version_string);
2767 os<<L", uptime="<<m_uptime.get();
2769 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2770 // Information about clients
2773 std::vector<u16> clients = m_clients.getClientIDs();
2774 for(std::vector<u16>::iterator i = clients.begin();
2775 i != clients.end(); ++i) {
2777 Player *player = m_env->getPlayer(*i);
2778 // Get name of player
2779 std::wstring name = L"unknown";
2781 name = narrow_to_wide(player->getName());
2782 // Add name to information string
2790 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2791 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2792 if(g_settings->get("motd") != "")
2793 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2797 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2799 std::set<std::string> privs;
2800 m_script->getAuth(name, NULL, &privs);
2804 bool Server::checkPriv(const std::string &name, const std::string &priv)
2806 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2807 return (privs.count(priv) != 0);
2810 void Server::reportPrivsModified(const std::string &name)
2813 std::vector<u16> clients = m_clients.getClientIDs();
2814 for(std::vector<u16>::iterator i = clients.begin();
2815 i != clients.end(); ++i) {
2816 Player *player = m_env->getPlayer(*i);
2817 reportPrivsModified(player->getName());
2820 Player *player = m_env->getPlayer(name.c_str());
2823 SendPlayerPrivileges(player->peer_id);
2824 PlayerSAO *sao = player->getPlayerSAO();
2827 sao->updatePrivileges(
2828 getPlayerEffectivePrivs(name),
2833 void Server::reportInventoryFormspecModified(const std::string &name)
2835 Player *player = m_env->getPlayer(name.c_str());
2838 SendPlayerInventoryFormspec(player->peer_id);
2841 void Server::setIpBanned(const std::string &ip, const std::string &name)
2843 m_banmanager->add(ip, name);
2846 void Server::unsetIpBanned(const std::string &ip_or_name)
2848 m_banmanager->remove(ip_or_name);
2851 std::string Server::getBanDescription(const std::string &ip_or_name)
2853 return m_banmanager->getBanDescription(ip_or_name);
2856 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2858 Player *player = m_env->getPlayer(name);
2862 if (player->peer_id == PEER_ID_INEXISTENT)
2865 SendChatMessage(player->peer_id, msg);
2868 bool Server::showFormspec(const char *playername, const std::string &formspec,
2869 const std::string &formname)
2871 Player *player = m_env->getPlayer(playername);
2875 SendShowFormspecMessage(player->peer_id, formspec, formname);
2879 u32 Server::hudAdd(Player *player, HudElement *form)
2884 u32 id = player->addHud(form);
2886 SendHUDAdd(player->peer_id, id, form);
2891 bool Server::hudRemove(Player *player, u32 id) {
2895 HudElement* todel = player->removeHud(id);
2902 SendHUDRemove(player->peer_id, id);
2906 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2911 SendHUDChange(player->peer_id, id, stat, data);
2915 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2920 SendHUDSetFlags(player->peer_id, flags, mask);
2921 player->hud_flags = flags;
2923 PlayerSAO* playersao = player->getPlayerSAO();
2925 if (playersao == NULL)
2928 m_script->player_event(playersao, "hud_changed");
2932 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2936 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2939 player->setHotbarItemcount(hotbar_itemcount);
2940 std::ostringstream os(std::ios::binary);
2941 writeS32(os, hotbar_itemcount);
2942 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2946 s32 Server::hudGetHotbarItemcount(Player *player)
2950 return player->getHotbarItemcount();
2953 void Server::hudSetHotbarImage(Player *player, std::string name)
2958 player->setHotbarImage(name);
2959 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2962 std::string Server::hudGetHotbarImage(Player *player)
2966 return player->getHotbarImage();
2969 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2974 player->setHotbarSelectedImage(name);
2975 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2978 std::string Server::hudGetHotbarSelectedImage(Player *player)
2983 return player->getHotbarSelectedImage();
2986 bool Server::setLocalPlayerAnimations(Player *player,
2987 v2s32 animation_frames[4], f32 frame_speed)
2992 player->setLocalAnimations(animation_frames, frame_speed);
2993 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2997 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3002 player->eye_offset_first = first;
3003 player->eye_offset_third = third;
3004 SendEyeOffset(player->peer_id, first, third);
3008 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3009 const std::string &type, const std::vector<std::string> ¶ms)
3014 player->setSky(bgcolor, type, params);
3015 SendSetSky(player->peer_id, bgcolor, type, params);
3019 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3025 player->overrideDayNightRatio(do_override, ratio);
3026 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3030 void Server::notifyPlayers(const std::wstring &msg)
3032 SendChatMessage(PEER_ID_INEXISTENT,msg);
3035 void Server::spawnParticle(const char *playername, v3f pos,
3036 v3f velocity, v3f acceleration,
3037 float expirationtime, float size, bool
3038 collisiondetection, bool vertical, const std::string &texture)
3040 Player *player = m_env->getPlayer(playername);
3043 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3044 expirationtime, size, collisiondetection, vertical, texture);
3047 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3048 float expirationtime, float size,
3049 bool collisiondetection, bool vertical, const std::string &texture)
3051 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3052 expirationtime, size, collisiondetection, vertical, texture);
3055 u32 Server::addParticleSpawner(const char *playername, u16 amount, float spawntime,
3056 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3057 float minexptime, float maxexptime, float minsize, float maxsize,
3058 bool collisiondetection, bool vertical, const std::string &texture)
3060 Player *player = m_env->getPlayer(playername);
3065 for(;;) // look for unused particlespawner id
3068 if (std::find(m_particlespawner_ids.begin(),
3069 m_particlespawner_ids.end(), id)
3070 == m_particlespawner_ids.end())
3072 m_particlespawner_ids.push_back(id);
3077 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3078 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3079 minexptime, maxexptime, minsize, maxsize,
3080 collisiondetection, vertical, texture, id);
3085 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3086 v3f minpos, v3f maxpos,
3087 v3f minvel, v3f maxvel,
3088 v3f minacc, v3f maxacc,
3089 float minexptime, float maxexptime,
3090 float minsize, float maxsize,
3091 bool collisiondetection, bool vertical, const std::string &texture)
3094 for(;;) // look for unused particlespawner id
3097 if (std::find(m_particlespawner_ids.begin(),
3098 m_particlespawner_ids.end(), id)
3099 == m_particlespawner_ids.end())
3101 m_particlespawner_ids.push_back(id);
3106 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3107 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3108 minexptime, maxexptime, minsize, maxsize,
3109 collisiondetection, vertical, texture, id);
3114 void Server::deleteParticleSpawner(const char *playername, u32 id)
3116 Player *player = m_env->getPlayer(playername);
3120 m_particlespawner_ids.erase(
3121 std::remove(m_particlespawner_ids.begin(),
3122 m_particlespawner_ids.end(), id),
3123 m_particlespawner_ids.end());
3124 SendDeleteParticleSpawner(player->peer_id, id);
3127 void Server::deleteParticleSpawnerAll(u32 id)
3129 m_particlespawner_ids.erase(
3130 std::remove(m_particlespawner_ids.begin(),
3131 m_particlespawner_ids.end(), id),
3132 m_particlespawner_ids.end());
3133 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3136 Inventory* Server::createDetachedInventory(const std::string &name)
3138 if(m_detached_inventories.count(name) > 0){
3139 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3140 delete m_detached_inventories[name];
3142 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3144 Inventory *inv = new Inventory(m_itemdef);
3146 m_detached_inventories[name] = inv;
3147 //TODO find a better way to do this
3148 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3152 // actions: time-reversed list
3153 // Return value: success/failure
3154 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3155 std::list<std::string> *log)
3157 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3158 ServerMap *map = (ServerMap*)(&m_env->getMap());
3160 // Fail if no actions to handle
3161 if(actions.empty()){
3162 log->push_back("Nothing to do.");
3169 for(std::list<RollbackAction>::const_iterator
3170 i = actions.begin();
3171 i != actions.end(); i++)
3173 const RollbackAction &action = *i;
3175 bool success = action.applyRevert(map, this, this);
3178 std::ostringstream os;
3179 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3180 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3182 log->push_back(os.str());
3184 std::ostringstream os;
3185 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3186 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3188 log->push_back(os.str());
3192 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3193 <<" failed"<<std::endl;
3195 // Call it done if less than half failed
3196 return num_failed <= num_tried/2;
3199 // IGameDef interface
3201 IItemDefManager *Server::getItemDefManager()
3206 INodeDefManager *Server::getNodeDefManager()
3211 ICraftDefManager *Server::getCraftDefManager()
3215 ITextureSource *Server::getTextureSource()
3219 IShaderSource *Server::getShaderSource()
3223 scene::ISceneManager *Server::getSceneManager()
3228 u16 Server::allocateUnknownNodeId(const std::string &name)
3230 return m_nodedef->allocateDummy(name);
3233 ISoundManager *Server::getSoundManager()
3235 return &dummySoundManager;
3238 MtEventManager *Server::getEventManager()
3243 IWritableItemDefManager *Server::getWritableItemDefManager()
3248 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3253 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3258 const ModSpec *Server::getModSpec(const std::string &modname) const
3260 std::vector<ModSpec>::const_iterator it;
3261 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3262 const ModSpec &mod = *it;
3263 if (mod.name == modname)
3269 void Server::getModNames(std::vector<std::string> &modlist)
3271 std::vector<ModSpec>::iterator it;
3272 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3273 modlist.push_back(it->name);
3276 std::string Server::getBuiltinLuaPath()
3278 return porting::path_share + DIR_DELIM + "builtin";
3281 v3f Server::findSpawnPos()
3283 ServerMap &map = m_env->getServerMap();
3285 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3286 return nodeposf * BS;
3289 // Default position is static_spawnpoint
3290 // We will return it if we don't found a good place
3291 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3293 s16 water_level = map.getWaterLevel();
3295 bool is_good = false;
3297 // Try to find a good place a few times
3298 for(s32 i = 0; i < 1000 && !is_good; i++) {
3300 // We're going to try to throw the player to this position
3301 v2s16 nodepos2d = v2s16(
3302 -range + (myrand() % (range * 2)),
3303 -range + (myrand() % (range * 2)));
3305 // Get ground height at point
3306 s16 groundheight = map.findGroundLevel(nodepos2d);
3307 if (groundheight <= water_level) // Don't go underwater
3309 if (groundheight > water_level + 6) // Don't go to high places
3312 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3315 for (s32 i = 0; i < 10; i++) {
3316 v3s16 blockpos = getNodeBlockPos(nodepos);
3317 map.emergeBlock(blockpos, true);
3318 content_t c = map.getNodeNoEx(nodepos).getContent();
3319 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3321 if (air_count >= 2){
3330 return intToFloat(nodepos, BS);
3333 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3335 bool newplayer = false;
3338 Try to get an existing player
3340 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3342 // If player is already connected, cancel
3343 if(player != NULL && player->peer_id != 0)
3345 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3350 If player with the wanted peer_id already exists, cancel.
3352 if(m_env->getPlayer(peer_id) != NULL)
3354 infostream<<"emergePlayer(): Player with wrong name but same"
3355 " peer_id already exists"<<std::endl;
3359 // Load player if it isn't already loaded
3361 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3364 // Create player if it doesn't exist
3367 player = new RemotePlayer(this, name);
3368 // Set player position
3369 infostream<<"Server: Finding spawn place for player \""
3370 <<name<<"\""<<std::endl;
3371 v3f pos = findSpawnPos();
3372 player->setPosition(pos);
3374 // Make sure the player is saved
3375 player->setModified(true);
3377 // Add player to environment
3378 m_env->addPlayer(player);
3381 // Create a new player active object
3382 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3383 getPlayerEffectivePrivs(player->getName()),
3386 /* Clean up old HUD elements from previous sessions */
3389 /* Add object to environment */
3390 m_env->addActiveObject(playersao);
3394 m_script->on_newplayer(playersao);
3400 void dedicated_server_loop(Server &server, bool &kill)
3402 DSTACK(__FUNCTION_NAME);
3404 verbosestream<<"dedicated_server_loop()"<<std::endl;
3406 IntervalLimiter m_profiler_interval;
3410 float steplen = g_settings->getFloat("dedicated_server_step");
3411 // This is kind of a hack but can be done like this
3412 // because server.step() is very light
3414 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3415 sleep_ms((int)(steplen*1000.0));
3417 server.step(steplen);
3419 if(server.getShutdownRequested() || kill)
3421 infostream<<"Dedicated server quitting"<<std::endl;
3423 if(g_settings->getBool("server_announce"))
3424 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3432 float profiler_print_interval =
3433 g_settings->getFloat("profiler_print_interval");
3434 if(profiler_print_interval != 0)
3436 if(m_profiler_interval.step(steplen, profiler_print_interval))
3438 infostream<<"Profiler:"<<std::endl;
3439 g_profiler->print(infostream);
3440 g_profiler->clear();