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: Saving environment metadata"<<std::endl;
408 // stop all emerge threads before deleting players that may have
409 // requested blocks to be emerged
410 m_emerge->stopThreads();
412 // Delete things in the reverse order of creation
415 // N.B. the EmergeManager should be deleted after the Environment since Map
416 // depends on EmergeManager to write its current params to the map meta
425 // Deinitialize scripting
426 infostream<<"Server: Deinitializing scripting"<<std::endl;
429 // Delete detached inventories
430 for (std::map<std::string, Inventory*>::iterator
431 i = m_detached_inventories.begin();
432 i != m_detached_inventories.end(); i++) {
437 void Server::start(Address bind_addr)
439 DSTACK(__FUNCTION_NAME);
441 m_bind_addr = bind_addr;
443 infostream<<"Starting server on "
444 << bind_addr.serializeString() <<"..."<<std::endl;
446 // Stop thread if already running
449 // Initialize connection
450 m_con.SetTimeoutMs(30);
451 m_con.Serve(bind_addr);
456 // ASCII art for the win!
458 <<" .__ __ __ "<<std::endl
459 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
460 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
461 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
462 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
463 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
464 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
465 actionstream<<"Server for gameid=\""<<m_gamespec.id
466 <<"\" listening on "<<bind_addr.serializeString()<<":"
467 <<bind_addr.getPort() << "."<<std::endl;
472 DSTACK(__FUNCTION_NAME);
474 infostream<<"Server: Stopping and waiting threads"<<std::endl;
476 // Stop threads (set run=false first so both start stopping)
478 //m_emergethread.setRun(false);
480 //m_emergethread.stop();
482 infostream<<"Server: Threads stopped"<<std::endl;
485 void Server::step(float dtime)
487 DSTACK(__FUNCTION_NAME);
492 JMutexAutoLock lock(m_step_dtime_mutex);
493 m_step_dtime += dtime;
495 // Throw if fatal error occurred in thread
496 std::string async_err = m_async_fatal_error.get();
497 if(async_err != "") {
498 if (m_simple_singleplayer_mode) {
499 throw ServerError(async_err);
502 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
503 << "Please fix the following error:" << std::endl
504 << async_err << std::endl;
505 FATAL_ERROR(async_err.c_str());
510 void Server::AsyncRunStep(bool initial_step)
512 DSTACK(__FUNCTION_NAME);
514 g_profiler->add("Server::AsyncRunStep (num)", 1);
518 JMutexAutoLock lock1(m_step_dtime_mutex);
519 dtime = m_step_dtime;
523 // Send blocks to clients
527 if((dtime < 0.001) && (initial_step == false))
530 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
532 //infostream<<"Server steps "<<dtime<<std::endl;
533 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
536 JMutexAutoLock lock1(m_step_dtime_mutex);
537 m_step_dtime -= dtime;
544 m_uptime.set(m_uptime.get() + dtime);
550 Update time of day and overall game time
552 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
555 Send to clients at constant intervals
558 m_time_of_day_send_timer -= dtime;
559 if(m_time_of_day_send_timer < 0.0) {
560 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
561 u16 time = m_env->getTimeOfDay();
562 float time_speed = g_settings->getFloat("time_speed");
563 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
567 JMutexAutoLock lock(m_env_mutex);
568 // Figure out and report maximum lag to environment
569 float max_lag = m_env->getMaxLagEstimate();
570 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
572 if(dtime > 0.1 && dtime > max_lag * 2.0)
573 infostream<<"Server: Maximum lag peaked to "<<dtime
577 m_env->reportMaxLagEstimate(max_lag);
579 ScopeProfiler sp(g_profiler, "SEnv step");
580 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
584 static const float map_timer_and_unload_dtime = 2.92;
585 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
587 JMutexAutoLock lock(m_env_mutex);
588 // Run Map's timers and unload unused data
589 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
590 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
591 g_settings->getFloat("server_unload_unused_data_timeout"));
598 /* Transform liquids */
599 m_liquid_transform_timer += dtime;
600 if(m_liquid_transform_timer >= m_liquid_transform_every)
602 m_liquid_transform_timer -= m_liquid_transform_every;
604 JMutexAutoLock lock(m_env_mutex);
606 ScopeProfiler sp(g_profiler, "Server: liquid transform");
608 std::map<v3s16, MapBlock*> modified_blocks;
609 m_env->getMap().transformLiquids(modified_blocks);
614 core::map<v3s16, MapBlock*> lighting_modified_blocks;
615 ServerMap &map = ((ServerMap&)m_env->getMap());
616 map.updateLighting(modified_blocks, lighting_modified_blocks);
618 // Add blocks modified by lighting to modified_blocks
619 for(core::map<v3s16, MapBlock*>::Iterator
620 i = lighting_modified_blocks.getIterator();
621 i.atEnd() == false; i++)
623 MapBlock *block = i.getNode()->getValue();
624 modified_blocks.insert(block->getPos(), block);
628 Set the modified blocks unsent for all the clients
630 if(!modified_blocks.empty())
632 SetBlocksNotSent(modified_blocks);
635 m_clients.step(dtime);
637 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
639 // send masterserver announce
641 float &counter = m_masterserver_timer;
642 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
643 g_settings->getBool("server_announce"))
645 ServerList::sendAnnounce(counter ? "update" : "start",
646 m_bind_addr.getPort(),
647 m_clients.getPlayerNames(),
649 m_env->getGameTime(),
652 m_emerge->params.mg_name,
661 Check added and deleted active objects
664 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
665 JMutexAutoLock envlock(m_env_mutex);
668 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
669 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
671 // Radius inside which objects are active
672 s16 radius = g_settings->getS16("active_object_send_range_blocks");
673 s16 player_radius = g_settings->getS16("player_transfer_distance");
675 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
676 !g_settings->getBool("unlimited_player_transfer_distance"))
677 player_radius = radius;
679 radius *= MAP_BLOCKSIZE;
680 player_radius *= MAP_BLOCKSIZE;
682 for(std::map<u16, RemoteClient*>::iterator
684 i != clients.end(); ++i)
686 RemoteClient *client = i->second;
688 // If definitions and textures have not been sent, don't
689 // send objects either
690 if (client->getState() < CS_DefinitionsSent)
693 Player *player = m_env->getPlayer(client->peer_id);
696 // This can happen if the client timeouts somehow
697 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
699 <<" has no associated player"<<std::endl;*/
702 v3s16 pos = floatToInt(player->getPosition(), BS);
704 std::set<u16> removed_objects;
705 std::set<u16> added_objects;
706 m_env->getRemovedActiveObjects(pos, radius, player_radius,
707 client->m_known_objects, removed_objects);
708 m_env->getAddedActiveObjects(pos, radius, player_radius,
709 client->m_known_objects, added_objects);
711 // Ignore if nothing happened
712 if(removed_objects.empty() && added_objects.empty())
714 //infostream<<"active objects: none changed"<<std::endl;
718 std::string data_buffer;
722 // Handle removed objects
723 writeU16((u8*)buf, removed_objects.size());
724 data_buffer.append(buf, 2);
725 for(std::set<u16>::iterator
726 i = removed_objects.begin();
727 i != removed_objects.end(); ++i)
731 ServerActiveObject* obj = m_env->getActiveObject(id);
733 // Add to data buffer for sending
734 writeU16((u8*)buf, id);
735 data_buffer.append(buf, 2);
737 // Remove from known objects
738 client->m_known_objects.erase(id);
740 if(obj && obj->m_known_by_count > 0)
741 obj->m_known_by_count--;
744 // Handle added objects
745 writeU16((u8*)buf, added_objects.size());
746 data_buffer.append(buf, 2);
747 for(std::set<u16>::iterator
748 i = added_objects.begin();
749 i != added_objects.end(); ++i)
753 ServerActiveObject* obj = m_env->getActiveObject(id);
756 u8 type = ACTIVEOBJECT_TYPE_INVALID;
758 infostream<<"WARNING: "<<__FUNCTION_NAME
759 <<": NULL object"<<std::endl;
761 type = obj->getSendType();
763 // Add to data buffer for sending
764 writeU16((u8*)buf, id);
765 data_buffer.append(buf, 2);
766 writeU8((u8*)buf, type);
767 data_buffer.append(buf, 1);
770 data_buffer.append(serializeLongString(
771 obj->getClientInitializationData(client->net_proto_version)));
773 data_buffer.append(serializeLongString(""));
775 // Add to known objects
776 client->m_known_objects.insert(id);
779 obj->m_known_by_count++;
782 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
783 verbosestream << "Server: Sent object remove/add: "
784 << removed_objects.size() << " removed, "
785 << added_objects.size() << " added, "
786 << "packet size is " << pktSize << std::endl;
795 JMutexAutoLock envlock(m_env_mutex);
796 ScopeProfiler sp(g_profiler, "Server: sending object messages");
799 // Value = data sent by object
800 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
802 // Get active object messages from environment
804 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
808 std::vector<ActiveObjectMessage>* message_list = NULL;
809 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
810 n = buffered_messages.find(aom.id);
811 if (n == buffered_messages.end()) {
812 message_list = new std::vector<ActiveObjectMessage>;
813 buffered_messages[aom.id] = message_list;
816 message_list = n->second;
818 message_list->push_back(aom);
822 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
823 // Route data to every client
824 for (std::map<u16, RemoteClient*>::iterator
826 i != clients.end(); ++i) {
827 RemoteClient *client = i->second;
828 std::string reliable_data;
829 std::string unreliable_data;
830 // Go through all objects in message buffer
831 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
832 j = buffered_messages.begin();
833 j != buffered_messages.end(); ++j) {
834 // If object is not known by client, skip it
836 if (client->m_known_objects.find(id) == client->m_known_objects.end())
839 // Get message list of object
840 std::vector<ActiveObjectMessage>* list = j->second;
841 // Go through every message
842 for (std::vector<ActiveObjectMessage>::iterator
843 k = list->begin(); k != list->end(); ++k) {
844 // Compose the full new data with header
845 ActiveObjectMessage aom = *k;
846 std::string new_data;
849 writeU16((u8*)&buf[0], aom.id);
850 new_data.append(buf, 2);
852 new_data += serializeString(aom.datastring);
853 // Add data to buffer
855 reliable_data += new_data;
857 unreliable_data += new_data;
861 reliable_data and unreliable_data are now ready.
864 if(reliable_data.size() > 0) {
865 SendActiveObjectMessages(client->peer_id, reliable_data);
868 if(unreliable_data.size() > 0) {
869 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
874 // Clear buffered_messages
875 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
876 i = buffered_messages.begin();
877 i != buffered_messages.end(); ++i) {
883 Send queued-for-sending map edit events.
886 // We will be accessing the environment
887 JMutexAutoLock lock(m_env_mutex);
889 // Don't send too many at a time
892 // Single change sending is disabled if queue size is not small
893 bool disable_single_change_sending = false;
894 if(m_unsent_map_edit_queue.size() >= 4)
895 disable_single_change_sending = true;
897 int event_count = m_unsent_map_edit_queue.size();
899 // We'll log the amount of each
902 while(m_unsent_map_edit_queue.size() != 0)
904 MapEditEvent* event = m_unsent_map_edit_queue.front();
905 m_unsent_map_edit_queue.pop();
907 // Players far away from the change are stored here.
908 // Instead of sending the changes, MapBlocks are set not sent
910 std::vector<u16> far_players;
912 switch (event->type) {
915 prof.add("MEET_ADDNODE", 1);
916 sendAddNode(event->p, event->n, event->already_known_by_peer,
917 &far_players, disable_single_change_sending ? 5 : 30,
918 event->type == MEET_ADDNODE);
920 case MEET_REMOVENODE:
921 prof.add("MEET_REMOVENODE", 1);
922 sendRemoveNode(event->p, event->already_known_by_peer,
923 &far_players, disable_single_change_sending ? 5 : 30);
925 case MEET_BLOCK_NODE_METADATA_CHANGED:
926 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
927 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
928 setBlockNotSent(event->p);
931 infostream << "Server: MEET_OTHER" << std::endl;
932 prof.add("MEET_OTHER", 1);
933 for(std::set<v3s16>::iterator
934 i = event->modified_blocks.begin();
935 i != event->modified_blocks.end(); ++i) {
940 prof.add("unknown", 1);
941 infostream << "WARNING: Server: Unknown MapEditEvent "
942 << ((u32)event->type) << std::endl;
947 Set blocks not sent to far players
949 if(!far_players.empty()) {
950 // Convert list format to that wanted by SetBlocksNotSent
951 std::map<v3s16, MapBlock*> modified_blocks2;
952 for(std::set<v3s16>::iterator
953 i = event->modified_blocks.begin();
954 i != event->modified_blocks.end(); ++i) {
955 modified_blocks2[*i] =
956 m_env->getMap().getBlockNoCreateNoEx(*i);
959 // Set blocks not sent
960 for(std::vector<u16>::iterator
961 i = far_players.begin();
962 i != far_players.end(); ++i) {
963 if(RemoteClient *client = getClient(*i))
964 client->SetBlocksNotSent(modified_blocks2);
970 /*// Don't send too many at a time
972 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
976 if(event_count >= 5){
977 infostream<<"Server: MapEditEvents:"<<std::endl;
978 prof.print(infostream);
979 } else if(event_count != 0){
980 verbosestream<<"Server: MapEditEvents:"<<std::endl;
981 prof.print(verbosestream);
987 Trigger emergethread (it somehow gets to a non-triggered but
988 bysy state sometimes)
991 float &counter = m_emergethread_trigger_timer;
997 m_emerge->startThreads();
1001 // Save map, players and auth stuff
1003 float &counter = m_savemap_timer;
1005 if(counter >= g_settings->getFloat("server_map_save_interval"))
1008 JMutexAutoLock lock(m_env_mutex);
1010 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1013 if (m_banmanager->isModified()) {
1014 m_banmanager->save();
1017 // Save changed parts of map
1018 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1021 m_env->saveLoadedPlayers();
1023 // Save environment metadata
1029 void Server::Receive()
1031 DSTACK(__FUNCTION_NAME);
1032 SharedBuffer<u8> data;
1036 m_con.Receive(&pkt);
1037 peer_id = pkt.getPeerId();
1040 catch(con::InvalidIncomingDataException &e) {
1041 infostream<<"Server::Receive(): "
1042 "InvalidIncomingDataException: what()="
1043 <<e.what()<<std::endl;
1045 catch(SerializationError &e) {
1046 infostream<<"Server::Receive(): "
1047 "SerializationError: what()="
1048 <<e.what()<<std::endl;
1050 catch(ClientStateError &e) {
1051 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1052 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1053 L"Try reconnecting or updating your client");
1055 catch(con::PeerNotFoundException &e) {
1060 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1062 std::string playername = "";
1063 PlayerSAO *playersao = NULL;
1066 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1067 if (client != NULL) {
1068 playername = client->getName();
1069 playersao = emergePlayer(playername.c_str(), peer_id);
1071 } catch (std::exception &e) {
1077 RemotePlayer *player =
1078 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1080 // If failed, cancel
1081 if ((playersao == NULL) || (player == NULL)) {
1082 if (player && player->peer_id != 0) {
1083 actionstream << "Server: Failed to emerge player \"" << playername
1084 << "\" (player allocated to an another client)" << std::endl;
1085 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1086 L"name. If your client closed unexpectedly, try again in "
1089 errorstream << "Server: " << playername << ": Failed to emerge player"
1091 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1097 Send complete position information
1099 SendMovePlayer(peer_id);
1102 SendPlayerPrivileges(peer_id);
1104 // Send inventory formspec
1105 SendPlayerInventoryFormspec(peer_id);
1108 SendInventory(playersao);
1111 SendPlayerHPOrDie(playersao);
1114 SendPlayerBreath(peer_id);
1116 // Show death screen if necessary
1117 if(player->isDead())
1118 SendDeathscreen(peer_id, false, v3f(0,0,0));
1120 // Note things in chat if not in simple singleplayer mode
1121 if(!m_simple_singleplayer_mode) {
1122 // Send information about server to player in chat
1123 SendChatMessage(peer_id, getStatusString());
1125 // Send information about joining in chat
1127 std::wstring name = L"unknown";
1128 Player *player = m_env->getPlayer(peer_id);
1130 name = narrow_to_wide(player->getName());
1132 std::wstring message;
1135 message += L" joined the game.";
1136 SendChatMessage(PEER_ID_INEXISTENT,message);
1139 Address addr = getPeerAddress(player->peer_id);
1140 std::string ip_str = addr.serializeString();
1141 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1146 std::vector<std::string> names = m_clients.getPlayerNames();
1148 actionstream<<player->getName() <<" joins game. List of players: ";
1150 for (std::vector<std::string>::iterator i = names.begin();
1151 i != names.end(); i++) {
1152 actionstream << *i << " ";
1155 actionstream << player->getName() <<std::endl;
1160 inline void Server::handleCommand(NetworkPacket* pkt)
1162 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1163 (this->*opHandle.handler)(pkt);
1166 void Server::ProcessData(NetworkPacket *pkt)
1168 DSTACK(__FUNCTION_NAME);
1169 // Environment is locked first.
1170 JMutexAutoLock envlock(m_env_mutex);
1172 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1173 u32 peer_id = pkt->getPeerId();
1176 Address address = getPeerAddress(peer_id);
1177 std::string addr_s = address.serializeString();
1179 if(m_banmanager->isIpBanned(addr_s)) {
1180 std::string ban_name = m_banmanager->getBanName(addr_s);
1181 infostream << "Server: A banned client tried to connect from "
1182 << addr_s << "; banned name was "
1183 << ban_name << std::endl;
1184 // This actually doesn't seem to transfer to the client
1185 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1186 + utf8_to_wide(ban_name));
1190 catch(con::PeerNotFoundException &e) {
1192 * no peer for this packet found
1193 * most common reason is peer timeout, e.g. peer didn't
1194 * respond for some time, your server was overloaded or
1197 infostream << "Server::ProcessData(): Canceling: peer "
1198 << peer_id << " not found" << std::endl;
1203 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1205 // Command must be handled into ToServerCommandHandler
1206 if (command >= TOSERVER_NUM_MSG_TYPES) {
1207 infostream << "Server: Ignoring unknown command "
1208 << command << std::endl;
1212 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1217 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1219 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1220 errorstream << "Server::ProcessData(): Cancelling: Peer"
1221 " serialization format invalid or not initialized."
1222 " Skipping incoming command=" << command << std::endl;
1226 /* Handle commands related to client startup */
1227 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1232 if (m_clients.getClientState(peer_id) < CS_Active) {
1233 if (command == TOSERVER_PLAYERPOS) return;
1235 errorstream << "Got packet command: " << command << " for peer id "
1236 << peer_id << " but client isn't active yet. Dropping packet "
1242 } catch (SendFailedException &e) {
1243 errorstream << "Server::ProcessData(): SendFailedException: "
1244 << "what=" << e.what()
1246 } catch (PacketError &e) {
1247 actionstream << "Server::ProcessData(): PacketError: "
1248 << "what=" << e.what()
1253 void Server::setTimeOfDay(u32 time)
1255 m_env->setTimeOfDay(time);
1256 m_time_of_day_send_timer = 0;
1259 void Server::onMapEditEvent(MapEditEvent *event)
1261 if(m_ignore_map_edit_events)
1263 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1265 MapEditEvent *e = event->clone();
1266 m_unsent_map_edit_queue.push(e);
1269 Inventory* Server::getInventory(const InventoryLocation &loc)
1272 case InventoryLocation::UNDEFINED:
1273 case InventoryLocation::CURRENT_PLAYER:
1275 case InventoryLocation::PLAYER:
1277 Player *player = m_env->getPlayer(loc.name.c_str());
1280 PlayerSAO *playersao = player->getPlayerSAO();
1283 return playersao->getInventory();
1286 case InventoryLocation::NODEMETA:
1288 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1291 return meta->getInventory();
1294 case InventoryLocation::DETACHED:
1296 if(m_detached_inventories.count(loc.name) == 0)
1298 return m_detached_inventories[loc.name];
1302 sanity_check(false); // abort
1307 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1310 case InventoryLocation::UNDEFINED:
1312 case InventoryLocation::PLAYER:
1317 Player *player = m_env->getPlayer(loc.name.c_str());
1320 PlayerSAO *playersao = player->getPlayerSAO();
1324 SendInventory(playersao);
1327 case InventoryLocation::NODEMETA:
1329 v3s16 blockpos = getNodeBlockPos(loc.p);
1331 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1333 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1335 setBlockNotSent(blockpos);
1338 case InventoryLocation::DETACHED:
1340 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1344 sanity_check(false); // abort
1349 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1351 std::vector<u16> clients = m_clients.getClientIDs();
1353 // Set the modified blocks unsent for all the clients
1354 for (std::vector<u16>::iterator i = clients.begin();
1355 i != clients.end(); ++i) {
1356 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1357 client->SetBlocksNotSent(block);
1362 void Server::peerAdded(con::Peer *peer)
1364 DSTACK(__FUNCTION_NAME);
1365 verbosestream<<"Server::peerAdded(): peer->id="
1366 <<peer->id<<std::endl;
1369 c.type = con::PEER_ADDED;
1370 c.peer_id = peer->id;
1372 m_peer_change_queue.push(c);
1375 void Server::deletingPeer(con::Peer *peer, bool timeout)
1377 DSTACK(__FUNCTION_NAME);
1378 verbosestream<<"Server::deletingPeer(): peer->id="
1379 <<peer->id<<", timeout="<<timeout<<std::endl;
1381 m_clients.event(peer->id, CSE_Disconnect);
1383 c.type = con::PEER_REMOVED;
1384 c.peer_id = peer->id;
1385 c.timeout = timeout;
1386 m_peer_change_queue.push(c);
1389 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1391 *retval = m_con.getPeerStat(peer_id,type);
1392 if (*retval == -1) return false;
1396 bool Server::getClientInfo(
1405 std::string* vers_string
1408 *state = m_clients.getClientState(peer_id);
1410 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1412 if (client == NULL) {
1417 *uptime = client->uptime();
1418 *ser_vers = client->serialization_version;
1419 *prot_vers = client->net_proto_version;
1421 *major = client->getMajor();
1422 *minor = client->getMinor();
1423 *patch = client->getPatch();
1424 *vers_string = client->getPatch();
1431 void Server::handlePeerChanges()
1433 while(m_peer_change_queue.size() > 0)
1435 con::PeerChange c = m_peer_change_queue.front();
1436 m_peer_change_queue.pop();
1438 verbosestream<<"Server: Handling peer change: "
1439 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1444 case con::PEER_ADDED:
1445 m_clients.CreateClient(c.peer_id);
1448 case con::PEER_REMOVED:
1449 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1453 FATAL_ERROR("Invalid peer change event received!");
1459 void Server::Send(NetworkPacket* pkt)
1461 m_clients.send(pkt->getPeerId(),
1462 clientCommandFactoryTable[pkt->getCommand()].channel,
1464 clientCommandFactoryTable[pkt->getCommand()].reliable);
1467 void Server::SendMovement(u16 peer_id)
1469 DSTACK(__FUNCTION_NAME);
1470 std::ostringstream os(std::ios_base::binary);
1472 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1474 pkt << g_settings->getFloat("movement_acceleration_default");
1475 pkt << g_settings->getFloat("movement_acceleration_air");
1476 pkt << g_settings->getFloat("movement_acceleration_fast");
1477 pkt << g_settings->getFloat("movement_speed_walk");
1478 pkt << g_settings->getFloat("movement_speed_crouch");
1479 pkt << g_settings->getFloat("movement_speed_fast");
1480 pkt << g_settings->getFloat("movement_speed_climb");
1481 pkt << g_settings->getFloat("movement_speed_jump");
1482 pkt << g_settings->getFloat("movement_liquid_fluidity");
1483 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1484 pkt << g_settings->getFloat("movement_liquid_sink");
1485 pkt << g_settings->getFloat("movement_gravity");
1490 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1492 if (!g_settings->getBool("enable_damage"))
1495 u16 peer_id = playersao->getPeerID();
1496 bool is_alive = playersao->getHP() > 0;
1499 SendPlayerHP(peer_id);
1504 void Server::SendHP(u16 peer_id, u8 hp)
1506 DSTACK(__FUNCTION_NAME);
1508 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1513 void Server::SendBreath(u16 peer_id, u16 breath)
1515 DSTACK(__FUNCTION_NAME);
1517 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1518 pkt << (u16) breath;
1522 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1524 DSTACK(__FUNCTION_NAME);
1526 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1529 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1530 pkt << custom_reason;
1535 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1537 DSTACK(__FUNCTION_NAME);
1539 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1544 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1545 v3f camera_point_target)
1547 DSTACK(__FUNCTION_NAME);
1549 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1550 pkt << set_camera_point_target << camera_point_target;
1554 void Server::SendItemDef(u16 peer_id,
1555 IItemDefManager *itemdef, u16 protocol_version)
1557 DSTACK(__FUNCTION_NAME);
1559 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1563 u32 length of the next item
1564 zlib-compressed serialized ItemDefManager
1566 std::ostringstream tmp_os(std::ios::binary);
1567 itemdef->serialize(tmp_os, protocol_version);
1568 std::ostringstream tmp_os2(std::ios::binary);
1569 compressZlib(tmp_os.str(), tmp_os2);
1570 pkt.putLongString(tmp_os2.str());
1573 verbosestream << "Server: Sending item definitions to id(" << peer_id
1574 << "): size=" << pkt.getSize() << std::endl;
1579 void Server::SendNodeDef(u16 peer_id,
1580 INodeDefManager *nodedef, u16 protocol_version)
1582 DSTACK(__FUNCTION_NAME);
1584 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1588 u32 length of the next item
1589 zlib-compressed serialized NodeDefManager
1591 std::ostringstream tmp_os(std::ios::binary);
1592 nodedef->serialize(tmp_os, protocol_version);
1593 std::ostringstream tmp_os2(std::ios::binary);
1594 compressZlib(tmp_os.str(), tmp_os2);
1596 pkt.putLongString(tmp_os2.str());
1599 verbosestream << "Server: Sending node definitions to id(" << peer_id
1600 << "): size=" << pkt.getSize() << std::endl;
1606 Non-static send methods
1609 void Server::SendInventory(PlayerSAO* playerSAO)
1611 DSTACK(__FUNCTION_NAME);
1613 UpdateCrafting(playerSAO->getPlayer());
1619 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1621 std::ostringstream os;
1622 playerSAO->getInventory()->serialize(os);
1624 std::string s = os.str();
1626 pkt.putRawString(s.c_str(), s.size());
1630 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1632 DSTACK(__FUNCTION_NAME);
1634 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1637 if (peer_id != PEER_ID_INEXISTENT) {
1641 m_clients.sendToAll(0, &pkt, true);
1645 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1646 const std::string &formname)
1648 DSTACK(__FUNCTION_NAME);
1650 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1652 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1658 // Spawns a particle on peer with peer_id
1659 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1660 float expirationtime, float size, bool collisiondetection,
1661 bool vertical, std::string texture)
1663 DSTACK(__FUNCTION_NAME);
1665 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1667 pkt << pos << velocity << acceleration << expirationtime
1668 << size << collisiondetection;
1669 pkt.putLongString(texture);
1672 if (peer_id != PEER_ID_INEXISTENT) {
1676 m_clients.sendToAll(0, &pkt, true);
1680 // Adds a ParticleSpawner on peer with peer_id
1681 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1682 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1683 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1685 DSTACK(__FUNCTION_NAME);
1687 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1689 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1690 << minacc << maxacc << minexptime << maxexptime << minsize
1691 << maxsize << collisiondetection;
1693 pkt.putLongString(texture);
1695 pkt << id << vertical;
1697 if (peer_id != PEER_ID_INEXISTENT) {
1701 m_clients.sendToAll(0, &pkt, true);
1705 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1707 DSTACK(__FUNCTION_NAME);
1709 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1711 // Ugly error in this packet
1714 if (peer_id != PEER_ID_INEXISTENT) {
1718 m_clients.sendToAll(0, &pkt, true);
1723 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1725 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1727 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1728 << form->text << form->number << form->item << form->dir
1729 << form->align << form->offset << form->world_pos << form->size;
1734 void Server::SendHUDRemove(u16 peer_id, u32 id)
1736 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1741 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1743 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1744 pkt << id << (u8) stat;
1748 case HUD_STAT_SCALE:
1749 case HUD_STAT_ALIGN:
1750 case HUD_STAT_OFFSET:
1751 pkt << *(v2f *) value;
1755 pkt << *(std::string *) value;
1757 case HUD_STAT_WORLD_POS:
1758 pkt << *(v3f *) value;
1761 pkt << *(v2s32 *) value;
1763 case HUD_STAT_NUMBER:
1767 pkt << *(u32 *) value;
1774 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1776 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1778 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1780 pkt << flags << mask;
1785 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1787 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1788 pkt << param << value;
1792 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1793 const std::string &type, const std::vector<std::string> ¶ms)
1795 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1796 pkt << bgcolor << type << (u16) params.size();
1798 for(size_t i=0; i<params.size(); i++)
1804 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1807 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1810 pkt << do_override << (u16) (ratio * 65535);
1815 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1817 DSTACK(__FUNCTION_NAME);
1819 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1820 pkt << time << time_speed;
1822 if (peer_id == PEER_ID_INEXISTENT) {
1823 m_clients.sendToAll(0, &pkt, true);
1830 void Server::SendPlayerHP(u16 peer_id)
1832 DSTACK(__FUNCTION_NAME);
1833 PlayerSAO *playersao = getPlayerSAO(peer_id);
1834 // In some rare case, if the player is disconnected
1835 // while Lua call l_punch, for example, this can be NULL
1839 SendHP(peer_id, playersao->getHP());
1840 m_script->player_event(playersao,"health_changed");
1842 // Send to other clients
1843 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1844 ActiveObjectMessage aom(playersao->getId(), true, str);
1845 playersao->m_messages_out.push(aom);
1848 void Server::SendPlayerBreath(u16 peer_id)
1850 DSTACK(__FUNCTION_NAME);
1851 PlayerSAO *playersao = getPlayerSAO(peer_id);
1854 m_script->player_event(playersao, "breath_changed");
1855 SendBreath(peer_id, playersao->getBreath());
1858 void Server::SendMovePlayer(u16 peer_id)
1860 DSTACK(__FUNCTION_NAME);
1861 Player *player = m_env->getPlayer(peer_id);
1864 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1865 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1868 v3f pos = player->getPosition();
1869 f32 pitch = player->getPitch();
1870 f32 yaw = player->getYaw();
1871 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1872 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1873 << " pitch=" << pitch
1881 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1883 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1886 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1887 << animation_frames[3] << animation_speed;
1892 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1894 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1895 pkt << first << third;
1898 void Server::SendPlayerPrivileges(u16 peer_id)
1900 Player *player = m_env->getPlayer(peer_id);
1902 if(player->peer_id == PEER_ID_INEXISTENT)
1905 std::set<std::string> privs;
1906 m_script->getAuth(player->getName(), NULL, &privs);
1908 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1909 pkt << (u16) privs.size();
1911 for(std::set<std::string>::const_iterator i = privs.begin();
1912 i != privs.end(); i++) {
1919 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1921 Player *player = m_env->getPlayer(peer_id);
1923 if(player->peer_id == PEER_ID_INEXISTENT)
1926 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1927 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1931 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1933 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1934 pkt.putRawString(datas.c_str(), datas.size());
1936 return pkt.getSize();
1939 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1941 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1942 datas.size(), peer_id);
1944 pkt.putRawString(datas.c_str(), datas.size());
1946 m_clients.send(pkt.getPeerId(),
1947 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1952 s32 Server::playSound(const SimpleSoundSpec &spec,
1953 const ServerSoundParams ¶ms)
1955 // Find out initial position of sound
1956 bool pos_exists = false;
1957 v3f pos = params.getPos(m_env, &pos_exists);
1958 // If position is not found while it should be, cancel sound
1959 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1962 // Filter destination clients
1963 std::vector<u16> dst_clients;
1964 if(params.to_player != "")
1966 Player *player = m_env->getPlayer(params.to_player.c_str());
1968 infostream<<"Server::playSound: Player \""<<params.to_player
1969 <<"\" not found"<<std::endl;
1972 if(player->peer_id == PEER_ID_INEXISTENT){
1973 infostream<<"Server::playSound: Player \""<<params.to_player
1974 <<"\" not connected"<<std::endl;
1977 dst_clients.push_back(player->peer_id);
1980 std::vector<u16> clients = m_clients.getClientIDs();
1982 for(std::vector<u16>::iterator
1983 i = clients.begin(); i != clients.end(); ++i) {
1984 Player *player = m_env->getPlayer(*i);
1989 if(player->getPosition().getDistanceFrom(pos) >
1990 params.max_hear_distance)
1993 dst_clients.push_back(*i);
1997 if(dst_clients.empty())
2001 s32 id = m_next_sound_id++;
2002 // The sound will exist as a reference in m_playing_sounds
2003 m_playing_sounds[id] = ServerPlayingSound();
2004 ServerPlayingSound &psound = m_playing_sounds[id];
2005 psound.params = params;
2007 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2008 pkt << id << spec.name << (float) (spec.gain * params.gain)
2009 << (u8) params.type << pos << params.object << params.loop;
2011 for(std::vector<u16>::iterator i = dst_clients.begin();
2012 i != dst_clients.end(); i++) {
2013 psound.clients.insert(*i);
2014 m_clients.send(*i, 0, &pkt, true);
2018 void Server::stopSound(s32 handle)
2020 // Get sound reference
2021 std::map<s32, ServerPlayingSound>::iterator i =
2022 m_playing_sounds.find(handle);
2023 if(i == m_playing_sounds.end())
2025 ServerPlayingSound &psound = i->second;
2027 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2030 for(std::set<u16>::iterator i = psound.clients.begin();
2031 i != psound.clients.end(); i++) {
2033 m_clients.send(*i, 0, &pkt, true);
2035 // Remove sound reference
2036 m_playing_sounds.erase(i);
2039 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2040 std::vector<u16> *far_players, float far_d_nodes)
2042 float maxd = far_d_nodes*BS;
2043 v3f p_f = intToFloat(p, BS);
2045 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2048 std::vector<u16> clients = m_clients.getClientIDs();
2049 for(std::vector<u16>::iterator i = clients.begin();
2050 i != clients.end(); ++i) {
2053 if(Player *player = m_env->getPlayer(*i)) {
2054 // If player is far away, only set modified blocks not sent
2055 v3f player_pos = player->getPosition();
2056 if(player_pos.getDistanceFrom(p_f) > maxd) {
2057 far_players->push_back(*i);
2064 m_clients.send(*i, 0, &pkt, true);
2068 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2069 std::vector<u16> *far_players, float far_d_nodes,
2070 bool remove_metadata)
2072 float maxd = far_d_nodes*BS;
2073 v3f p_f = intToFloat(p, BS);
2075 std::vector<u16> clients = m_clients.getClientIDs();
2076 for(std::vector<u16>::iterator i = clients.begin();
2077 i != clients.end(); ++i) {
2081 if(Player *player = m_env->getPlayer(*i)) {
2082 // If player is far away, only set modified blocks not sent
2083 v3f player_pos = player->getPosition();
2084 if(player_pos.getDistanceFrom(p_f) > maxd) {
2085 far_players->push_back(*i);
2091 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2093 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2095 pkt << p << n.param0 << n.param1 << n.param2
2096 << (u8) (remove_metadata ? 0 : 1);
2098 if (!remove_metadata) {
2099 if (client->net_proto_version <= 21) {
2100 // Old clients always clear metadata; fix it
2101 // by sending the full block again.
2102 client->SetBlockNotSent(p);
2109 if (pkt.getSize() > 0)
2110 m_clients.send(*i, 0, &pkt, true);
2114 void Server::setBlockNotSent(v3s16 p)
2116 std::vector<u16> clients = m_clients.getClientIDs();
2118 for(std::vector<u16>::iterator i = clients.begin();
2119 i != clients.end(); ++i) {
2120 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2121 client->SetBlockNotSent(p);
2126 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2128 DSTACK(__FUNCTION_NAME);
2130 v3s16 p = block->getPos();
2133 Create a packet with the block in the right format
2136 std::ostringstream os(std::ios_base::binary);
2137 block->serialize(os, ver, false);
2138 block->serializeNetworkSpecific(os, net_proto_version);
2139 std::string s = os.str();
2141 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2144 pkt.putRawString(s.c_str(), s.size());
2148 void Server::SendBlocks(float dtime)
2150 DSTACK(__FUNCTION_NAME);
2152 JMutexAutoLock envlock(m_env_mutex);
2153 //TODO check if one big lock could be faster then multiple small ones
2155 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2157 std::vector<PrioritySortedBlockTransfer> queue;
2159 s32 total_sending = 0;
2162 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2164 std::vector<u16> clients = m_clients.getClientIDs();
2167 for(std::vector<u16>::iterator i = clients.begin();
2168 i != clients.end(); ++i) {
2169 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2174 total_sending += client->SendingCount();
2175 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2181 // Lowest priority number comes first.
2182 // Lowest is most important.
2183 std::sort(queue.begin(), queue.end());
2186 for(u32 i=0; i<queue.size(); i++)
2188 //TODO: Calculate limit dynamically
2189 if(total_sending >= g_settings->getS32
2190 ("max_simultaneous_block_sends_server_total"))
2193 PrioritySortedBlockTransfer q = queue[i];
2195 MapBlock *block = NULL;
2198 block = m_env->getMap().getBlockNoCreate(q.pos);
2200 catch(InvalidPositionException &e)
2205 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2210 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2212 client->SentBlock(q.pos);
2218 void Server::fillMediaCache()
2220 DSTACK(__FUNCTION_NAME);
2222 infostream<<"Server: Calculating media file checksums"<<std::endl;
2224 // Collect all media file paths
2225 std::vector<std::string> paths;
2226 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2227 i != m_mods.end(); i++) {
2228 const ModSpec &mod = *i;
2229 paths.push_back(mod.path + DIR_DELIM + "textures");
2230 paths.push_back(mod.path + DIR_DELIM + "sounds");
2231 paths.push_back(mod.path + DIR_DELIM + "media");
2232 paths.push_back(mod.path + DIR_DELIM + "models");
2234 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2236 // Collect media file information from paths into cache
2237 for(std::vector<std::string>::iterator i = paths.begin();
2238 i != paths.end(); i++) {
2239 std::string mediapath = *i;
2240 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2241 for (u32 j = 0; j < dirlist.size(); j++) {
2242 if (dirlist[j].dir) // Ignode dirs
2244 std::string filename = dirlist[j].name;
2245 // If name contains illegal characters, ignore the file
2246 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2247 infostream<<"Server: ignoring illegal file name: \""
2248 << filename << "\"" << std::endl;
2251 // If name is not in a supported format, ignore it
2252 const char *supported_ext[] = {
2253 ".png", ".jpg", ".bmp", ".tga",
2254 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2256 ".x", ".b3d", ".md2", ".obj",
2259 if (removeStringEnd(filename, supported_ext) == ""){
2260 infostream << "Server: ignoring unsupported file extension: \""
2261 << filename << "\"" << std::endl;
2264 // Ok, attempt to load the file and add to cache
2265 std::string filepath = mediapath + DIR_DELIM + filename;
2267 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2269 errorstream << "Server::fillMediaCache(): Could not open \""
2270 << filename << "\" for reading" << std::endl;
2273 std::ostringstream tmp_os(std::ios_base::binary);
2277 fis.read(buf, 1024);
2278 std::streamsize len = fis.gcount();
2279 tmp_os.write(buf, len);
2288 errorstream<<"Server::fillMediaCache(): Failed to read \""
2289 << filename << "\"" << std::endl;
2292 if(tmp_os.str().length() == 0) {
2293 errorstream << "Server::fillMediaCache(): Empty file \""
2294 << filepath << "\"" << std::endl;
2299 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2301 unsigned char *digest = sha1.getDigest();
2302 std::string sha1_base64 = base64_encode(digest, 20);
2303 std::string sha1_hex = hex_encode((char*)digest, 20);
2307 m_media[filename] = MediaInfo(filepath, sha1_base64);
2308 verbosestream << "Server: " << sha1_hex << " is " << filename
2314 struct SendableMediaAnnouncement
2317 std::string sha1_digest;
2319 SendableMediaAnnouncement(const std::string &name_="",
2320 const std::string &sha1_digest_=""):
2322 sha1_digest(sha1_digest_)
2326 void Server::sendMediaAnnouncement(u16 peer_id)
2328 DSTACK(__FUNCTION_NAME);
2330 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2333 std::vector<SendableMediaAnnouncement> file_announcements;
2335 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2336 i != m_media.end(); i++){
2338 file_announcements.push_back(
2339 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2343 std::ostringstream os(std::ios_base::binary);
2345 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2346 pkt << (u16) file_announcements.size();
2348 for (std::vector<SendableMediaAnnouncement>::iterator
2349 j = file_announcements.begin();
2350 j != file_announcements.end(); ++j) {
2351 pkt << j->name << j->sha1_digest;
2354 pkt << g_settings->get("remote_media");
2358 struct SendableMedia
2364 SendableMedia(const std::string &name_="", const std::string &path_="",
2365 const std::string &data_=""):
2372 void Server::sendRequestedMedia(u16 peer_id,
2373 const std::vector<std::string> &tosend)
2375 DSTACK(__FUNCTION_NAME);
2377 verbosestream<<"Server::sendRequestedMedia(): "
2378 <<"Sending files to client"<<std::endl;
2382 // Put 5kB in one bunch (this is not accurate)
2383 u32 bytes_per_bunch = 5000;
2385 std::vector< std::vector<SendableMedia> > file_bunches;
2386 file_bunches.push_back(std::vector<SendableMedia>());
2388 u32 file_size_bunch_total = 0;
2390 for(std::vector<std::string>::const_iterator i = tosend.begin();
2391 i != tosend.end(); ++i) {
2392 const std::string &name = *i;
2394 if(m_media.find(name) == m_media.end()) {
2395 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2396 <<"unknown file \""<<(name)<<"\""<<std::endl;
2400 //TODO get path + name
2401 std::string tpath = m_media[name].path;
2404 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2405 if(fis.good() == false){
2406 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2407 <<tpath<<"\" for reading"<<std::endl;
2410 std::ostringstream tmp_os(std::ios_base::binary);
2414 fis.read(buf, 1024);
2415 std::streamsize len = fis.gcount();
2416 tmp_os.write(buf, len);
2417 file_size_bunch_total += len;
2426 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2427 <<name<<"\""<<std::endl;
2430 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2431 <<tname<<"\""<<std::endl;*/
2433 file_bunches[file_bunches.size()-1].push_back(
2434 SendableMedia(name, tpath, tmp_os.str()));
2436 // Start next bunch if got enough data
2437 if(file_size_bunch_total >= bytes_per_bunch) {
2438 file_bunches.push_back(std::vector<SendableMedia>());
2439 file_size_bunch_total = 0;
2444 /* Create and send packets */
2446 u16 num_bunches = file_bunches.size();
2447 for(u16 i = 0; i < num_bunches; i++) {
2450 u16 total number of texture bunches
2451 u16 index of this bunch
2452 u32 number of files in this bunch
2461 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2462 pkt << num_bunches << i << (u32) file_bunches[i].size();
2464 for(std::vector<SendableMedia>::iterator
2465 j = file_bunches[i].begin();
2466 j != file_bunches[i].end(); ++j) {
2468 pkt.putLongString(j->data);
2471 verbosestream << "Server::sendRequestedMedia(): bunch "
2472 << i << "/" << num_bunches
2473 << " files=" << file_bunches[i].size()
2474 << " size=" << pkt.getSize() << std::endl;
2479 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2481 if(m_detached_inventories.count(name) == 0) {
2482 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2485 Inventory *inv = m_detached_inventories[name];
2486 std::ostringstream os(std::ios_base::binary);
2488 os << serializeString(name);
2492 std::string s = os.str();
2494 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2495 pkt.putRawString(s.c_str(), s.size());
2497 if (peer_id != PEER_ID_INEXISTENT) {
2501 m_clients.sendToAll(0, &pkt, true);
2505 void Server::sendDetachedInventories(u16 peer_id)
2507 DSTACK(__FUNCTION_NAME);
2509 for(std::map<std::string, Inventory*>::iterator
2510 i = m_detached_inventories.begin();
2511 i != m_detached_inventories.end(); i++) {
2512 const std::string &name = i->first;
2513 //Inventory *inv = i->second;
2514 sendDetachedInventory(name, peer_id);
2522 void Server::DiePlayer(u16 peer_id)
2524 DSTACK(__FUNCTION_NAME);
2526 PlayerSAO *playersao = getPlayerSAO(peer_id);
2529 infostream << "Server::DiePlayer(): Player "
2530 << playersao->getPlayer()->getName()
2531 << " dies" << std::endl;
2533 playersao->setHP(0);
2535 // Trigger scripted stuff
2536 m_script->on_dieplayer(playersao);
2538 SendPlayerHP(peer_id);
2539 SendDeathscreen(peer_id, false, v3f(0,0,0));
2542 void Server::RespawnPlayer(u16 peer_id)
2544 DSTACK(__FUNCTION_NAME);
2546 PlayerSAO *playersao = getPlayerSAO(peer_id);
2549 infostream << "Server::RespawnPlayer(): Player "
2550 << playersao->getPlayer()->getName()
2551 << " respawns" << std::endl;
2553 playersao->setHP(PLAYER_MAX_HP);
2554 playersao->setBreath(PLAYER_MAX_BREATH);
2556 SendPlayerHP(peer_id);
2557 SendPlayerBreath(peer_id);
2559 bool repositioned = m_script->on_respawnplayer(playersao);
2561 v3f pos = findSpawnPos();
2562 // setPos will send the new position to client
2563 playersao->setPos(pos);
2566 void Server::DenySudoAccess(u16 peer_id)
2568 DSTACK(__FUNCTION_NAME);
2570 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2574 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2576 DSTACK(__FUNCTION_NAME);
2578 SendAccessDenied(peer_id, reason, custom_reason);
2579 m_clients.event(peer_id, CSE_SetDenied);
2580 m_con.DisconnectPeer(peer_id);
2583 // 13/03/15: remove this function when protocol version 25 will become
2584 // the minimum version for MT users, maybe in 1 year
2585 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2587 DSTACK(__FUNCTION_NAME);
2589 SendAccessDenied_Legacy(peer_id, reason);
2590 m_clients.event(peer_id, CSE_SetDenied);
2591 m_con.DisconnectPeer(peer_id);
2594 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2596 DSTACK(__FUNCTION_NAME);
2599 RemoteClient* client = getClient(peer_id, CS_Invalid);
2601 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2603 // Right now, the auth mechs don't change between login and sudo mode.
2604 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2605 client->allowed_sudo_mechs = sudo_auth_mechs;
2607 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2608 << g_settings->getFloat("dedicated_server_step")
2612 m_clients.event(peer_id, CSE_AuthAccept);
2614 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2616 // We only support SRP right now
2617 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2619 resp_pkt << sudo_auth_mechs;
2621 m_clients.event(peer_id, CSE_SudoSuccess);
2625 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2627 DSTACK(__FUNCTION_NAME);
2628 std::wstring message;
2631 Clear references to playing sounds
2633 for(std::map<s32, ServerPlayingSound>::iterator
2634 i = m_playing_sounds.begin();
2635 i != m_playing_sounds.end();)
2637 ServerPlayingSound &psound = i->second;
2638 psound.clients.erase(peer_id);
2639 if(psound.clients.empty())
2640 m_playing_sounds.erase(i++);
2645 Player *player = m_env->getPlayer(peer_id);
2647 // Collect information about leaving in chat
2649 if(player != NULL && reason != CDR_DENY)
2651 std::wstring name = narrow_to_wide(player->getName());
2654 message += L" left the game.";
2655 if(reason == CDR_TIMEOUT)
2656 message += L" (timed out)";
2660 /* Run scripts and remove from environment */
2664 PlayerSAO *playersao = player->getPlayerSAO();
2667 m_script->on_leaveplayer(playersao);
2669 playersao->disconnected();
2677 if(player != NULL && reason != CDR_DENY) {
2678 std::ostringstream os(std::ios_base::binary);
2679 std::vector<u16> clients = m_clients.getClientIDs();
2681 for(std::vector<u16>::iterator i = clients.begin();
2682 i != clients.end(); ++i) {
2684 Player *player = m_env->getPlayer(*i);
2688 // Get name of player
2689 os << player->getName() << " ";
2692 actionstream << player->getName() << " "
2693 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2694 << " List of players: " << os.str() << std::endl;
2698 JMutexAutoLock env_lock(m_env_mutex);
2699 m_clients.DeleteClient(peer_id);
2703 // Send leave chat message to all remaining clients
2704 if(message.length() != 0)
2705 SendChatMessage(PEER_ID_INEXISTENT,message);
2708 void Server::UpdateCrafting(Player* player)
2710 DSTACK(__FUNCTION_NAME);
2712 // Get a preview for crafting
2714 InventoryLocation loc;
2715 loc.setPlayer(player->getName());
2716 std::vector<ItemStack> output_replacements;
2717 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2718 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2720 // Put the new preview in
2721 InventoryList *plist = player->inventory.getList("craftpreview");
2722 sanity_check(plist);
2723 sanity_check(plist->getSize() >= 1);
2724 plist->changeItem(0, preview);
2727 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2729 RemoteClient *client = getClientNoEx(peer_id,state_min);
2731 throw ClientNotFoundException("Client not found");
2735 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2737 return m_clients.getClientNoEx(peer_id, state_min);
2740 std::string Server::getPlayerName(u16 peer_id)
2742 Player *player = m_env->getPlayer(peer_id);
2744 return "[id="+itos(peer_id)+"]";
2745 return player->getName();
2748 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2750 Player *player = m_env->getPlayer(peer_id);
2753 return player->getPlayerSAO();
2756 std::wstring Server::getStatusString()
2758 std::wostringstream os(std::ios_base::binary);
2761 os<<L"version="<<narrow_to_wide(g_version_string);
2763 os<<L", uptime="<<m_uptime.get();
2765 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2766 // Information about clients
2769 std::vector<u16> clients = m_clients.getClientIDs();
2770 for(std::vector<u16>::iterator i = clients.begin();
2771 i != clients.end(); ++i) {
2773 Player *player = m_env->getPlayer(*i);
2774 // Get name of player
2775 std::wstring name = L"unknown";
2777 name = narrow_to_wide(player->getName());
2778 // Add name to information string
2786 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2787 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2788 if(g_settings->get("motd") != "")
2789 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2793 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2795 std::set<std::string> privs;
2796 m_script->getAuth(name, NULL, &privs);
2800 bool Server::checkPriv(const std::string &name, const std::string &priv)
2802 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2803 return (privs.count(priv) != 0);
2806 void Server::reportPrivsModified(const std::string &name)
2809 std::vector<u16> clients = m_clients.getClientIDs();
2810 for(std::vector<u16>::iterator i = clients.begin();
2811 i != clients.end(); ++i) {
2812 Player *player = m_env->getPlayer(*i);
2813 reportPrivsModified(player->getName());
2816 Player *player = m_env->getPlayer(name.c_str());
2819 SendPlayerPrivileges(player->peer_id);
2820 PlayerSAO *sao = player->getPlayerSAO();
2823 sao->updatePrivileges(
2824 getPlayerEffectivePrivs(name),
2829 void Server::reportInventoryFormspecModified(const std::string &name)
2831 Player *player = m_env->getPlayer(name.c_str());
2834 SendPlayerInventoryFormspec(player->peer_id);
2837 void Server::setIpBanned(const std::string &ip, const std::string &name)
2839 m_banmanager->add(ip, name);
2842 void Server::unsetIpBanned(const std::string &ip_or_name)
2844 m_banmanager->remove(ip_or_name);
2847 std::string Server::getBanDescription(const std::string &ip_or_name)
2849 return m_banmanager->getBanDescription(ip_or_name);
2852 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2854 Player *player = m_env->getPlayer(name);
2858 if (player->peer_id == PEER_ID_INEXISTENT)
2861 SendChatMessage(player->peer_id, msg);
2864 bool Server::showFormspec(const char *playername, const std::string &formspec,
2865 const std::string &formname)
2867 Player *player = m_env->getPlayer(playername);
2871 SendShowFormspecMessage(player->peer_id, formspec, formname);
2875 u32 Server::hudAdd(Player *player, HudElement *form)
2880 u32 id = player->addHud(form);
2882 SendHUDAdd(player->peer_id, id, form);
2887 bool Server::hudRemove(Player *player, u32 id) {
2891 HudElement* todel = player->removeHud(id);
2898 SendHUDRemove(player->peer_id, id);
2902 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2907 SendHUDChange(player->peer_id, id, stat, data);
2911 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2916 SendHUDSetFlags(player->peer_id, flags, mask);
2917 player->hud_flags = flags;
2919 PlayerSAO* playersao = player->getPlayerSAO();
2921 if (playersao == NULL)
2924 m_script->player_event(playersao, "hud_changed");
2928 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2932 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2935 player->setHotbarItemcount(hotbar_itemcount);
2936 std::ostringstream os(std::ios::binary);
2937 writeS32(os, hotbar_itemcount);
2938 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2942 s32 Server::hudGetHotbarItemcount(Player *player)
2946 return player->getHotbarItemcount();
2949 void Server::hudSetHotbarImage(Player *player, std::string name)
2954 player->setHotbarImage(name);
2955 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2958 std::string Server::hudGetHotbarImage(Player *player)
2962 return player->getHotbarImage();
2965 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2970 player->setHotbarSelectedImage(name);
2971 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2974 std::string Server::hudGetHotbarSelectedImage(Player *player)
2979 return player->getHotbarSelectedImage();
2982 bool Server::setLocalPlayerAnimations(Player *player,
2983 v2s32 animation_frames[4], f32 frame_speed)
2988 player->setLocalAnimations(animation_frames, frame_speed);
2989 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2993 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2998 player->eye_offset_first = first;
2999 player->eye_offset_third = third;
3000 SendEyeOffset(player->peer_id, first, third);
3004 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3005 const std::string &type, const std::vector<std::string> ¶ms)
3010 player->setSky(bgcolor, type, params);
3011 SendSetSky(player->peer_id, bgcolor, type, params);
3015 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3021 player->overrideDayNightRatio(do_override, ratio);
3022 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3026 void Server::notifyPlayers(const std::wstring &msg)
3028 SendChatMessage(PEER_ID_INEXISTENT,msg);
3031 void Server::spawnParticle(const char *playername, v3f pos,
3032 v3f velocity, v3f acceleration,
3033 float expirationtime, float size, bool
3034 collisiondetection, bool vertical, const std::string &texture)
3036 Player *player = m_env->getPlayer(playername);
3039 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3040 expirationtime, size, collisiondetection, vertical, texture);
3043 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3044 float expirationtime, float size,
3045 bool collisiondetection, bool vertical, const std::string &texture)
3047 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3048 expirationtime, size, collisiondetection, vertical, texture);
3051 u32 Server::addParticleSpawner(const char *playername, u16 amount, float spawntime,
3052 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3053 float minexptime, float maxexptime, float minsize, float maxsize,
3054 bool collisiondetection, bool vertical, const std::string &texture)
3056 Player *player = m_env->getPlayer(playername);
3061 for(;;) // look for unused particlespawner id
3064 if (std::find(m_particlespawner_ids.begin(),
3065 m_particlespawner_ids.end(), id)
3066 == m_particlespawner_ids.end())
3068 m_particlespawner_ids.push_back(id);
3073 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3074 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3075 minexptime, maxexptime, minsize, maxsize,
3076 collisiondetection, vertical, texture, id);
3081 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3082 v3f minpos, v3f maxpos,
3083 v3f minvel, v3f maxvel,
3084 v3f minacc, v3f maxacc,
3085 float minexptime, float maxexptime,
3086 float minsize, float maxsize,
3087 bool collisiondetection, bool vertical, const std::string &texture)
3090 for(;;) // look for unused particlespawner id
3093 if (std::find(m_particlespawner_ids.begin(),
3094 m_particlespawner_ids.end(), id)
3095 == m_particlespawner_ids.end())
3097 m_particlespawner_ids.push_back(id);
3102 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3103 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3104 minexptime, maxexptime, minsize, maxsize,
3105 collisiondetection, vertical, texture, id);
3110 void Server::deleteParticleSpawner(const char *playername, u32 id)
3112 Player *player = m_env->getPlayer(playername);
3116 m_particlespawner_ids.erase(
3117 std::remove(m_particlespawner_ids.begin(),
3118 m_particlespawner_ids.end(), id),
3119 m_particlespawner_ids.end());
3120 SendDeleteParticleSpawner(player->peer_id, id);
3123 void Server::deleteParticleSpawnerAll(u32 id)
3125 m_particlespawner_ids.erase(
3126 std::remove(m_particlespawner_ids.begin(),
3127 m_particlespawner_ids.end(), id),
3128 m_particlespawner_ids.end());
3129 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3132 Inventory* Server::createDetachedInventory(const std::string &name)
3134 if(m_detached_inventories.count(name) > 0){
3135 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3136 delete m_detached_inventories[name];
3138 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3140 Inventory *inv = new Inventory(m_itemdef);
3142 m_detached_inventories[name] = inv;
3143 //TODO find a better way to do this
3144 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3148 // actions: time-reversed list
3149 // Return value: success/failure
3150 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3151 std::list<std::string> *log)
3153 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3154 ServerMap *map = (ServerMap*)(&m_env->getMap());
3156 // Fail if no actions to handle
3157 if(actions.empty()){
3158 log->push_back("Nothing to do.");
3165 for(std::list<RollbackAction>::const_iterator
3166 i = actions.begin();
3167 i != actions.end(); i++)
3169 const RollbackAction &action = *i;
3171 bool success = action.applyRevert(map, this, this);
3174 std::ostringstream os;
3175 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3176 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3178 log->push_back(os.str());
3180 std::ostringstream os;
3181 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3182 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3184 log->push_back(os.str());
3188 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3189 <<" failed"<<std::endl;
3191 // Call it done if less than half failed
3192 return num_failed <= num_tried/2;
3195 // IGameDef interface
3197 IItemDefManager *Server::getItemDefManager()
3202 INodeDefManager *Server::getNodeDefManager()
3207 ICraftDefManager *Server::getCraftDefManager()
3211 ITextureSource *Server::getTextureSource()
3215 IShaderSource *Server::getShaderSource()
3219 scene::ISceneManager *Server::getSceneManager()
3224 u16 Server::allocateUnknownNodeId(const std::string &name)
3226 return m_nodedef->allocateDummy(name);
3229 ISoundManager *Server::getSoundManager()
3231 return &dummySoundManager;
3234 MtEventManager *Server::getEventManager()
3239 IWritableItemDefManager *Server::getWritableItemDefManager()
3244 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3249 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3254 const ModSpec *Server::getModSpec(const std::string &modname) const
3256 std::vector<ModSpec>::const_iterator it;
3257 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3258 const ModSpec &mod = *it;
3259 if (mod.name == modname)
3265 void Server::getModNames(std::vector<std::string> &modlist)
3267 std::vector<ModSpec>::iterator it;
3268 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3269 modlist.push_back(it->name);
3272 std::string Server::getBuiltinLuaPath()
3274 return porting::path_share + DIR_DELIM + "builtin";
3277 v3f Server::findSpawnPos()
3279 ServerMap &map = m_env->getServerMap();
3281 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3282 return nodeposf * BS;
3285 // Default position is static_spawnpoint
3286 // We will return it if we don't found a good place
3287 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3289 s16 water_level = map.getWaterLevel();
3291 bool is_good = false;
3293 // Try to find a good place a few times
3294 for(s32 i = 0; i < 1000 && !is_good; i++) {
3296 // We're going to try to throw the player to this position
3297 v2s16 nodepos2d = v2s16(
3298 -range + (myrand() % (range * 2)),
3299 -range + (myrand() % (range * 2)));
3301 // Get ground height at point
3302 s16 groundheight = map.findGroundLevel(nodepos2d);
3303 if (groundheight <= water_level) // Don't go underwater
3305 if (groundheight > water_level + 6) // Don't go to high places
3308 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3311 for (s32 i = 0; i < 10; i++) {
3312 v3s16 blockpos = getNodeBlockPos(nodepos);
3313 map.emergeBlock(blockpos, true);
3314 content_t c = map.getNodeNoEx(nodepos).getContent();
3315 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3317 if (air_count >= 2){
3326 return intToFloat(nodepos, BS);
3329 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3331 bool newplayer = false;
3334 Try to get an existing player
3336 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3338 // If player is already connected, cancel
3339 if(player != NULL && player->peer_id != 0)
3341 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3346 If player with the wanted peer_id already exists, cancel.
3348 if(m_env->getPlayer(peer_id) != NULL)
3350 infostream<<"emergePlayer(): Player with wrong name but same"
3351 " peer_id already exists"<<std::endl;
3355 // Load player if it isn't already loaded
3357 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3360 // Create player if it doesn't exist
3363 player = new RemotePlayer(this, name);
3364 // Set player position
3365 infostream<<"Server: Finding spawn place for player \""
3366 <<name<<"\""<<std::endl;
3367 v3f pos = findSpawnPos();
3368 player->setPosition(pos);
3370 // Make sure the player is saved
3371 player->setModified(true);
3373 // Add player to environment
3374 m_env->addPlayer(player);
3377 // Create a new player active object
3378 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3379 getPlayerEffectivePrivs(player->getName()),
3382 /* Clean up old HUD elements from previous sessions */
3385 /* Add object to environment */
3386 m_env->addActiveObject(playersao);
3390 m_script->on_newplayer(playersao);
3396 void dedicated_server_loop(Server &server, bool &kill)
3398 DSTACK(__FUNCTION_NAME);
3400 verbosestream<<"dedicated_server_loop()"<<std::endl;
3402 IntervalLimiter m_profiler_interval;
3406 float steplen = g_settings->getFloat("dedicated_server_step");
3407 // This is kind of a hack but can be done like this
3408 // because server.step() is very light
3410 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3411 sleep_ms((int)(steplen*1000.0));
3413 server.step(steplen);
3415 if(server.getShutdownRequested() || kill)
3417 infostream<<"Dedicated server quitting"<<std::endl;
3419 if(g_settings->getBool("server_announce"))
3420 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3428 float profiler_print_interval =
3429 g_settings->getFloat("profiler_print_interval");
3430 if(profiler_print_interval != 0)
3432 if(m_profiler_interval.step(steplen, profiler_print_interval))
3434 infostream<<"Profiler:"<<std::endl;
3435 g_profiler->print(infostream);
3436 g_profiler->clear();