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(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;
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::SendHP(u16 peer_id, u8 hp)
1492 DSTACK(__FUNCTION_NAME);
1494 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1499 void Server::SendBreath(u16 peer_id, u16 breath)
1501 DSTACK(__FUNCTION_NAME);
1503 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1504 pkt << (u16) breath;
1508 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1510 DSTACK(__FUNCTION_NAME);
1512 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1515 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1516 pkt << custom_reason;
1521 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1523 DSTACK(__FUNCTION_NAME);
1525 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1530 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1531 v3f camera_point_target)
1533 DSTACK(__FUNCTION_NAME);
1535 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1536 pkt << set_camera_point_target << camera_point_target;
1540 void Server::SendItemDef(u16 peer_id,
1541 IItemDefManager *itemdef, u16 protocol_version)
1543 DSTACK(__FUNCTION_NAME);
1545 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1549 u32 length of the next item
1550 zlib-compressed serialized ItemDefManager
1552 std::ostringstream tmp_os(std::ios::binary);
1553 itemdef->serialize(tmp_os, protocol_version);
1554 std::ostringstream tmp_os2(std::ios::binary);
1555 compressZlib(tmp_os.str(), tmp_os2);
1556 pkt.putLongString(tmp_os2.str());
1559 verbosestream << "Server: Sending item definitions to id(" << peer_id
1560 << "): size=" << pkt.getSize() << std::endl;
1565 void Server::SendNodeDef(u16 peer_id,
1566 INodeDefManager *nodedef, u16 protocol_version)
1568 DSTACK(__FUNCTION_NAME);
1570 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1574 u32 length of the next item
1575 zlib-compressed serialized NodeDefManager
1577 std::ostringstream tmp_os(std::ios::binary);
1578 nodedef->serialize(tmp_os, protocol_version);
1579 std::ostringstream tmp_os2(std::ios::binary);
1580 compressZlib(tmp_os.str(), tmp_os2);
1582 pkt.putLongString(tmp_os2.str());
1585 verbosestream << "Server: Sending node definitions to id(" << peer_id
1586 << "): size=" << pkt.getSize() << std::endl;
1592 Non-static send methods
1595 void Server::SendInventory(PlayerSAO* playerSAO)
1597 DSTACK(__FUNCTION_NAME);
1599 UpdateCrafting(playerSAO->getPlayer());
1605 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1607 std::ostringstream os;
1608 playerSAO->getInventory()->serialize(os);
1610 std::string s = os.str();
1612 pkt.putRawString(s.c_str(), s.size());
1616 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1618 DSTACK(__FUNCTION_NAME);
1620 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1623 if (peer_id != PEER_ID_INEXISTENT) {
1627 m_clients.sendToAll(0, &pkt, true);
1631 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1632 const std::string &formname)
1634 DSTACK(__FUNCTION_NAME);
1636 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1638 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1644 // Spawns a particle on peer with peer_id
1645 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1646 float expirationtime, float size, bool collisiondetection,
1647 bool vertical, std::string texture)
1649 DSTACK(__FUNCTION_NAME);
1651 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1653 pkt << pos << velocity << acceleration << expirationtime
1654 << size << collisiondetection;
1655 pkt.putLongString(texture);
1658 if (peer_id != PEER_ID_INEXISTENT) {
1662 m_clients.sendToAll(0, &pkt, true);
1666 // Adds a ParticleSpawner on peer with peer_id
1667 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1668 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1669 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1671 DSTACK(__FUNCTION_NAME);
1673 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1675 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1676 << minacc << maxacc << minexptime << maxexptime << minsize
1677 << maxsize << collisiondetection;
1679 pkt.putLongString(texture);
1681 pkt << id << vertical;
1683 if (peer_id != PEER_ID_INEXISTENT) {
1687 m_clients.sendToAll(0, &pkt, true);
1691 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1693 DSTACK(__FUNCTION_NAME);
1695 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1697 // Ugly error in this packet
1700 if (peer_id != PEER_ID_INEXISTENT) {
1704 m_clients.sendToAll(0, &pkt, true);
1709 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1711 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1713 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1714 << form->text << form->number << form->item << form->dir
1715 << form->align << form->offset << form->world_pos << form->size;
1720 void Server::SendHUDRemove(u16 peer_id, u32 id)
1722 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1727 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1729 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1730 pkt << id << (u8) stat;
1734 case HUD_STAT_SCALE:
1735 case HUD_STAT_ALIGN:
1736 case HUD_STAT_OFFSET:
1737 pkt << *(v2f *) value;
1741 pkt << *(std::string *) value;
1743 case HUD_STAT_WORLD_POS:
1744 pkt << *(v3f *) value;
1747 pkt << *(v2s32 *) value;
1749 case HUD_STAT_NUMBER:
1753 pkt << *(u32 *) value;
1760 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1762 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1764 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1766 pkt << flags << mask;
1771 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1773 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1774 pkt << param << value;
1778 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1779 const std::string &type, const std::vector<std::string> ¶ms)
1781 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1782 pkt << bgcolor << type << (u16) params.size();
1784 for(size_t i=0; i<params.size(); i++)
1790 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1793 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1796 pkt << do_override << (u16) (ratio * 65535);
1801 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1803 DSTACK(__FUNCTION_NAME);
1805 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1806 pkt << time << time_speed;
1808 if (peer_id == PEER_ID_INEXISTENT) {
1809 m_clients.sendToAll(0, &pkt, true);
1816 void Server::SendPlayerHP(u16 peer_id)
1818 DSTACK(__FUNCTION_NAME);
1819 PlayerSAO *playersao = getPlayerSAO(peer_id);
1820 // In some rare case, if the player is disconnected
1821 // while Lua call l_punch, for example, this can be NULL
1825 SendHP(peer_id, playersao->getHP());
1826 m_script->player_event(playersao,"health_changed");
1828 // Send to other clients
1829 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1830 ActiveObjectMessage aom(playersao->getId(), true, str);
1831 playersao->m_messages_out.push(aom);
1834 void Server::SendPlayerBreath(u16 peer_id)
1836 DSTACK(__FUNCTION_NAME);
1837 PlayerSAO *playersao = getPlayerSAO(peer_id);
1840 m_script->player_event(playersao, "breath_changed");
1841 SendBreath(peer_id, playersao->getBreath());
1844 void Server::SendMovePlayer(u16 peer_id)
1846 DSTACK(__FUNCTION_NAME);
1847 Player *player = m_env->getPlayer(peer_id);
1850 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1851 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1854 v3f pos = player->getPosition();
1855 f32 pitch = player->getPitch();
1856 f32 yaw = player->getYaw();
1857 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1858 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1859 << " pitch=" << pitch
1867 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1869 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1872 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1873 << animation_frames[3] << animation_speed;
1878 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1880 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1881 pkt << first << third;
1884 void Server::SendPlayerPrivileges(u16 peer_id)
1886 Player *player = m_env->getPlayer(peer_id);
1888 if(player->peer_id == PEER_ID_INEXISTENT)
1891 std::set<std::string> privs;
1892 m_script->getAuth(player->getName(), NULL, &privs);
1894 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1895 pkt << (u16) privs.size();
1897 for(std::set<std::string>::const_iterator i = privs.begin();
1898 i != privs.end(); i++) {
1905 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1907 Player *player = m_env->getPlayer(peer_id);
1909 if(player->peer_id == PEER_ID_INEXISTENT)
1912 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1913 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1917 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1919 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1920 pkt.putRawString(datas.c_str(), datas.size());
1922 return pkt.getSize();
1925 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1927 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1928 datas.size(), peer_id);
1930 pkt.putRawString(datas.c_str(), datas.size());
1932 m_clients.send(pkt.getPeerId(),
1933 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1938 s32 Server::playSound(const SimpleSoundSpec &spec,
1939 const ServerSoundParams ¶ms)
1941 // Find out initial position of sound
1942 bool pos_exists = false;
1943 v3f pos = params.getPos(m_env, &pos_exists);
1944 // If position is not found while it should be, cancel sound
1945 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1948 // Filter destination clients
1949 std::vector<u16> dst_clients;
1950 if(params.to_player != "")
1952 Player *player = m_env->getPlayer(params.to_player.c_str());
1954 infostream<<"Server::playSound: Player \""<<params.to_player
1955 <<"\" not found"<<std::endl;
1958 if(player->peer_id == PEER_ID_INEXISTENT){
1959 infostream<<"Server::playSound: Player \""<<params.to_player
1960 <<"\" not connected"<<std::endl;
1963 dst_clients.push_back(player->peer_id);
1966 std::vector<u16> clients = m_clients.getClientIDs();
1968 for(std::vector<u16>::iterator
1969 i = clients.begin(); i != clients.end(); ++i) {
1970 Player *player = m_env->getPlayer(*i);
1975 if(player->getPosition().getDistanceFrom(pos) >
1976 params.max_hear_distance)
1979 dst_clients.push_back(*i);
1983 if(dst_clients.empty())
1987 s32 id = m_next_sound_id++;
1988 // The sound will exist as a reference in m_playing_sounds
1989 m_playing_sounds[id] = ServerPlayingSound();
1990 ServerPlayingSound &psound = m_playing_sounds[id];
1991 psound.params = params;
1993 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1994 pkt << id << spec.name << (float) (spec.gain * params.gain)
1995 << (u8) params.type << pos << params.object << params.loop;
1997 for(std::vector<u16>::iterator i = dst_clients.begin();
1998 i != dst_clients.end(); i++) {
1999 psound.clients.insert(*i);
2000 m_clients.send(*i, 0, &pkt, true);
2004 void Server::stopSound(s32 handle)
2006 // Get sound reference
2007 std::map<s32, ServerPlayingSound>::iterator i =
2008 m_playing_sounds.find(handle);
2009 if(i == m_playing_sounds.end())
2011 ServerPlayingSound &psound = i->second;
2013 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2016 for(std::set<u16>::iterator i = psound.clients.begin();
2017 i != psound.clients.end(); i++) {
2019 m_clients.send(*i, 0, &pkt, true);
2021 // Remove sound reference
2022 m_playing_sounds.erase(i);
2025 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2026 std::vector<u16> *far_players, float far_d_nodes)
2028 float maxd = far_d_nodes*BS;
2029 v3f p_f = intToFloat(p, BS);
2031 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2034 std::vector<u16> clients = m_clients.getClientIDs();
2035 for(std::vector<u16>::iterator i = clients.begin();
2036 i != clients.end(); ++i) {
2039 if(Player *player = m_env->getPlayer(*i)) {
2040 // If player is far away, only set modified blocks not sent
2041 v3f player_pos = player->getPosition();
2042 if(player_pos.getDistanceFrom(p_f) > maxd) {
2043 far_players->push_back(*i);
2050 m_clients.send(*i, 0, &pkt, true);
2054 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2055 std::vector<u16> *far_players, float far_d_nodes,
2056 bool remove_metadata)
2058 float maxd = far_d_nodes*BS;
2059 v3f p_f = intToFloat(p, BS);
2061 std::vector<u16> clients = m_clients.getClientIDs();
2062 for(std::vector<u16>::iterator i = clients.begin();
2063 i != clients.end(); ++i) {
2067 if(Player *player = m_env->getPlayer(*i)) {
2068 // If player is far away, only set modified blocks not sent
2069 v3f player_pos = player->getPosition();
2070 if(player_pos.getDistanceFrom(p_f) > maxd) {
2071 far_players->push_back(*i);
2077 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2079 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2081 pkt << p << n.param0 << n.param1 << n.param2
2082 << (u8) (remove_metadata ? 0 : 1);
2084 if (!remove_metadata) {
2085 if (client->net_proto_version <= 21) {
2086 // Old clients always clear metadata; fix it
2087 // by sending the full block again.
2088 client->SetBlockNotSent(p);
2095 if (pkt.getSize() > 0)
2096 m_clients.send(*i, 0, &pkt, true);
2100 void Server::setBlockNotSent(v3s16 p)
2102 std::vector<u16> clients = m_clients.getClientIDs();
2104 for(std::vector<u16>::iterator i = clients.begin();
2105 i != clients.end(); ++i) {
2106 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2107 client->SetBlockNotSent(p);
2112 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2114 DSTACK(__FUNCTION_NAME);
2116 v3s16 p = block->getPos();
2119 Create a packet with the block in the right format
2122 std::ostringstream os(std::ios_base::binary);
2123 block->serialize(os, ver, false);
2124 block->serializeNetworkSpecific(os, net_proto_version);
2125 std::string s = os.str();
2127 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2130 pkt.putRawString(s.c_str(), s.size());
2134 void Server::SendBlocks(float dtime)
2136 DSTACK(__FUNCTION_NAME);
2138 JMutexAutoLock envlock(m_env_mutex);
2139 //TODO check if one big lock could be faster then multiple small ones
2141 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2143 std::vector<PrioritySortedBlockTransfer> queue;
2145 s32 total_sending = 0;
2148 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2150 std::vector<u16> clients = m_clients.getClientIDs();
2153 for(std::vector<u16>::iterator i = clients.begin();
2154 i != clients.end(); ++i) {
2155 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2160 total_sending += client->SendingCount();
2161 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2167 // Lowest priority number comes first.
2168 // Lowest is most important.
2169 std::sort(queue.begin(), queue.end());
2172 for(u32 i=0; i<queue.size(); i++)
2174 //TODO: Calculate limit dynamically
2175 if(total_sending >= g_settings->getS32
2176 ("max_simultaneous_block_sends_server_total"))
2179 PrioritySortedBlockTransfer q = queue[i];
2181 MapBlock *block = NULL;
2184 block = m_env->getMap().getBlockNoCreate(q.pos);
2186 catch(InvalidPositionException &e)
2191 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2196 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2198 client->SentBlock(q.pos);
2204 void Server::fillMediaCache()
2206 DSTACK(__FUNCTION_NAME);
2208 infostream<<"Server: Calculating media file checksums"<<std::endl;
2210 // Collect all media file paths
2211 std::vector<std::string> paths;
2212 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2213 i != m_mods.end(); i++) {
2214 const ModSpec &mod = *i;
2215 paths.push_back(mod.path + DIR_DELIM + "textures");
2216 paths.push_back(mod.path + DIR_DELIM + "sounds");
2217 paths.push_back(mod.path + DIR_DELIM + "media");
2218 paths.push_back(mod.path + DIR_DELIM + "models");
2220 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2222 // Collect media file information from paths into cache
2223 for(std::vector<std::string>::iterator i = paths.begin();
2224 i != paths.end(); i++) {
2225 std::string mediapath = *i;
2226 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2227 for (u32 j = 0; j < dirlist.size(); j++) {
2228 if (dirlist[j].dir) // Ignode dirs
2230 std::string filename = dirlist[j].name;
2231 // If name contains illegal characters, ignore the file
2232 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2233 infostream<<"Server: ignoring illegal file name: \""
2234 << filename << "\"" << std::endl;
2237 // If name is not in a supported format, ignore it
2238 const char *supported_ext[] = {
2239 ".png", ".jpg", ".bmp", ".tga",
2240 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2242 ".x", ".b3d", ".md2", ".obj",
2245 if (removeStringEnd(filename, supported_ext) == ""){
2246 infostream << "Server: ignoring unsupported file extension: \""
2247 << filename << "\"" << std::endl;
2250 // Ok, attempt to load the file and add to cache
2251 std::string filepath = mediapath + DIR_DELIM + filename;
2253 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2255 errorstream << "Server::fillMediaCache(): Could not open \""
2256 << filename << "\" for reading" << std::endl;
2259 std::ostringstream tmp_os(std::ios_base::binary);
2263 fis.read(buf, 1024);
2264 std::streamsize len = fis.gcount();
2265 tmp_os.write(buf, len);
2274 errorstream<<"Server::fillMediaCache(): Failed to read \""
2275 << filename << "\"" << std::endl;
2278 if(tmp_os.str().length() == 0) {
2279 errorstream << "Server::fillMediaCache(): Empty file \""
2280 << filepath << "\"" << std::endl;
2285 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2287 unsigned char *digest = sha1.getDigest();
2288 std::string sha1_base64 = base64_encode(digest, 20);
2289 std::string sha1_hex = hex_encode((char*)digest, 20);
2293 m_media[filename] = MediaInfo(filepath, sha1_base64);
2294 verbosestream << "Server: " << sha1_hex << " is " << filename
2300 struct SendableMediaAnnouncement
2303 std::string sha1_digest;
2305 SendableMediaAnnouncement(const std::string &name_="",
2306 const std::string &sha1_digest_=""):
2308 sha1_digest(sha1_digest_)
2312 void Server::sendMediaAnnouncement(u16 peer_id)
2314 DSTACK(__FUNCTION_NAME);
2316 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2319 std::vector<SendableMediaAnnouncement> file_announcements;
2321 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2322 i != m_media.end(); i++){
2324 file_announcements.push_back(
2325 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2329 std::ostringstream os(std::ios_base::binary);
2331 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2332 pkt << (u16) file_announcements.size();
2334 for (std::vector<SendableMediaAnnouncement>::iterator
2335 j = file_announcements.begin();
2336 j != file_announcements.end(); ++j) {
2337 pkt << j->name << j->sha1_digest;
2340 pkt << g_settings->get("remote_media");
2344 struct SendableMedia
2350 SendableMedia(const std::string &name_="", const std::string &path_="",
2351 const std::string &data_=""):
2358 void Server::sendRequestedMedia(u16 peer_id,
2359 const std::vector<std::string> &tosend)
2361 DSTACK(__FUNCTION_NAME);
2363 verbosestream<<"Server::sendRequestedMedia(): "
2364 <<"Sending files to client"<<std::endl;
2368 // Put 5kB in one bunch (this is not accurate)
2369 u32 bytes_per_bunch = 5000;
2371 std::vector< std::vector<SendableMedia> > file_bunches;
2372 file_bunches.push_back(std::vector<SendableMedia>());
2374 u32 file_size_bunch_total = 0;
2376 for(std::vector<std::string>::const_iterator i = tosend.begin();
2377 i != tosend.end(); ++i) {
2378 const std::string &name = *i;
2380 if(m_media.find(name) == m_media.end()) {
2381 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2382 <<"unknown file \""<<(name)<<"\""<<std::endl;
2386 //TODO get path + name
2387 std::string tpath = m_media[name].path;
2390 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2391 if(fis.good() == false){
2392 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2393 <<tpath<<"\" for reading"<<std::endl;
2396 std::ostringstream tmp_os(std::ios_base::binary);
2400 fis.read(buf, 1024);
2401 std::streamsize len = fis.gcount();
2402 tmp_os.write(buf, len);
2403 file_size_bunch_total += len;
2412 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2413 <<name<<"\""<<std::endl;
2416 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2417 <<tname<<"\""<<std::endl;*/
2419 file_bunches[file_bunches.size()-1].push_back(
2420 SendableMedia(name, tpath, tmp_os.str()));
2422 // Start next bunch if got enough data
2423 if(file_size_bunch_total >= bytes_per_bunch) {
2424 file_bunches.push_back(std::vector<SendableMedia>());
2425 file_size_bunch_total = 0;
2430 /* Create and send packets */
2432 u16 num_bunches = file_bunches.size();
2433 for(u16 i = 0; i < num_bunches; i++) {
2436 u16 total number of texture bunches
2437 u16 index of this bunch
2438 u32 number of files in this bunch
2447 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2448 pkt << num_bunches << i << (u32) file_bunches[i].size();
2450 for(std::vector<SendableMedia>::iterator
2451 j = file_bunches[i].begin();
2452 j != file_bunches[i].end(); ++j) {
2454 pkt.putLongString(j->data);
2457 verbosestream << "Server::sendRequestedMedia(): bunch "
2458 << i << "/" << num_bunches
2459 << " files=" << file_bunches[i].size()
2460 << " size=" << pkt.getSize() << std::endl;
2465 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2467 if(m_detached_inventories.count(name) == 0) {
2468 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2471 Inventory *inv = m_detached_inventories[name];
2472 std::ostringstream os(std::ios_base::binary);
2474 os << serializeString(name);
2478 std::string s = os.str();
2480 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2481 pkt.putRawString(s.c_str(), s.size());
2483 if (peer_id != PEER_ID_INEXISTENT) {
2487 m_clients.sendToAll(0, &pkt, true);
2491 void Server::sendDetachedInventories(u16 peer_id)
2493 DSTACK(__FUNCTION_NAME);
2495 for(std::map<std::string, Inventory*>::iterator
2496 i = m_detached_inventories.begin();
2497 i != m_detached_inventories.end(); i++) {
2498 const std::string &name = i->first;
2499 //Inventory *inv = i->second;
2500 sendDetachedInventory(name, peer_id);
2508 void Server::DiePlayer(u16 peer_id)
2510 DSTACK(__FUNCTION_NAME);
2512 PlayerSAO *playersao = getPlayerSAO(peer_id);
2515 infostream << "Server::DiePlayer(): Player "
2516 << playersao->getPlayer()->getName()
2517 << " dies" << std::endl;
2519 playersao->setHP(0);
2521 // Trigger scripted stuff
2522 m_script->on_dieplayer(playersao);
2524 SendPlayerHP(peer_id);
2525 SendDeathscreen(peer_id, false, v3f(0,0,0));
2528 void Server::RespawnPlayer(u16 peer_id)
2530 DSTACK(__FUNCTION_NAME);
2532 PlayerSAO *playersao = getPlayerSAO(peer_id);
2535 infostream << "Server::RespawnPlayer(): Player "
2536 << playersao->getPlayer()->getName()
2537 << " respawns" << std::endl;
2539 playersao->setHP(PLAYER_MAX_HP);
2540 playersao->setBreath(PLAYER_MAX_BREATH);
2542 SendPlayerHP(peer_id);
2543 SendPlayerBreath(peer_id);
2545 bool repositioned = m_script->on_respawnplayer(playersao);
2547 v3f pos = findSpawnPos();
2548 // setPos will send the new position to client
2549 playersao->setPos(pos);
2552 void Server::DenySudoAccess(u16 peer_id)
2554 DSTACK(__FUNCTION_NAME);
2556 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2560 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2562 DSTACK(__FUNCTION_NAME);
2564 SendAccessDenied(peer_id, reason, custom_reason);
2565 m_clients.event(peer_id, CSE_SetDenied);
2566 m_con.DisconnectPeer(peer_id);
2569 // 13/03/15: remove this function when protocol version 25 will become
2570 // the minimum version for MT users, maybe in 1 year
2571 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2573 DSTACK(__FUNCTION_NAME);
2575 SendAccessDenied_Legacy(peer_id, reason);
2576 m_clients.event(peer_id, CSE_SetDenied);
2577 m_con.DisconnectPeer(peer_id);
2580 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2582 DSTACK(__FUNCTION_NAME);
2585 RemoteClient* client = getClient(peer_id, CS_Invalid);
2587 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2589 // Right now, the auth mechs don't change between login and sudo mode.
2590 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2591 client->allowed_sudo_mechs = sudo_auth_mechs;
2593 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2594 << g_settings->getFloat("dedicated_server_step")
2598 m_clients.event(peer_id, CSE_AuthAccept);
2600 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2602 // We only support SRP right now
2603 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2605 resp_pkt << sudo_auth_mechs;
2607 m_clients.event(peer_id, CSE_SudoSuccess);
2611 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2613 DSTACK(__FUNCTION_NAME);
2614 std::wstring message;
2617 Clear references to playing sounds
2619 for(std::map<s32, ServerPlayingSound>::iterator
2620 i = m_playing_sounds.begin();
2621 i != m_playing_sounds.end();)
2623 ServerPlayingSound &psound = i->second;
2624 psound.clients.erase(peer_id);
2625 if(psound.clients.empty())
2626 m_playing_sounds.erase(i++);
2631 Player *player = m_env->getPlayer(peer_id);
2633 // Collect information about leaving in chat
2635 if(player != NULL && reason != CDR_DENY)
2637 std::wstring name = narrow_to_wide(player->getName());
2640 message += L" left the game.";
2641 if(reason == CDR_TIMEOUT)
2642 message += L" (timed out)";
2646 /* Run scripts and remove from environment */
2650 PlayerSAO *playersao = player->getPlayerSAO();
2653 m_script->on_leaveplayer(playersao);
2655 playersao->disconnected();
2663 if(player != NULL && reason != CDR_DENY) {
2664 std::ostringstream os(std::ios_base::binary);
2665 std::vector<u16> clients = m_clients.getClientIDs();
2667 for(std::vector<u16>::iterator i = clients.begin();
2668 i != clients.end(); ++i) {
2670 Player *player = m_env->getPlayer(*i);
2674 // Get name of player
2675 os << player->getName() << " ";
2678 actionstream << player->getName() << " "
2679 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2680 << " List of players: " << os.str() << std::endl;
2684 JMutexAutoLock env_lock(m_env_mutex);
2685 m_clients.DeleteClient(peer_id);
2689 // Send leave chat message to all remaining clients
2690 if(message.length() != 0)
2691 SendChatMessage(PEER_ID_INEXISTENT,message);
2694 void Server::UpdateCrafting(Player* player)
2696 DSTACK(__FUNCTION_NAME);
2698 // Get a preview for crafting
2700 InventoryLocation loc;
2701 loc.setPlayer(player->getName());
2702 std::vector<ItemStack> output_replacements;
2703 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2704 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2706 // Put the new preview in
2707 InventoryList *plist = player->inventory.getList("craftpreview");
2708 sanity_check(plist);
2709 sanity_check(plist->getSize() >= 1);
2710 plist->changeItem(0, preview);
2713 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2715 RemoteClient *client = getClientNoEx(peer_id,state_min);
2717 throw ClientNotFoundException("Client not found");
2721 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2723 return m_clients.getClientNoEx(peer_id, state_min);
2726 std::string Server::getPlayerName(u16 peer_id)
2728 Player *player = m_env->getPlayer(peer_id);
2730 return "[id="+itos(peer_id)+"]";
2731 return player->getName();
2734 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2736 Player *player = m_env->getPlayer(peer_id);
2739 return player->getPlayerSAO();
2742 std::wstring Server::getStatusString()
2744 std::wostringstream os(std::ios_base::binary);
2747 os<<L"version="<<narrow_to_wide(g_version_string);
2749 os<<L", uptime="<<m_uptime.get();
2751 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2752 // Information about clients
2755 std::vector<u16> clients = m_clients.getClientIDs();
2756 for(std::vector<u16>::iterator i = clients.begin();
2757 i != clients.end(); ++i) {
2759 Player *player = m_env->getPlayer(*i);
2760 // Get name of player
2761 std::wstring name = L"unknown";
2763 name = narrow_to_wide(player->getName());
2764 // Add name to information string
2772 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2773 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2774 if(g_settings->get("motd") != "")
2775 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2779 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2781 std::set<std::string> privs;
2782 m_script->getAuth(name, NULL, &privs);
2786 bool Server::checkPriv(const std::string &name, const std::string &priv)
2788 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2789 return (privs.count(priv) != 0);
2792 void Server::reportPrivsModified(const std::string &name)
2795 std::vector<u16> clients = m_clients.getClientIDs();
2796 for(std::vector<u16>::iterator i = clients.begin();
2797 i != clients.end(); ++i) {
2798 Player *player = m_env->getPlayer(*i);
2799 reportPrivsModified(player->getName());
2802 Player *player = m_env->getPlayer(name.c_str());
2805 SendPlayerPrivileges(player->peer_id);
2806 PlayerSAO *sao = player->getPlayerSAO();
2809 sao->updatePrivileges(
2810 getPlayerEffectivePrivs(name),
2815 void Server::reportInventoryFormspecModified(const std::string &name)
2817 Player *player = m_env->getPlayer(name.c_str());
2820 SendPlayerInventoryFormspec(player->peer_id);
2823 void Server::setIpBanned(const std::string &ip, const std::string &name)
2825 m_banmanager->add(ip, name);
2828 void Server::unsetIpBanned(const std::string &ip_or_name)
2830 m_banmanager->remove(ip_or_name);
2833 std::string Server::getBanDescription(const std::string &ip_or_name)
2835 return m_banmanager->getBanDescription(ip_or_name);
2838 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2840 Player *player = m_env->getPlayer(name);
2844 if (player->peer_id == PEER_ID_INEXISTENT)
2847 SendChatMessage(player->peer_id, msg);
2850 bool Server::showFormspec(const char *playername, const std::string &formspec,
2851 const std::string &formname)
2853 Player *player = m_env->getPlayer(playername);
2857 SendShowFormspecMessage(player->peer_id, formspec, formname);
2861 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)
2893 SendHUDChange(player->peer_id, id, stat, data);
2897 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2902 SendHUDSetFlags(player->peer_id, flags, mask);
2903 player->hud_flags = flags;
2905 PlayerSAO* playersao = player->getPlayerSAO();
2907 if (playersao == NULL)
2910 m_script->player_event(playersao, "hud_changed");
2914 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2918 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2921 player->setHotbarItemcount(hotbar_itemcount);
2922 std::ostringstream os(std::ios::binary);
2923 writeS32(os, hotbar_itemcount);
2924 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2928 s32 Server::hudGetHotbarItemcount(Player *player)
2932 return player->getHotbarItemcount();
2935 void Server::hudSetHotbarImage(Player *player, std::string name)
2940 player->setHotbarImage(name);
2941 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2944 std::string Server::hudGetHotbarImage(Player *player)
2948 return player->getHotbarImage();
2951 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2956 player->setHotbarSelectedImage(name);
2957 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2960 std::string Server::hudGetHotbarSelectedImage(Player *player)
2965 return player->getHotbarSelectedImage();
2968 bool Server::setLocalPlayerAnimations(Player *player,
2969 v2s32 animation_frames[4], f32 frame_speed)
2974 player->setLocalAnimations(animation_frames, frame_speed);
2975 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2979 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2984 player->eye_offset_first = first;
2985 player->eye_offset_third = third;
2986 SendEyeOffset(player->peer_id, first, third);
2990 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2991 const std::string &type, const std::vector<std::string> ¶ms)
2996 player->setSky(bgcolor, type, params);
2997 SendSetSky(player->peer_id, bgcolor, type, params);
3001 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3007 player->overrideDayNightRatio(do_override, ratio);
3008 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3012 void Server::notifyPlayers(const std::wstring &msg)
3014 SendChatMessage(PEER_ID_INEXISTENT,msg);
3017 void Server::spawnParticle(const char *playername, v3f pos,
3018 v3f velocity, v3f acceleration,
3019 float expirationtime, float size, bool
3020 collisiondetection, bool vertical, const std::string &texture)
3022 Player *player = m_env->getPlayer(playername);
3025 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3026 expirationtime, size, collisiondetection, vertical, texture);
3029 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3030 float expirationtime, float size,
3031 bool collisiondetection, bool vertical, const std::string &texture)
3033 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3034 expirationtime, size, collisiondetection, vertical, texture);
3037 u32 Server::addParticleSpawner(const char *playername, u16 amount, float spawntime,
3038 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3039 float minexptime, float maxexptime, float minsize, float maxsize,
3040 bool collisiondetection, bool vertical, const std::string &texture)
3042 Player *player = m_env->getPlayer(playername);
3047 for(;;) // look for unused particlespawner id
3050 if (std::find(m_particlespawner_ids.begin(),
3051 m_particlespawner_ids.end(), id)
3052 == m_particlespawner_ids.end())
3054 m_particlespawner_ids.push_back(id);
3059 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3060 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3061 minexptime, maxexptime, minsize, maxsize,
3062 collisiondetection, vertical, texture, id);
3067 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3068 v3f minpos, v3f maxpos,
3069 v3f minvel, v3f maxvel,
3070 v3f minacc, v3f maxacc,
3071 float minexptime, float maxexptime,
3072 float minsize, float maxsize,
3073 bool collisiondetection, bool vertical, const std::string &texture)
3076 for(;;) // look for unused particlespawner id
3079 if (std::find(m_particlespawner_ids.begin(),
3080 m_particlespawner_ids.end(), id)
3081 == m_particlespawner_ids.end())
3083 m_particlespawner_ids.push_back(id);
3088 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3089 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3090 minexptime, maxexptime, minsize, maxsize,
3091 collisiondetection, vertical, texture, id);
3096 void Server::deleteParticleSpawner(const char *playername, u32 id)
3098 Player *player = m_env->getPlayer(playername);
3102 m_particlespawner_ids.erase(
3103 std::remove(m_particlespawner_ids.begin(),
3104 m_particlespawner_ids.end(), id),
3105 m_particlespawner_ids.end());
3106 SendDeleteParticleSpawner(player->peer_id, id);
3109 void Server::deleteParticleSpawnerAll(u32 id)
3111 m_particlespawner_ids.erase(
3112 std::remove(m_particlespawner_ids.begin(),
3113 m_particlespawner_ids.end(), id),
3114 m_particlespawner_ids.end());
3115 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3118 Inventory* Server::createDetachedInventory(const std::string &name)
3120 if(m_detached_inventories.count(name) > 0){
3121 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3122 delete m_detached_inventories[name];
3124 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3126 Inventory *inv = new Inventory(m_itemdef);
3128 m_detached_inventories[name] = inv;
3129 //TODO find a better way to do this
3130 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3134 // actions: time-reversed list
3135 // Return value: success/failure
3136 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3137 std::list<std::string> *log)
3139 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3140 ServerMap *map = (ServerMap*)(&m_env->getMap());
3142 // Fail if no actions to handle
3143 if(actions.empty()){
3144 log->push_back("Nothing to do.");
3151 for(std::list<RollbackAction>::const_iterator
3152 i = actions.begin();
3153 i != actions.end(); i++)
3155 const RollbackAction &action = *i;
3157 bool success = action.applyRevert(map, this, this);
3160 std::ostringstream os;
3161 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3162 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3164 log->push_back(os.str());
3166 std::ostringstream os;
3167 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3168 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3170 log->push_back(os.str());
3174 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3175 <<" failed"<<std::endl;
3177 // Call it done if less than half failed
3178 return num_failed <= num_tried/2;
3181 // IGameDef interface
3183 IItemDefManager *Server::getItemDefManager()
3188 INodeDefManager *Server::getNodeDefManager()
3193 ICraftDefManager *Server::getCraftDefManager()
3197 ITextureSource *Server::getTextureSource()
3201 IShaderSource *Server::getShaderSource()
3205 scene::ISceneManager *Server::getSceneManager()
3210 u16 Server::allocateUnknownNodeId(const std::string &name)
3212 return m_nodedef->allocateDummy(name);
3215 ISoundManager *Server::getSoundManager()
3217 return &dummySoundManager;
3220 MtEventManager *Server::getEventManager()
3225 IWritableItemDefManager *Server::getWritableItemDefManager()
3230 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3235 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3240 const ModSpec *Server::getModSpec(const std::string &modname) const
3242 std::vector<ModSpec>::const_iterator it;
3243 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3244 const ModSpec &mod = *it;
3245 if (mod.name == modname)
3251 void Server::getModNames(std::vector<std::string> &modlist)
3253 std::vector<ModSpec>::iterator it;
3254 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3255 modlist.push_back(it->name);
3258 std::string Server::getBuiltinLuaPath()
3260 return porting::path_share + DIR_DELIM + "builtin";
3263 v3f Server::findSpawnPos()
3265 ServerMap &map = m_env->getServerMap();
3267 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3268 return nodeposf * BS;
3271 // Default position is static_spawnpoint
3272 // We will return it if we don't found a good place
3273 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3275 s16 water_level = map.getWaterLevel();
3277 bool is_good = false;
3279 // Try to find a good place a few times
3280 for(s32 i = 0; i < 1000 && !is_good; i++) {
3282 // We're going to try to throw the player to this position
3283 v2s16 nodepos2d = v2s16(
3284 -range + (myrand() % (range * 2)),
3285 -range + (myrand() % (range * 2)));
3287 // Get ground height at point
3288 s16 groundheight = map.findGroundLevel(nodepos2d);
3289 if (groundheight <= water_level) // Don't go underwater
3291 if (groundheight > water_level + 6) // Don't go to high places
3294 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3297 for (s32 i = 0; i < 10; i++) {
3298 v3s16 blockpos = getNodeBlockPos(nodepos);
3299 map.emergeBlock(blockpos, true);
3300 content_t c = map.getNodeNoEx(nodepos).getContent();
3301 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3303 if (air_count >= 2){
3312 return intToFloat(nodepos, BS);
3315 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3317 bool newplayer = false;
3320 Try to get an existing player
3322 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3324 // If player is already connected, cancel
3325 if(player != NULL && player->peer_id != 0)
3327 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3332 If player with the wanted peer_id already exists, cancel.
3334 if(m_env->getPlayer(peer_id) != NULL)
3336 infostream<<"emergePlayer(): Player with wrong name but same"
3337 " peer_id already exists"<<std::endl;
3341 // Load player if it isn't already loaded
3343 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3346 // Create player if it doesn't exist
3349 player = new RemotePlayer(this, name);
3350 // Set player position
3351 infostream<<"Server: Finding spawn place for player \""
3352 <<name<<"\""<<std::endl;
3353 v3f pos = findSpawnPos();
3354 player->setPosition(pos);
3356 // Make sure the player is saved
3357 player->setModified(true);
3359 // Add player to environment
3360 m_env->addPlayer(player);
3363 // Create a new player active object
3364 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3365 getPlayerEffectivePrivs(player->getName()),
3368 /* Clean up old HUD elements from previous sessions */
3371 /* Add object to environment */
3372 m_env->addActiveObject(playersao);
3376 m_script->on_newplayer(playersao);
3382 void dedicated_server_loop(Server &server, bool &kill)
3384 DSTACK(__FUNCTION_NAME);
3386 verbosestream<<"dedicated_server_loop()"<<std::endl;
3388 IntervalLimiter m_profiler_interval;
3392 float steplen = g_settings->getFloat("dedicated_server_step");
3393 // This is kind of a hack but can be done like this
3394 // because server.step() is very light
3396 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3397 sleep_ms((int)(steplen*1000.0));
3399 server.step(steplen);
3401 if(server.getShutdownRequested() || kill)
3403 infostream<<"Dedicated server quitting"<<std::endl;
3405 if(g_settings->getBool("server_announce"))
3406 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3414 float profiler_print_interval =
3415 g_settings->getFloat("profiler_print_interval");
3416 if(profiler_print_interval != 0)
3418 if(m_profiler_interval.step(steplen, profiler_print_interval))
3420 infostream<<"Profiler:"<<std::endl;
3421 g_profiler->print(infostream);
3422 g_profiler->clear();