3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
60 #include "util/thread.h"
61 #include "defaultsettings.h"
62 #include "util/base64.h"
63 #include "util/sha1.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public JThread
80 ServerThread(Server *server):
89 void * ServerThread::Thread()
91 log_register_thread("ServerThread");
93 DSTACK(__FUNCTION_NAME);
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
100 porting::setThreadName("ServerThread");
102 while(!StopRequested())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
107 m_server->AsyncRunStep();
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
165 const std::string &path_world,
166 const SubgameSpec &gamespec,
167 bool simple_singleplayer_mode,
170 m_path_world(path_world),
171 m_gamespec(gamespec),
172 m_simple_singleplayer_mode(simple_singleplayer_mode),
173 m_async_fatal_error(""),
182 m_enable_rollback_recording(false),
185 m_itemdef(createItemDefManager()),
186 m_nodedef(createNodeDefManager()),
187 m_craftdef(createCraftDefManager()),
188 m_event(new EventManager()),
190 m_time_of_day_send_timer(0),
193 m_shutdown_requested(false),
194 m_ignore_map_edit_events(false),
195 m_ignore_map_edit_events_peer_id(0),
199 m_liquid_transform_timer = 0.0;
200 m_liquid_transform_every = 1.0;
201 m_print_info_timer = 0.0;
202 m_masterserver_timer = 0.0;
203 m_objectdata_timer = 0.0;
204 m_emergethread_trigger_timer = 0.0;
205 m_savemap_timer = 0.0;
208 m_lag = g_settings->getFloat("dedicated_server_step");
211 throw ServerError("Supplied empty world path");
213 if(!gamespec.isValid())
214 throw ServerError("Supplied invalid gamespec");
216 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
217 if(m_simple_singleplayer_mode)
218 infostream<<" in simple singleplayer mode"<<std::endl;
220 infostream<<std::endl;
221 infostream<<"- world: "<<m_path_world<<std::endl;
222 infostream<<"- game: "<<m_gamespec.path<<std::endl;
224 // Create world if it doesn't exist
225 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
226 throw ServerError("Failed to initialize world");
228 // Create server thread
229 m_thread = new ServerThread(this);
231 // Create emerge manager
232 m_emerge = new EmergeManager(this);
234 // Create ban manager
235 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
236 m_banmanager = new BanManager(ban_path);
238 ModConfiguration modconf(m_path_world);
239 m_mods = modconf.getMods();
240 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
241 // complain about mods with unsatisfied dependencies
242 if(!modconf.isConsistent())
244 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
245 it != unsatisfied_mods.end(); ++it)
248 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
249 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
250 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
251 errorstream << " \"" << *dep_it << "\"";
252 errorstream << std::endl;
256 Settings worldmt_settings;
257 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
258 worldmt_settings.readConfigFile(worldmt.c_str());
259 std::vector<std::string> names = worldmt_settings.getNames();
260 std::set<std::string> load_mod_names;
261 for(std::vector<std::string>::iterator it = names.begin();
262 it != names.end(); ++it)
264 std::string name = *it;
265 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
266 load_mod_names.insert(name.substr(9));
268 // complain about mods declared to be loaded, but not found
269 for(std::vector<ModSpec>::iterator it = m_mods.begin();
270 it != m_mods.end(); ++it)
271 load_mod_names.erase((*it).name);
272 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
273 it != unsatisfied_mods.end(); ++it)
274 load_mod_names.erase((*it).name);
275 if(!load_mod_names.empty())
277 errorstream << "The following mods could not be found:";
278 for(std::set<std::string>::iterator it = load_mod_names.begin();
279 it != load_mod_names.end(); ++it)
280 errorstream << " \"" << (*it) << "\"";
281 errorstream << std::endl;
285 JMutexAutoLock envlock(m_env_mutex);
287 // Load mapgen params from Settings
288 m_emerge->loadMapgenParams();
290 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
291 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
293 // Initialize scripting
294 infostream<<"Server: Initializing Lua"<<std::endl;
296 m_script = new GameScripting(this);
298 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
300 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME)) {
301 throw ModError("Failed to load and run " + script_path);
305 infostream << "Server: Loading mods: ";
306 for(std::vector<ModSpec>::iterator i = m_mods.begin();
307 i != m_mods.end(); i++){
308 const ModSpec &mod = *i;
309 infostream << mod.name << " ";
311 infostream << std::endl;
312 // Load and run "mod" scripts
313 for (std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++) {
315 const ModSpec &mod = *i;
316 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
317 errorstream << "Error loading mod \"" << mod.name
318 << "\": mod_name does not follow naming conventions: "
319 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
320 throw ModError("Mod \"" + mod.name + "\" does not follow naming conventions.");
322 std::string script_path = mod.path + DIR_DELIM "init.lua";
323 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
324 << script_path << "\"]" << std::endl;
325 if (!m_script->loadMod(script_path, mod.name)) {
326 errorstream << "Server: Failed to load and run "
327 << script_path << std::endl;
328 throw ModError("Failed to load and run " + script_path);
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(peer_id, playersao->getHP() == 0);
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 + narrow_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;
1211 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1216 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1218 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1219 errorstream << "Server::ProcessData(): Cancelling: Peer"
1220 " serialization format invalid or not initialized."
1221 " Skipping incoming command=" << command << std::endl;
1225 /* Handle commands related to client startup */
1226 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1231 if (m_clients.getClientState(peer_id) < CS_Active) {
1232 if (command == TOSERVER_PLAYERPOS) return;
1234 errorstream << "Got packet command: " << command << " for peer id "
1235 << peer_id << " but client isn't active yet. Dropping packet "
1241 } catch (SendFailedException &e) {
1242 errorstream << "Server::ProcessData(): SendFailedException: "
1243 << "what=" << e.what()
1245 } catch (PacketError &e) {
1246 actionstream << "Server::ProcessData(): PacketError: "
1247 << "what=" << e.what()
1252 void Server::setTimeOfDay(u32 time)
1254 m_env->setTimeOfDay(time);
1255 m_time_of_day_send_timer = 0;
1258 void Server::onMapEditEvent(MapEditEvent *event)
1260 if(m_ignore_map_edit_events)
1262 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1264 MapEditEvent *e = event->clone();
1265 m_unsent_map_edit_queue.push(e);
1268 Inventory* Server::getInventory(const InventoryLocation &loc)
1271 case InventoryLocation::UNDEFINED:
1272 case InventoryLocation::CURRENT_PLAYER:
1274 case InventoryLocation::PLAYER:
1276 Player *player = m_env->getPlayer(loc.name.c_str());
1279 PlayerSAO *playersao = player->getPlayerSAO();
1282 return playersao->getInventory();
1285 case InventoryLocation::NODEMETA:
1287 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1290 return meta->getInventory();
1293 case InventoryLocation::DETACHED:
1295 if(m_detached_inventories.count(loc.name) == 0)
1297 return m_detached_inventories[loc.name];
1301 sanity_check(false); // abort
1306 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1309 case InventoryLocation::UNDEFINED:
1311 case InventoryLocation::PLAYER:
1316 Player *player = m_env->getPlayer(loc.name.c_str());
1319 PlayerSAO *playersao = player->getPlayerSAO();
1323 SendInventory(playersao);
1326 case InventoryLocation::NODEMETA:
1328 v3s16 blockpos = getNodeBlockPos(loc.p);
1330 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1332 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1334 setBlockNotSent(blockpos);
1337 case InventoryLocation::DETACHED:
1339 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1343 sanity_check(false); // abort
1348 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1350 std::vector<u16> clients = m_clients.getClientIDs();
1352 // Set the modified blocks unsent for all the clients
1353 for (std::vector<u16>::iterator i = clients.begin();
1354 i != clients.end(); ++i) {
1355 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1356 client->SetBlocksNotSent(block);
1361 void Server::peerAdded(con::Peer *peer)
1363 DSTACK(__FUNCTION_NAME);
1364 verbosestream<<"Server::peerAdded(): peer->id="
1365 <<peer->id<<std::endl;
1368 c.type = con::PEER_ADDED;
1369 c.peer_id = peer->id;
1371 m_peer_change_queue.push(c);
1374 void Server::deletingPeer(con::Peer *peer, bool timeout)
1376 DSTACK(__FUNCTION_NAME);
1377 verbosestream<<"Server::deletingPeer(): peer->id="
1378 <<peer->id<<", timeout="<<timeout<<std::endl;
1380 m_clients.event(peer->id, CSE_Disconnect);
1382 c.type = con::PEER_REMOVED;
1383 c.peer_id = peer->id;
1384 c.timeout = timeout;
1385 m_peer_change_queue.push(c);
1388 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1390 *retval = m_con.getPeerStat(peer_id,type);
1391 if (*retval == -1) return false;
1395 bool Server::getClientInfo(
1404 std::string* vers_string
1407 *state = m_clients.getClientState(peer_id);
1409 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1411 if (client == NULL) {
1416 *uptime = client->uptime();
1417 *ser_vers = client->serialization_version;
1418 *prot_vers = client->net_proto_version;
1420 *major = client->getMajor();
1421 *minor = client->getMinor();
1422 *patch = client->getPatch();
1423 *vers_string = client->getPatch();
1430 void Server::handlePeerChanges()
1432 while(m_peer_change_queue.size() > 0)
1434 con::PeerChange c = m_peer_change_queue.front();
1435 m_peer_change_queue.pop();
1437 verbosestream<<"Server: Handling peer change: "
1438 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1443 case con::PEER_ADDED:
1444 m_clients.CreateClient(c.peer_id);
1447 case con::PEER_REMOVED:
1448 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1452 FATAL_ERROR("Invalid peer change event received!");
1458 void Server::Send(NetworkPacket* pkt)
1460 m_clients.send(pkt->getPeerId(),
1461 clientCommandFactoryTable[pkt->getCommand()].channel,
1463 clientCommandFactoryTable[pkt->getCommand()].reliable);
1466 void Server::SendMovement(u16 peer_id)
1468 DSTACK(__FUNCTION_NAME);
1469 std::ostringstream os(std::ios_base::binary);
1471 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1473 pkt << g_settings->getFloat("movement_acceleration_default");
1474 pkt << g_settings->getFloat("movement_acceleration_air");
1475 pkt << g_settings->getFloat("movement_acceleration_fast");
1476 pkt << g_settings->getFloat("movement_speed_walk");
1477 pkt << g_settings->getFloat("movement_speed_crouch");
1478 pkt << g_settings->getFloat("movement_speed_fast");
1479 pkt << g_settings->getFloat("movement_speed_climb");
1480 pkt << g_settings->getFloat("movement_speed_jump");
1481 pkt << g_settings->getFloat("movement_liquid_fluidity");
1482 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1483 pkt << g_settings->getFloat("movement_liquid_sink");
1484 pkt << g_settings->getFloat("movement_gravity");
1489 void Server::SendHP(u16 peer_id, u8 hp)
1491 DSTACK(__FUNCTION_NAME);
1493 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1498 void Server::SendBreath(u16 peer_id, u16 breath)
1500 DSTACK(__FUNCTION_NAME);
1502 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1503 pkt << (u16) breath;
1507 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1509 DSTACK(__FUNCTION_NAME);
1511 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1514 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1515 pkt << custom_reason;
1520 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1522 DSTACK(__FUNCTION_NAME);
1524 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1529 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1530 v3f camera_point_target)
1532 DSTACK(__FUNCTION_NAME);
1534 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1535 pkt << set_camera_point_target << camera_point_target;
1539 void Server::SendItemDef(u16 peer_id,
1540 IItemDefManager *itemdef, u16 protocol_version)
1542 DSTACK(__FUNCTION_NAME);
1544 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1548 u32 length of the next item
1549 zlib-compressed serialized ItemDefManager
1551 std::ostringstream tmp_os(std::ios::binary);
1552 itemdef->serialize(tmp_os, protocol_version);
1553 std::ostringstream tmp_os2(std::ios::binary);
1554 compressZlib(tmp_os.str(), tmp_os2);
1555 pkt.putLongString(tmp_os2.str());
1558 verbosestream << "Server: Sending item definitions to id(" << peer_id
1559 << "): size=" << pkt.getSize() << std::endl;
1564 void Server::SendNodeDef(u16 peer_id,
1565 INodeDefManager *nodedef, u16 protocol_version)
1567 DSTACK(__FUNCTION_NAME);
1569 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1573 u32 length of the next item
1574 zlib-compressed serialized NodeDefManager
1576 std::ostringstream tmp_os(std::ios::binary);
1577 nodedef->serialize(tmp_os, protocol_version);
1578 std::ostringstream tmp_os2(std::ios::binary);
1579 compressZlib(tmp_os.str(), tmp_os2);
1581 pkt.putLongString(tmp_os2.str());
1584 verbosestream << "Server: Sending node definitions to id(" << peer_id
1585 << "): size=" << pkt.getSize() << std::endl;
1591 Non-static send methods
1594 void Server::SendInventory(PlayerSAO* playerSAO)
1596 DSTACK(__FUNCTION_NAME);
1598 UpdateCrafting(playerSAO->getPlayer());
1604 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1606 std::ostringstream os;
1607 playerSAO->getInventory()->serialize(os);
1609 std::string s = os.str();
1611 pkt.putRawString(s.c_str(), s.size());
1615 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1617 DSTACK(__FUNCTION_NAME);
1619 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1622 if (peer_id != PEER_ID_INEXISTENT) {
1626 m_clients.sendToAll(0, &pkt, true);
1630 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1631 const std::string &formname)
1633 DSTACK(__FUNCTION_NAME);
1635 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1637 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1643 // Spawns a particle on peer with peer_id
1644 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1645 float expirationtime, float size, bool collisiondetection,
1646 bool vertical, std::string texture)
1648 DSTACK(__FUNCTION_NAME);
1650 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1652 pkt << pos << velocity << acceleration << expirationtime
1653 << size << collisiondetection;
1654 pkt.putLongString(texture);
1657 if (peer_id != PEER_ID_INEXISTENT) {
1661 m_clients.sendToAll(0, &pkt, true);
1665 // Adds a ParticleSpawner on peer with peer_id
1666 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1667 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1668 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1670 DSTACK(__FUNCTION_NAME);
1672 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1674 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1675 << minacc << maxacc << minexptime << maxexptime << minsize
1676 << maxsize << collisiondetection;
1678 pkt.putLongString(texture);
1680 pkt << id << vertical;
1682 if (peer_id != PEER_ID_INEXISTENT) {
1686 m_clients.sendToAll(0, &pkt, true);
1690 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1692 DSTACK(__FUNCTION_NAME);
1694 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1696 // Ugly error in this packet
1699 if (peer_id != PEER_ID_INEXISTENT) {
1703 m_clients.sendToAll(0, &pkt, true);
1708 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1710 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1712 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1713 << form->text << form->number << form->item << form->dir
1714 << form->align << form->offset << form->world_pos << form->size;
1719 void Server::SendHUDRemove(u16 peer_id, u32 id)
1721 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1726 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1728 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1729 pkt << id << (u8) stat;
1733 case HUD_STAT_SCALE:
1734 case HUD_STAT_ALIGN:
1735 case HUD_STAT_OFFSET:
1736 pkt << *(v2f *) value;
1740 pkt << *(std::string *) value;
1742 case HUD_STAT_WORLD_POS:
1743 pkt << *(v3f *) value;
1746 pkt << *(v2s32 *) value;
1748 case HUD_STAT_NUMBER:
1752 pkt << *(u32 *) value;
1759 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1761 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1763 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1765 pkt << flags << mask;
1770 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1772 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1773 pkt << param << value;
1777 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1778 const std::string &type, const std::vector<std::string> ¶ms)
1780 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1781 pkt << bgcolor << type << (u16) params.size();
1783 for(size_t i=0; i<params.size(); i++)
1789 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1792 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1795 pkt << do_override << (u16) (ratio * 65535);
1800 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1802 DSTACK(__FUNCTION_NAME);
1804 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1805 pkt << time << time_speed;
1807 if (peer_id == PEER_ID_INEXISTENT) {
1808 m_clients.sendToAll(0, &pkt, true);
1815 void Server::SendPlayerHP(u16 peer_id)
1817 DSTACK(__FUNCTION_NAME);
1818 PlayerSAO *playersao = getPlayerSAO(peer_id);
1819 // In some rare case, if the player is disconnected
1820 // while Lua call l_punch, for example, this can be NULL
1824 SendHP(peer_id, playersao->getHP());
1825 m_script->player_event(playersao,"health_changed");
1827 // Send to other clients
1828 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1829 ActiveObjectMessage aom(playersao->getId(), true, str);
1830 playersao->m_messages_out.push(aom);
1833 void Server::SendPlayerBreath(u16 peer_id)
1835 DSTACK(__FUNCTION_NAME);
1836 PlayerSAO *playersao = getPlayerSAO(peer_id);
1839 m_script->player_event(playersao, "breath_changed");
1840 SendBreath(peer_id, playersao->getBreath());
1843 void Server::SendMovePlayer(u16 peer_id)
1845 DSTACK(__FUNCTION_NAME);
1846 Player *player = m_env->getPlayer(peer_id);
1849 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1850 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1853 v3f pos = player->getPosition();
1854 f32 pitch = player->getPitch();
1855 f32 yaw = player->getYaw();
1856 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1857 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1858 << " pitch=" << pitch
1866 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1868 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1871 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1872 << animation_frames[3] << animation_speed;
1877 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1879 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1880 pkt << first << third;
1883 void Server::SendPlayerPrivileges(u16 peer_id)
1885 Player *player = m_env->getPlayer(peer_id);
1887 if(player->peer_id == PEER_ID_INEXISTENT)
1890 std::set<std::string> privs;
1891 m_script->getAuth(player->getName(), NULL, &privs);
1893 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1894 pkt << (u16) privs.size();
1896 for(std::set<std::string>::const_iterator i = privs.begin();
1897 i != privs.end(); i++) {
1904 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1906 Player *player = m_env->getPlayer(peer_id);
1908 if(player->peer_id == PEER_ID_INEXISTENT)
1911 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1912 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1916 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1918 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1919 pkt.putRawString(datas.c_str(), datas.size());
1921 return pkt.getSize();
1924 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1926 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1927 datas.size(), peer_id);
1929 pkt.putRawString(datas.c_str(), datas.size());
1931 m_clients.send(pkt.getPeerId(),
1932 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1937 s32 Server::playSound(const SimpleSoundSpec &spec,
1938 const ServerSoundParams ¶ms)
1940 // Find out initial position of sound
1941 bool pos_exists = false;
1942 v3f pos = params.getPos(m_env, &pos_exists);
1943 // If position is not found while it should be, cancel sound
1944 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1947 // Filter destination clients
1948 std::vector<u16> dst_clients;
1949 if(params.to_player != "")
1951 Player *player = m_env->getPlayer(params.to_player.c_str());
1953 infostream<<"Server::playSound: Player \""<<params.to_player
1954 <<"\" not found"<<std::endl;
1957 if(player->peer_id == PEER_ID_INEXISTENT){
1958 infostream<<"Server::playSound: Player \""<<params.to_player
1959 <<"\" not connected"<<std::endl;
1962 dst_clients.push_back(player->peer_id);
1965 std::vector<u16> clients = m_clients.getClientIDs();
1967 for(std::vector<u16>::iterator
1968 i = clients.begin(); i != clients.end(); ++i) {
1969 Player *player = m_env->getPlayer(*i);
1974 if(player->getPosition().getDistanceFrom(pos) >
1975 params.max_hear_distance)
1978 dst_clients.push_back(*i);
1982 if(dst_clients.empty())
1986 s32 id = m_next_sound_id++;
1987 // The sound will exist as a reference in m_playing_sounds
1988 m_playing_sounds[id] = ServerPlayingSound();
1989 ServerPlayingSound &psound = m_playing_sounds[id];
1990 psound.params = params;
1992 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1993 pkt << id << spec.name << (float) (spec.gain * params.gain)
1994 << (u8) params.type << pos << params.object << params.loop;
1996 for(std::vector<u16>::iterator i = dst_clients.begin();
1997 i != dst_clients.end(); i++) {
1998 psound.clients.insert(*i);
1999 m_clients.send(*i, 0, &pkt, true);
2003 void Server::stopSound(s32 handle)
2005 // Get sound reference
2006 std::map<s32, ServerPlayingSound>::iterator i =
2007 m_playing_sounds.find(handle);
2008 if(i == m_playing_sounds.end())
2010 ServerPlayingSound &psound = i->second;
2012 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2015 for(std::set<u16>::iterator i = psound.clients.begin();
2016 i != psound.clients.end(); i++) {
2018 m_clients.send(*i, 0, &pkt, true);
2020 // Remove sound reference
2021 m_playing_sounds.erase(i);
2024 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2025 std::vector<u16> *far_players, float far_d_nodes)
2027 float maxd = far_d_nodes*BS;
2028 v3f p_f = intToFloat(p, BS);
2030 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2033 std::vector<u16> clients = m_clients.getClientIDs();
2034 for(std::vector<u16>::iterator i = clients.begin();
2035 i != clients.end(); ++i) {
2038 if(Player *player = m_env->getPlayer(*i)) {
2039 // If player is far away, only set modified blocks not sent
2040 v3f player_pos = player->getPosition();
2041 if(player_pos.getDistanceFrom(p_f) > maxd) {
2042 far_players->push_back(*i);
2049 m_clients.send(*i, 0, &pkt, true);
2053 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2054 std::vector<u16> *far_players, float far_d_nodes,
2055 bool remove_metadata)
2057 float maxd = far_d_nodes*BS;
2058 v3f p_f = intToFloat(p, BS);
2060 std::vector<u16> clients = m_clients.getClientIDs();
2061 for(std::vector<u16>::iterator i = clients.begin();
2062 i != clients.end(); ++i) {
2066 if(Player *player = m_env->getPlayer(*i)) {
2067 // If player is far away, only set modified blocks not sent
2068 v3f player_pos = player->getPosition();
2069 if(player_pos.getDistanceFrom(p_f) > maxd) {
2070 far_players->push_back(*i);
2076 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2078 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2080 pkt << p << n.param0 << n.param1 << n.param2
2081 << (u8) (remove_metadata ? 0 : 1);
2083 if (!remove_metadata) {
2084 if (client->net_proto_version <= 21) {
2085 // Old clients always clear metadata; fix it
2086 // by sending the full block again.
2087 client->SetBlockNotSent(p);
2094 if (pkt.getSize() > 0)
2095 m_clients.send(*i, 0, &pkt, true);
2099 void Server::setBlockNotSent(v3s16 p)
2101 std::vector<u16> clients = m_clients.getClientIDs();
2103 for(std::vector<u16>::iterator i = clients.begin();
2104 i != clients.end(); ++i) {
2105 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2106 client->SetBlockNotSent(p);
2111 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2113 DSTACK(__FUNCTION_NAME);
2115 v3s16 p = block->getPos();
2118 Create a packet with the block in the right format
2121 std::ostringstream os(std::ios_base::binary);
2122 block->serialize(os, ver, false);
2123 block->serializeNetworkSpecific(os, net_proto_version);
2124 std::string s = os.str();
2126 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2129 pkt.putRawString(s.c_str(), s.size());
2133 void Server::SendBlocks(float dtime)
2135 DSTACK(__FUNCTION_NAME);
2137 JMutexAutoLock envlock(m_env_mutex);
2138 //TODO check if one big lock could be faster then multiple small ones
2140 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2142 std::vector<PrioritySortedBlockTransfer> queue;
2144 s32 total_sending = 0;
2147 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2149 std::vector<u16> clients = m_clients.getClientIDs();
2152 for(std::vector<u16>::iterator i = clients.begin();
2153 i != clients.end(); ++i) {
2154 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2159 total_sending += client->SendingCount();
2160 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2166 // Lowest priority number comes first.
2167 // Lowest is most important.
2168 std::sort(queue.begin(), queue.end());
2171 for(u32 i=0; i<queue.size(); i++)
2173 //TODO: Calculate limit dynamically
2174 if(total_sending >= g_settings->getS32
2175 ("max_simultaneous_block_sends_server_total"))
2178 PrioritySortedBlockTransfer q = queue[i];
2180 MapBlock *block = NULL;
2183 block = m_env->getMap().getBlockNoCreate(q.pos);
2185 catch(InvalidPositionException &e)
2190 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2195 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2197 client->SentBlock(q.pos);
2203 void Server::fillMediaCache()
2205 DSTACK(__FUNCTION_NAME);
2207 infostream<<"Server: Calculating media file checksums"<<std::endl;
2209 // Collect all media file paths
2210 std::vector<std::string> paths;
2211 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2212 i != m_mods.end(); i++) {
2213 const ModSpec &mod = *i;
2214 paths.push_back(mod.path + DIR_DELIM + "textures");
2215 paths.push_back(mod.path + DIR_DELIM + "sounds");
2216 paths.push_back(mod.path + DIR_DELIM + "media");
2217 paths.push_back(mod.path + DIR_DELIM + "models");
2219 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2221 // Collect media file information from paths into cache
2222 for(std::vector<std::string>::iterator i = paths.begin();
2223 i != paths.end(); i++) {
2224 std::string mediapath = *i;
2225 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2226 for (u32 j = 0; j < dirlist.size(); j++) {
2227 if (dirlist[j].dir) // Ignode dirs
2229 std::string filename = dirlist[j].name;
2230 // If name contains illegal characters, ignore the file
2231 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2232 infostream<<"Server: ignoring illegal file name: \""
2233 << filename << "\"" << std::endl;
2236 // If name is not in a supported format, ignore it
2237 const char *supported_ext[] = {
2238 ".png", ".jpg", ".bmp", ".tga",
2239 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2241 ".x", ".b3d", ".md2", ".obj",
2244 if (removeStringEnd(filename, supported_ext) == ""){
2245 infostream << "Server: ignoring unsupported file extension: \""
2246 << filename << "\"" << std::endl;
2249 // Ok, attempt to load the file and add to cache
2250 std::string filepath = mediapath + DIR_DELIM + filename;
2252 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2254 errorstream << "Server::fillMediaCache(): Could not open \""
2255 << filename << "\" for reading" << std::endl;
2258 std::ostringstream tmp_os(std::ios_base::binary);
2262 fis.read(buf, 1024);
2263 std::streamsize len = fis.gcount();
2264 tmp_os.write(buf, len);
2273 errorstream<<"Server::fillMediaCache(): Failed to read \""
2274 << filename << "\"" << std::endl;
2277 if(tmp_os.str().length() == 0) {
2278 errorstream << "Server::fillMediaCache(): Empty file \""
2279 << filepath << "\"" << std::endl;
2284 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2286 unsigned char *digest = sha1.getDigest();
2287 std::string sha1_base64 = base64_encode(digest, 20);
2288 std::string sha1_hex = hex_encode((char*)digest, 20);
2292 m_media[filename] = MediaInfo(filepath, sha1_base64);
2293 verbosestream << "Server: " << sha1_hex << " is " << filename
2299 struct SendableMediaAnnouncement
2302 std::string sha1_digest;
2304 SendableMediaAnnouncement(const std::string &name_="",
2305 const std::string &sha1_digest_=""):
2307 sha1_digest(sha1_digest_)
2311 void Server::sendMediaAnnouncement(u16 peer_id)
2313 DSTACK(__FUNCTION_NAME);
2315 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2318 std::vector<SendableMediaAnnouncement> file_announcements;
2320 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2321 i != m_media.end(); i++){
2323 file_announcements.push_back(
2324 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2328 std::ostringstream os(std::ios_base::binary);
2330 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2331 pkt << (u16) file_announcements.size();
2333 for (std::vector<SendableMediaAnnouncement>::iterator
2334 j = file_announcements.begin();
2335 j != file_announcements.end(); ++j) {
2336 pkt << j->name << j->sha1_digest;
2339 pkt << g_settings->get("remote_media");
2343 struct SendableMedia
2349 SendableMedia(const std::string &name_="", const std::string &path_="",
2350 const std::string &data_=""):
2357 void Server::sendRequestedMedia(u16 peer_id,
2358 const std::vector<std::string> &tosend)
2360 DSTACK(__FUNCTION_NAME);
2362 verbosestream<<"Server::sendRequestedMedia(): "
2363 <<"Sending files to client"<<std::endl;
2367 // Put 5kB in one bunch (this is not accurate)
2368 u32 bytes_per_bunch = 5000;
2370 std::vector< std::vector<SendableMedia> > file_bunches;
2371 file_bunches.push_back(std::vector<SendableMedia>());
2373 u32 file_size_bunch_total = 0;
2375 for(std::vector<std::string>::const_iterator i = tosend.begin();
2376 i != tosend.end(); ++i) {
2377 const std::string &name = *i;
2379 if(m_media.find(name) == m_media.end()) {
2380 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2381 <<"unknown file \""<<(name)<<"\""<<std::endl;
2385 //TODO get path + name
2386 std::string tpath = m_media[name].path;
2389 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2390 if(fis.good() == false){
2391 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2392 <<tpath<<"\" for reading"<<std::endl;
2395 std::ostringstream tmp_os(std::ios_base::binary);
2399 fis.read(buf, 1024);
2400 std::streamsize len = fis.gcount();
2401 tmp_os.write(buf, len);
2402 file_size_bunch_total += len;
2411 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2412 <<name<<"\""<<std::endl;
2415 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2416 <<tname<<"\""<<std::endl;*/
2418 file_bunches[file_bunches.size()-1].push_back(
2419 SendableMedia(name, tpath, tmp_os.str()));
2421 // Start next bunch if got enough data
2422 if(file_size_bunch_total >= bytes_per_bunch) {
2423 file_bunches.push_back(std::vector<SendableMedia>());
2424 file_size_bunch_total = 0;
2429 /* Create and send packets */
2431 u16 num_bunches = file_bunches.size();
2432 for(u16 i = 0; i < num_bunches; i++) {
2435 u16 total number of texture bunches
2436 u16 index of this bunch
2437 u32 number of files in this bunch
2446 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2447 pkt << num_bunches << i << (u32) file_bunches[i].size();
2449 for(std::vector<SendableMedia>::iterator
2450 j = file_bunches[i].begin();
2451 j != file_bunches[i].end(); ++j) {
2453 pkt.putLongString(j->data);
2456 verbosestream << "Server::sendRequestedMedia(): bunch "
2457 << i << "/" << num_bunches
2458 << " files=" << file_bunches[i].size()
2459 << " size=" << pkt.getSize() << std::endl;
2464 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2466 if(m_detached_inventories.count(name) == 0) {
2467 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2470 Inventory *inv = m_detached_inventories[name];
2471 std::ostringstream os(std::ios_base::binary);
2473 os << serializeString(name);
2477 std::string s = os.str();
2479 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2480 pkt.putRawString(s.c_str(), s.size());
2482 if (peer_id != PEER_ID_INEXISTENT) {
2486 m_clients.sendToAll(0, &pkt, true);
2490 void Server::sendDetachedInventories(u16 peer_id)
2492 DSTACK(__FUNCTION_NAME);
2494 for(std::map<std::string, Inventory*>::iterator
2495 i = m_detached_inventories.begin();
2496 i != m_detached_inventories.end(); i++) {
2497 const std::string &name = i->first;
2498 //Inventory *inv = i->second;
2499 sendDetachedInventory(name, peer_id);
2507 void Server::DiePlayer(u16 peer_id)
2509 DSTACK(__FUNCTION_NAME);
2511 PlayerSAO *playersao = getPlayerSAO(peer_id);
2514 infostream << "Server::DiePlayer(): Player "
2515 << playersao->getPlayer()->getName()
2516 << " dies" << std::endl;
2518 playersao->setHP(0);
2520 // Trigger scripted stuff
2521 m_script->on_dieplayer(playersao);
2523 SendPlayerHP(peer_id);
2524 SendDeathscreen(peer_id, false, v3f(0,0,0));
2527 void Server::RespawnPlayer(u16 peer_id)
2529 DSTACK(__FUNCTION_NAME);
2531 PlayerSAO *playersao = getPlayerSAO(peer_id);
2534 infostream << "Server::RespawnPlayer(): Player "
2535 << playersao->getPlayer()->getName()
2536 << " respawns" << std::endl;
2538 playersao->setHP(PLAYER_MAX_HP);
2539 playersao->setBreath(PLAYER_MAX_BREATH);
2541 SendPlayerHP(peer_id);
2542 SendPlayerBreath(peer_id);
2544 bool repositioned = m_script->on_respawnplayer(playersao);
2546 v3f pos = findSpawnPos();
2547 // setPos will send the new position to client
2548 playersao->setPos(pos);
2551 void Server::DenySudoAccess(u16 peer_id)
2553 DSTACK(__FUNCTION_NAME);
2555 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2559 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2561 DSTACK(__FUNCTION_NAME);
2563 SendAccessDenied(peer_id, reason, custom_reason);
2564 m_clients.event(peer_id, CSE_SetDenied);
2565 m_con.DisconnectPeer(peer_id);
2568 // 13/03/15: remove this function when protocol version 25 will become
2569 // the minimum version for MT users, maybe in 1 year
2570 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2572 DSTACK(__FUNCTION_NAME);
2574 SendAccessDenied_Legacy(peer_id, reason);
2575 m_clients.event(peer_id, CSE_SetDenied);
2576 m_con.DisconnectPeer(peer_id);
2579 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2581 DSTACK(__FUNCTION_NAME);
2584 RemoteClient* client = getClient(peer_id, CS_Invalid);
2586 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2588 // Right now, the auth mechs don't change between login and sudo mode.
2589 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2590 client->allowed_sudo_mechs = sudo_auth_mechs;
2592 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2593 << g_settings->getFloat("dedicated_server_step")
2597 m_clients.event(peer_id, CSE_AuthAccept);
2599 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2601 // We only support SRP right now
2602 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2604 resp_pkt << sudo_auth_mechs;
2606 m_clients.event(peer_id, CSE_SudoSuccess);
2610 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2612 DSTACK(__FUNCTION_NAME);
2613 std::wstring message;
2616 Clear references to playing sounds
2618 for(std::map<s32, ServerPlayingSound>::iterator
2619 i = m_playing_sounds.begin();
2620 i != m_playing_sounds.end();)
2622 ServerPlayingSound &psound = i->second;
2623 psound.clients.erase(peer_id);
2624 if(psound.clients.empty())
2625 m_playing_sounds.erase(i++);
2630 Player *player = m_env->getPlayer(peer_id);
2632 // Collect information about leaving in chat
2634 if(player != NULL && reason != CDR_DENY)
2636 std::wstring name = narrow_to_wide(player->getName());
2639 message += L" left the game.";
2640 if(reason == CDR_TIMEOUT)
2641 message += L" (timed out)";
2645 /* Run scripts and remove from environment */
2649 PlayerSAO *playersao = player->getPlayerSAO();
2652 m_script->on_leaveplayer(playersao);
2654 playersao->disconnected();
2662 if(player != NULL && reason != CDR_DENY) {
2663 std::ostringstream os(std::ios_base::binary);
2664 std::vector<u16> clients = m_clients.getClientIDs();
2666 for(std::vector<u16>::iterator i = clients.begin();
2667 i != clients.end(); ++i) {
2669 Player *player = m_env->getPlayer(*i);
2673 // Get name of player
2674 os << player->getName() << " ";
2677 actionstream << player->getName() << " "
2678 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2679 << " List of players: " << os.str() << std::endl;
2683 JMutexAutoLock env_lock(m_env_mutex);
2684 m_clients.DeleteClient(peer_id);
2688 // Send leave chat message to all remaining clients
2689 if(message.length() != 0)
2690 SendChatMessage(PEER_ID_INEXISTENT,message);
2693 void Server::UpdateCrafting(Player* player)
2695 DSTACK(__FUNCTION_NAME);
2697 // Get a preview for crafting
2699 InventoryLocation loc;
2700 loc.setPlayer(player->getName());
2701 getCraftingResult(&player->inventory, preview, false, this);
2702 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2704 // Put the new preview in
2705 InventoryList *plist = player->inventory.getList("craftpreview");
2706 sanity_check(plist);
2707 sanity_check(plist->getSize() >= 1);
2708 plist->changeItem(0, preview);
2711 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2713 RemoteClient *client = getClientNoEx(peer_id,state_min);
2715 throw ClientNotFoundException("Client not found");
2719 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2721 return m_clients.getClientNoEx(peer_id, state_min);
2724 std::string Server::getPlayerName(u16 peer_id)
2726 Player *player = m_env->getPlayer(peer_id);
2728 return "[id="+itos(peer_id)+"]";
2729 return player->getName();
2732 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2734 Player *player = m_env->getPlayer(peer_id);
2737 return player->getPlayerSAO();
2740 std::wstring Server::getStatusString()
2742 std::wostringstream os(std::ios_base::binary);
2745 os<<L"version="<<narrow_to_wide(g_version_string);
2747 os<<L", uptime="<<m_uptime.get();
2749 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2750 // Information about clients
2753 std::vector<u16> clients = m_clients.getClientIDs();
2754 for(std::vector<u16>::iterator i = clients.begin();
2755 i != clients.end(); ++i) {
2757 Player *player = m_env->getPlayer(*i);
2758 // Get name of player
2759 std::wstring name = L"unknown";
2761 name = narrow_to_wide(player->getName());
2762 // Add name to information string
2770 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2771 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2772 if(g_settings->get("motd") != "")
2773 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2777 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2779 std::set<std::string> privs;
2780 m_script->getAuth(name, NULL, &privs);
2784 bool Server::checkPriv(const std::string &name, const std::string &priv)
2786 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2787 return (privs.count(priv) != 0);
2790 void Server::reportPrivsModified(const std::string &name)
2793 std::vector<u16> clients = m_clients.getClientIDs();
2794 for(std::vector<u16>::iterator i = clients.begin();
2795 i != clients.end(); ++i) {
2796 Player *player = m_env->getPlayer(*i);
2797 reportPrivsModified(player->getName());
2800 Player *player = m_env->getPlayer(name.c_str());
2803 SendPlayerPrivileges(player->peer_id);
2804 PlayerSAO *sao = player->getPlayerSAO();
2807 sao->updatePrivileges(
2808 getPlayerEffectivePrivs(name),
2813 void Server::reportInventoryFormspecModified(const std::string &name)
2815 Player *player = m_env->getPlayer(name.c_str());
2818 SendPlayerInventoryFormspec(player->peer_id);
2821 void Server::setIpBanned(const std::string &ip, const std::string &name)
2823 m_banmanager->add(ip, name);
2826 void Server::unsetIpBanned(const std::string &ip_or_name)
2828 m_banmanager->remove(ip_or_name);
2831 std::string Server::getBanDescription(const std::string &ip_or_name)
2833 return m_banmanager->getBanDescription(ip_or_name);
2836 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2838 Player *player = m_env->getPlayer(name);
2842 if (player->peer_id == PEER_ID_INEXISTENT)
2845 SendChatMessage(player->peer_id, msg);
2848 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2850 Player *player = m_env->getPlayer(playername);
2854 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2858 SendShowFormspecMessage(player->peer_id, formspec, formname);
2862 u32 Server::hudAdd(Player *player, HudElement *form) {
2866 u32 id = player->addHud(form);
2868 SendHUDAdd(player->peer_id, id, form);
2873 bool Server::hudRemove(Player *player, u32 id) {
2877 HudElement* todel = player->removeHud(id);
2884 SendHUDRemove(player->peer_id, id);
2888 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2892 SendHUDChange(player->peer_id, id, stat, data);
2896 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2900 SendHUDSetFlags(player->peer_id, flags, mask);
2901 player->hud_flags = flags;
2903 PlayerSAO* playersao = player->getPlayerSAO();
2905 if (playersao == NULL)
2908 m_script->player_event(playersao, "hud_changed");
2912 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2915 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2918 player->setHotbarItemcount(hotbar_itemcount);
2919 std::ostringstream os(std::ios::binary);
2920 writeS32(os, hotbar_itemcount);
2921 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2925 s32 Server::hudGetHotbarItemcount(Player *player) {
2928 return player->getHotbarItemcount();
2931 void Server::hudSetHotbarImage(Player *player, std::string name) {
2935 player->setHotbarImage(name);
2936 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2939 std::string Server::hudGetHotbarImage(Player *player) {
2942 return player->getHotbarImage();
2945 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2949 player->setHotbarSelectedImage(name);
2950 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2953 std::string Server::hudGetHotbarSelectedImage(Player *player) {
2957 return player->getHotbarSelectedImage();
2960 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2965 player->setLocalAnimations(animation_frames, frame_speed);
2966 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2970 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2975 player->eye_offset_first = first;
2976 player->eye_offset_third = third;
2977 SendEyeOffset(player->peer_id, first, third);
2981 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2982 const std::string &type, const std::vector<std::string> ¶ms)
2987 player->setSky(bgcolor, type, params);
2988 SendSetSky(player->peer_id, bgcolor, type, params);
2992 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2998 player->overrideDayNightRatio(do_override, ratio);
2999 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3003 void Server::notifyPlayers(const std::wstring &msg)
3005 SendChatMessage(PEER_ID_INEXISTENT,msg);
3008 void Server::spawnParticle(const char *playername, v3f pos,
3009 v3f velocity, v3f acceleration,
3010 float expirationtime, float size, bool
3011 collisiondetection, bool vertical, std::string texture)
3013 Player *player = m_env->getPlayer(playername);
3016 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3017 expirationtime, size, collisiondetection, vertical, texture);
3020 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3021 float expirationtime, float size,
3022 bool collisiondetection, bool vertical, std::string texture)
3024 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3025 expirationtime, size, collisiondetection, vertical, texture);
3028 u32 Server::addParticleSpawner(const char *playername,
3029 u16 amount, float spawntime,
3030 v3f minpos, v3f maxpos,
3031 v3f minvel, v3f maxvel,
3032 v3f minacc, v3f maxacc,
3033 float minexptime, float maxexptime,
3034 float minsize, float maxsize,
3035 bool collisiondetection, bool vertical, std::string texture)
3037 Player *player = m_env->getPlayer(playername);
3042 for(;;) // look for unused particlespawner id
3045 if (std::find(m_particlespawner_ids.begin(),
3046 m_particlespawner_ids.end(), id)
3047 == m_particlespawner_ids.end())
3049 m_particlespawner_ids.push_back(id);
3054 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3055 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3056 minexptime, maxexptime, minsize, maxsize,
3057 collisiondetection, vertical, texture, id);
3062 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3063 v3f minpos, v3f maxpos,
3064 v3f minvel, v3f maxvel,
3065 v3f minacc, v3f maxacc,
3066 float minexptime, float maxexptime,
3067 float minsize, float maxsize,
3068 bool collisiondetection, bool vertical, std::string texture)
3071 for(;;) // look for unused particlespawner id
3074 if (std::find(m_particlespawner_ids.begin(),
3075 m_particlespawner_ids.end(), id)
3076 == m_particlespawner_ids.end())
3078 m_particlespawner_ids.push_back(id);
3083 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3084 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3085 minexptime, maxexptime, minsize, maxsize,
3086 collisiondetection, vertical, texture, id);
3091 void Server::deleteParticleSpawner(const char *playername, u32 id)
3093 Player *player = m_env->getPlayer(playername);
3097 m_particlespawner_ids.erase(
3098 std::remove(m_particlespawner_ids.begin(),
3099 m_particlespawner_ids.end(), id),
3100 m_particlespawner_ids.end());
3101 SendDeleteParticleSpawner(player->peer_id, id);
3104 void Server::deleteParticleSpawnerAll(u32 id)
3106 m_particlespawner_ids.erase(
3107 std::remove(m_particlespawner_ids.begin(),
3108 m_particlespawner_ids.end(), id),
3109 m_particlespawner_ids.end());
3110 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3113 Inventory* Server::createDetachedInventory(const std::string &name)
3115 if(m_detached_inventories.count(name) > 0){
3116 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3117 delete m_detached_inventories[name];
3119 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3121 Inventory *inv = new Inventory(m_itemdef);
3123 m_detached_inventories[name] = inv;
3124 //TODO find a better way to do this
3125 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3132 BoolScopeSet(bool *dst, bool val):
3135 m_orig_state = *m_dst;
3140 *m_dst = m_orig_state;
3147 // actions: time-reversed list
3148 // Return value: success/failure
3149 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3150 std::list<std::string> *log)
3152 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3153 ServerMap *map = (ServerMap*)(&m_env->getMap());
3155 // Fail if no actions to handle
3156 if(actions.empty()){
3157 log->push_back("Nothing to do.");
3164 for(std::list<RollbackAction>::const_iterator
3165 i = actions.begin();
3166 i != actions.end(); i++)
3168 const RollbackAction &action = *i;
3170 bool success = action.applyRevert(map, this, this);
3173 std::ostringstream os;
3174 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3175 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3177 log->push_back(os.str());
3179 std::ostringstream os;
3180 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3181 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3183 log->push_back(os.str());
3187 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3188 <<" failed"<<std::endl;
3190 // Call it done if less than half failed
3191 return num_failed <= num_tried/2;
3194 // IGameDef interface
3196 IItemDefManager* Server::getItemDefManager()
3200 INodeDefManager* Server::getNodeDefManager()
3204 ICraftDefManager* Server::getCraftDefManager()
3208 ITextureSource* Server::getTextureSource()
3212 IShaderSource* Server::getShaderSource()
3216 scene::ISceneManager* Server::getSceneManager()
3221 u16 Server::allocateUnknownNodeId(const std::string &name)
3223 return m_nodedef->allocateDummy(name);
3225 ISoundManager* Server::getSoundManager()
3227 return &dummySoundManager;
3229 MtEventManager* Server::getEventManager()
3234 IWritableItemDefManager* Server::getWritableItemDefManager()
3238 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3242 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3247 const ModSpec* Server::getModSpec(const std::string &modname) const
3249 for(std::vector<ModSpec>::const_iterator i = m_mods.begin();
3250 i != m_mods.end(); i++){
3251 const ModSpec &mod = *i;
3252 if(mod.name == modname)
3257 void Server::getModNames(std::vector<std::string> &modlist)
3259 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3260 modlist.push_back(i->name);
3263 std::string Server::getBuiltinLuaPath()
3265 return porting::path_share + DIR_DELIM + "builtin";
3268 v3f Server::findSpawnPos()
3270 ServerMap &map = m_env->getServerMap();
3272 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3273 return nodeposf * BS;
3276 // Default position is static_spawnpoint
3277 // We will return it if we don't found a good place
3278 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3280 s16 water_level = map.getWaterLevel();
3282 bool is_good = false;
3284 // Try to find a good place a few times
3285 for(s32 i = 0; i < 1000 && !is_good; i++) {
3287 // We're going to try to throw the player to this position
3288 v2s16 nodepos2d = v2s16(
3289 -range + (myrand() % (range * 2)),
3290 -range + (myrand() % (range * 2)));
3292 // Get ground height at point
3293 s16 groundheight = map.findGroundLevel(nodepos2d);
3294 if (groundheight <= water_level) // Don't go underwater
3296 if (groundheight > water_level + 6) // Don't go to high places
3299 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3302 for (s32 i = 0; i < 10; i++) {
3303 v3s16 blockpos = getNodeBlockPos(nodepos);
3304 map.emergeBlock(blockpos, true);
3305 content_t c = map.getNodeNoEx(nodepos).getContent();
3306 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3308 if (air_count >= 2){
3317 return intToFloat(nodepos, BS);
3320 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3322 bool newplayer = false;
3325 Try to get an existing player
3327 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3329 // If player is already connected, cancel
3330 if(player != NULL && player->peer_id != 0)
3332 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3337 If player with the wanted peer_id already exists, cancel.
3339 if(m_env->getPlayer(peer_id) != NULL)
3341 infostream<<"emergePlayer(): Player with wrong name but same"
3342 " peer_id already exists"<<std::endl;
3346 // Load player if it isn't already loaded
3348 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3351 // Create player if it doesn't exist
3354 player = new RemotePlayer(this, name);
3355 // Set player position
3356 infostream<<"Server: Finding spawn place for player \""
3357 <<name<<"\""<<std::endl;
3358 v3f pos = findSpawnPos();
3359 player->setPosition(pos);
3361 // Make sure the player is saved
3362 player->setModified(true);
3364 // Add player to environment
3365 m_env->addPlayer(player);
3368 // Create a new player active object
3369 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3370 getPlayerEffectivePrivs(player->getName()),
3373 /* Clean up old HUD elements from previous sessions */
3376 /* Add object to environment */
3377 m_env->addActiveObject(playersao);
3381 m_script->on_newplayer(playersao);
3387 void dedicated_server_loop(Server &server, bool &kill)
3389 DSTACK(__FUNCTION_NAME);
3391 verbosestream<<"dedicated_server_loop()"<<std::endl;
3393 IntervalLimiter m_profiler_interval;
3397 float steplen = g_settings->getFloat("dedicated_server_step");
3398 // This is kind of a hack but can be done like this
3399 // because server.step() is very light
3401 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3402 sleep_ms((int)(steplen*1000.0));
3404 server.step(steplen);
3406 if(server.getShutdownRequested() || kill)
3408 infostream<<"Dedicated server quitting"<<std::endl;
3410 if(g_settings->getBool("server_announce"))
3411 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3419 float profiler_print_interval =
3420 g_settings->getFloat("profiler_print_interval");
3421 if(profiler_print_interval != 0)
3423 if(m_profiler_interval.step(steplen, profiler_print_interval))
3425 infostream<<"Profiler:"<<std::endl;
3426 g_profiler->print(infostream);
3427 g_profiler->clear();