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()) {
104 //TimeTaker timer("AsyncRunStep() + Receive()");
106 m_server->AsyncRunStep();
110 } catch (con::NoIncomingDataException &e) {
111 } catch (con::PeerNotFoundException &e) {
112 infostream<<"Server: PeerNotFoundException"<<std::endl;
113 } catch (ClientNotFoundException &e) {
114 } catch (con::ConnectionBindFailed &e) {
115 m_server->setAsyncFatalError(e.what());
116 } catch (LuaError &e) {
117 m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
121 END_DEBUG_EXCEPTION_HANDLER(errorstream)
126 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
128 if(pos_exists) *pos_exists = false;
133 if(pos_exists) *pos_exists = true;
138 ServerActiveObject *sao = env->getActiveObject(object);
141 if(pos_exists) *pos_exists = true;
142 return sao->getBasePosition(); }
154 const std::string &path_world,
155 const SubgameSpec &gamespec,
156 bool simple_singleplayer_mode,
159 m_path_world(path_world),
160 m_gamespec(gamespec),
161 m_simple_singleplayer_mode(simple_singleplayer_mode),
162 m_async_fatal_error(""),
171 m_enable_rollback_recording(false),
174 m_itemdef(createItemDefManager()),
175 m_nodedef(createNodeDefManager()),
176 m_craftdef(createCraftDefManager()),
177 m_event(new EventManager()),
179 m_time_of_day_send_timer(0),
182 m_shutdown_requested(false),
183 m_shutdown_ask_reconnect(false),
184 m_ignore_map_edit_events(false),
185 m_ignore_map_edit_events_peer_id(0),
189 m_liquid_transform_timer = 0.0;
190 m_liquid_transform_every = 1.0;
191 m_print_info_timer = 0.0;
192 m_masterserver_timer = 0.0;
193 m_objectdata_timer = 0.0;
194 m_emergethread_trigger_timer = 0.0;
195 m_savemap_timer = 0.0;
198 m_lag = g_settings->getFloat("dedicated_server_step");
201 throw ServerError("Supplied empty world path");
203 if(!gamespec.isValid())
204 throw ServerError("Supplied invalid gamespec");
206 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
207 if(m_simple_singleplayer_mode)
208 infostream<<" in simple singleplayer mode"<<std::endl;
210 infostream<<std::endl;
211 infostream<<"- world: "<<m_path_world<<std::endl;
212 infostream<<"- game: "<<m_gamespec.path<<std::endl;
214 // Create world if it doesn't exist
215 if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
216 throw ServerError("Failed to initialize world");
218 // Create server thread
219 m_thread = new ServerThread(this);
221 // Create emerge manager
222 m_emerge = new EmergeManager(this);
224 // Create ban manager
225 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
226 m_banmanager = new BanManager(ban_path);
228 ModConfiguration modconf(m_path_world);
229 m_mods = modconf.getMods();
230 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
231 // complain about mods with unsatisfied dependencies
232 if(!modconf.isConsistent()) {
233 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
234 it != unsatisfied_mods.end(); ++it) {
236 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
237 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
238 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
239 errorstream << " \"" << *dep_it << "\"";
240 errorstream << std::endl;
244 Settings worldmt_settings;
245 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
246 worldmt_settings.readConfigFile(worldmt.c_str());
247 std::vector<std::string> names = worldmt_settings.getNames();
248 std::set<std::string> load_mod_names;
249 for(std::vector<std::string>::iterator it = names.begin();
250 it != names.end(); ++it) {
251 std::string name = *it;
252 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
253 load_mod_names.insert(name.substr(9));
255 // complain about mods declared to be loaded, but not found
256 for(std::vector<ModSpec>::iterator it = m_mods.begin();
257 it != m_mods.end(); ++it)
258 load_mod_names.erase((*it).name);
259 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
260 it != unsatisfied_mods.end(); ++it)
261 load_mod_names.erase((*it).name);
262 if(!load_mod_names.empty()) {
263 errorstream << "The following mods could not be found:";
264 for(std::set<std::string>::iterator it = load_mod_names.begin();
265 it != load_mod_names.end(); ++it)
266 errorstream << " \"" << (*it) << "\"";
267 errorstream << std::endl;
271 JMutexAutoLock envlock(m_env_mutex);
273 // Load mapgen params from Settings
274 m_emerge->loadMapgenParams();
276 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
277 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
279 // Initialize scripting
280 infostream<<"Server: Initializing Lua"<<std::endl;
282 m_script = new GameScripting(this);
284 std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
285 std::string error_msg;
287 if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
288 throw ModError("Failed to load and run " + script_path
289 + "\nError from Lua:\n" + error_msg);
292 infostream << "Server: Loading mods: ";
293 for(std::vector<ModSpec>::iterator i = m_mods.begin();
294 i != m_mods.end(); i++) {
295 const ModSpec &mod = *i;
296 infostream << mod.name << " ";
298 infostream << std::endl;
299 // Load and run "mod" scripts
300 for (std::vector<ModSpec>::iterator i = m_mods.begin();
301 i != m_mods.end(); i++) {
302 const ModSpec &mod = *i;
303 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
304 std::ostringstream err;
305 err << "Error loading mod \"" << mod.name
306 << "\": mod_name does not follow naming conventions: "
307 << "Only chararacters [a-z0-9_] are allowed." << std::endl;
308 errorstream << err.str().c_str();
309 throw ModError(err.str());
311 std::string script_path = mod.path + DIR_DELIM "init.lua";
312 infostream << " [" << padStringRight(mod.name, 12) << "] [\""
313 << script_path << "\"]" << std::endl;
314 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
315 errorstream << "Server: Failed to load and run "
316 << script_path << std::endl;
317 throw ModError("Failed to load and run " + script_path
318 + "\nError from Lua:\n" + error_msg);
322 // Read Textures and calculate sha1 sums
325 // Apply item aliases in the node definition manager
326 m_nodedef->updateAliases(m_itemdef);
328 // Apply texture overrides from texturepack/override.txt
329 std::string texture_path = g_settings->get("texture_path");
330 if (texture_path != "" && fs::IsDir(texture_path))
331 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
333 m_nodedef->setNodeRegistrationStatus(true);
335 // Perform pending node name resolutions
336 m_nodedef->runNodeResolveCallbacks();
338 // init the recipe hashes to speed up crafting
339 m_craftdef->initHashes(this);
341 // Initialize Environment
342 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
344 m_clients.setEnv(m_env);
346 // Initialize mapgens
347 m_emerge->initMapgens();
349 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
350 if (m_enable_rollback_recording) {
351 // Create rollback manager
352 m_rollback = new RollbackManager(m_path_world, this);
355 // Give environment reference to scripting api
356 m_script->initializeEnvironment(m_env);
358 // Register us to receive map edit events
359 servermap->addEventReceiver(this);
361 // If file exists, load environment metadata
362 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
364 infostream<<"Server: Loading environment metadata"<<std::endl;
368 // Add some test ActiveBlockModifiers to environment
369 add_legacy_abms(m_env, m_nodedef);
371 m_liquid_transform_every = g_settings->getFloat("liquid_update");
376 infostream<<"Server destructing"<<std::endl;
378 // Send shutdown message
379 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
382 JMutexAutoLock envlock(m_env_mutex);
384 // Execute script shutdown hooks
385 m_script->on_shutdown();
387 infostream << "Server: Saving players" << std::endl;
388 m_env->saveLoadedPlayers();
390 infostream << "Server: Kicking players" << std::endl;
391 std::string kick_msg;
392 bool reconnect = false;
393 if (getShutdownRequested()) {
394 reconnect = m_shutdown_ask_reconnect;
395 kick_msg = m_shutdown_msg;
397 if (kick_msg == "") {
398 kick_msg = g_settings->get("kick_msg_shutdown");
400 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
401 kick_msg, reconnect);
403 infostream << "Server: Saving environment metadata" << std::endl;
411 // stop all emerge threads before deleting players that may have
412 // requested blocks to be emerged
413 m_emerge->stopThreads();
415 // Delete things in the reverse order of creation
418 // N.B. the EmergeManager should be deleted after the Environment since Map
419 // depends on EmergeManager to write its current params to the map meta
428 // Deinitialize scripting
429 infostream<<"Server: Deinitializing scripting"<<std::endl;
432 // Delete detached inventories
433 for (std::map<std::string, Inventory*>::iterator
434 i = m_detached_inventories.begin();
435 i != m_detached_inventories.end(); i++) {
440 void Server::start(Address bind_addr)
442 DSTACK(__FUNCTION_NAME);
444 m_bind_addr = bind_addr;
446 infostream<<"Starting server on "
447 << bind_addr.serializeString() <<"..."<<std::endl;
449 // Stop thread if already running
452 // Initialize connection
453 m_con.SetTimeoutMs(30);
454 m_con.Serve(bind_addr);
459 // ASCII art for the win!
461 <<" .__ __ __ "<<std::endl
462 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
463 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
464 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
465 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
466 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
467 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
468 actionstream<<"Server for gameid=\""<<m_gamespec.id
469 <<"\" listening on "<<bind_addr.serializeString()<<":"
470 <<bind_addr.getPort() << "."<<std::endl;
475 DSTACK(__FUNCTION_NAME);
477 infostream<<"Server: Stopping and waiting threads"<<std::endl;
479 // Stop threads (set run=false first so both start stopping)
481 //m_emergethread.setRun(false);
483 //m_emergethread.stop();
485 infostream<<"Server: Threads stopped"<<std::endl;
488 void Server::step(float dtime)
490 DSTACK(__FUNCTION_NAME);
495 JMutexAutoLock lock(m_step_dtime_mutex);
496 m_step_dtime += dtime;
498 // Throw if fatal error occurred in thread
499 std::string async_err = m_async_fatal_error.get();
500 if(async_err != "") {
501 if (m_simple_singleplayer_mode) {
502 throw ServerError(async_err);
505 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
506 g_settings->get("kick_msg_crash"),
507 g_settings->getBool("ask_reconnect_on_crash"));
508 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
509 << "Please fix the following error:" << std::endl
510 << async_err << std::endl;
511 FATAL_ERROR(async_err.c_str());
516 void Server::AsyncRunStep(bool initial_step)
518 DSTACK(__FUNCTION_NAME);
520 g_profiler->add("Server::AsyncRunStep (num)", 1);
524 JMutexAutoLock lock1(m_step_dtime_mutex);
525 dtime = m_step_dtime;
529 // Send blocks to clients
533 if((dtime < 0.001) && (initial_step == false))
536 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
538 //infostream<<"Server steps "<<dtime<<std::endl;
539 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
542 JMutexAutoLock lock1(m_step_dtime_mutex);
543 m_step_dtime -= dtime;
550 m_uptime.set(m_uptime.get() + dtime);
556 Update time of day and overall game time
558 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
561 Send to clients at constant intervals
564 m_time_of_day_send_timer -= dtime;
565 if(m_time_of_day_send_timer < 0.0) {
566 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
567 u16 time = m_env->getTimeOfDay();
568 float time_speed = g_settings->getFloat("time_speed");
569 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
573 JMutexAutoLock lock(m_env_mutex);
574 // Figure out and report maximum lag to environment
575 float max_lag = m_env->getMaxLagEstimate();
576 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
578 if(dtime > 0.1 && dtime > max_lag * 2.0)
579 infostream<<"Server: Maximum lag peaked to "<<dtime
583 m_env->reportMaxLagEstimate(max_lag);
585 ScopeProfiler sp(g_profiler, "SEnv step");
586 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
590 static const float map_timer_and_unload_dtime = 2.92;
591 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
593 JMutexAutoLock lock(m_env_mutex);
594 // Run Map's timers and unload unused data
595 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
596 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
597 g_settings->getFloat("server_unload_unused_data_timeout"));
604 /* Transform liquids */
605 m_liquid_transform_timer += dtime;
606 if(m_liquid_transform_timer >= m_liquid_transform_every)
608 m_liquid_transform_timer -= m_liquid_transform_every;
610 JMutexAutoLock lock(m_env_mutex);
612 ScopeProfiler sp(g_profiler, "Server: liquid transform");
614 std::map<v3s16, MapBlock*> modified_blocks;
615 m_env->getMap().transformLiquids(modified_blocks);
620 core::map<v3s16, MapBlock*> lighting_modified_blocks;
621 ServerMap &map = ((ServerMap&)m_env->getMap());
622 map.updateLighting(modified_blocks, lighting_modified_blocks);
624 // Add blocks modified by lighting to modified_blocks
625 for(core::map<v3s16, MapBlock*>::Iterator
626 i = lighting_modified_blocks.getIterator();
627 i.atEnd() == false; i++)
629 MapBlock *block = i.getNode()->getValue();
630 modified_blocks.insert(block->getPos(), block);
634 Set the modified blocks unsent for all the clients
636 if(!modified_blocks.empty())
638 SetBlocksNotSent(modified_blocks);
641 m_clients.step(dtime);
643 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
645 // send masterserver announce
647 float &counter = m_masterserver_timer;
648 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
649 g_settings->getBool("server_announce"))
651 ServerList::sendAnnounce(counter ? "update" : "start",
652 m_bind_addr.getPort(),
653 m_clients.getPlayerNames(),
655 m_env->getGameTime(),
658 m_emerge->params.mg_name,
667 Check added and deleted active objects
670 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
671 JMutexAutoLock envlock(m_env_mutex);
674 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
675 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
677 // Radius inside which objects are active
678 s16 radius = g_settings->getS16("active_object_send_range_blocks");
679 s16 player_radius = g_settings->getS16("player_transfer_distance");
681 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
682 !g_settings->getBool("unlimited_player_transfer_distance"))
683 player_radius = radius;
685 radius *= MAP_BLOCKSIZE;
686 player_radius *= MAP_BLOCKSIZE;
688 for(std::map<u16, RemoteClient*>::iterator
690 i != clients.end(); ++i)
692 RemoteClient *client = i->second;
694 // If definitions and textures have not been sent, don't
695 // send objects either
696 if (client->getState() < CS_DefinitionsSent)
699 Player *player = m_env->getPlayer(client->peer_id);
702 // This can happen if the client timeouts somehow
703 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
705 <<" has no associated player"<<std::endl;*/
708 v3s16 pos = floatToInt(player->getPosition(), BS);
710 std::set<u16> removed_objects;
711 std::set<u16> added_objects;
712 m_env->getRemovedActiveObjects(pos, radius, player_radius,
713 client->m_known_objects, removed_objects);
714 m_env->getAddedActiveObjects(pos, radius, player_radius,
715 client->m_known_objects, added_objects);
717 // Ignore if nothing happened
718 if(removed_objects.empty() && added_objects.empty())
720 //infostream<<"active objects: none changed"<<std::endl;
724 std::string data_buffer;
728 // Handle removed objects
729 writeU16((u8*)buf, removed_objects.size());
730 data_buffer.append(buf, 2);
731 for(std::set<u16>::iterator
732 i = removed_objects.begin();
733 i != removed_objects.end(); ++i)
737 ServerActiveObject* obj = m_env->getActiveObject(id);
739 // Add to data buffer for sending
740 writeU16((u8*)buf, id);
741 data_buffer.append(buf, 2);
743 // Remove from known objects
744 client->m_known_objects.erase(id);
746 if(obj && obj->m_known_by_count > 0)
747 obj->m_known_by_count--;
750 // Handle added objects
751 writeU16((u8*)buf, added_objects.size());
752 data_buffer.append(buf, 2);
753 for(std::set<u16>::iterator
754 i = added_objects.begin();
755 i != added_objects.end(); ++i)
759 ServerActiveObject* obj = m_env->getActiveObject(id);
762 u8 type = ACTIVEOBJECT_TYPE_INVALID;
764 infostream<<"WARNING: "<<__FUNCTION_NAME
765 <<": NULL object"<<std::endl;
767 type = obj->getSendType();
769 // Add to data buffer for sending
770 writeU16((u8*)buf, id);
771 data_buffer.append(buf, 2);
772 writeU8((u8*)buf, type);
773 data_buffer.append(buf, 1);
776 data_buffer.append(serializeLongString(
777 obj->getClientInitializationData(client->net_proto_version)));
779 data_buffer.append(serializeLongString(""));
781 // Add to known objects
782 client->m_known_objects.insert(id);
785 obj->m_known_by_count++;
788 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
789 verbosestream << "Server: Sent object remove/add: "
790 << removed_objects.size() << " removed, "
791 << added_objects.size() << " added, "
792 << "packet size is " << pktSize << std::endl;
801 JMutexAutoLock envlock(m_env_mutex);
802 ScopeProfiler sp(g_profiler, "Server: sending object messages");
805 // Value = data sent by object
806 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
808 // Get active object messages from environment
810 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
814 std::vector<ActiveObjectMessage>* message_list = NULL;
815 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
816 n = buffered_messages.find(aom.id);
817 if (n == buffered_messages.end()) {
818 message_list = new std::vector<ActiveObjectMessage>;
819 buffered_messages[aom.id] = message_list;
822 message_list = n->second;
824 message_list->push_back(aom);
828 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
829 // Route data to every client
830 for (std::map<u16, RemoteClient*>::iterator
832 i != clients.end(); ++i) {
833 RemoteClient *client = i->second;
834 std::string reliable_data;
835 std::string unreliable_data;
836 // Go through all objects in message buffer
837 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
838 j = buffered_messages.begin();
839 j != buffered_messages.end(); ++j) {
840 // If object is not known by client, skip it
842 if (client->m_known_objects.find(id) == client->m_known_objects.end())
845 // Get message list of object
846 std::vector<ActiveObjectMessage>* list = j->second;
847 // Go through every message
848 for (std::vector<ActiveObjectMessage>::iterator
849 k = list->begin(); k != list->end(); ++k) {
850 // Compose the full new data with header
851 ActiveObjectMessage aom = *k;
852 std::string new_data;
855 writeU16((u8*)&buf[0], aom.id);
856 new_data.append(buf, 2);
858 new_data += serializeString(aom.datastring);
859 // Add data to buffer
861 reliable_data += new_data;
863 unreliable_data += new_data;
867 reliable_data and unreliable_data are now ready.
870 if(reliable_data.size() > 0) {
871 SendActiveObjectMessages(client->peer_id, reliable_data);
874 if(unreliable_data.size() > 0) {
875 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
880 // Clear buffered_messages
881 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
882 i = buffered_messages.begin();
883 i != buffered_messages.end(); ++i) {
889 Send queued-for-sending map edit events.
892 // We will be accessing the environment
893 JMutexAutoLock lock(m_env_mutex);
895 // Don't send too many at a time
898 // Single change sending is disabled if queue size is not small
899 bool disable_single_change_sending = false;
900 if(m_unsent_map_edit_queue.size() >= 4)
901 disable_single_change_sending = true;
903 int event_count = m_unsent_map_edit_queue.size();
905 // We'll log the amount of each
908 while(m_unsent_map_edit_queue.size() != 0)
910 MapEditEvent* event = m_unsent_map_edit_queue.front();
911 m_unsent_map_edit_queue.pop();
913 // Players far away from the change are stored here.
914 // Instead of sending the changes, MapBlocks are set not sent
916 std::vector<u16> far_players;
918 switch (event->type) {
921 prof.add("MEET_ADDNODE", 1);
922 sendAddNode(event->p, event->n, event->already_known_by_peer,
923 &far_players, disable_single_change_sending ? 5 : 30,
924 event->type == MEET_ADDNODE);
926 case MEET_REMOVENODE:
927 prof.add("MEET_REMOVENODE", 1);
928 sendRemoveNode(event->p, event->already_known_by_peer,
929 &far_players, disable_single_change_sending ? 5 : 30);
931 case MEET_BLOCK_NODE_METADATA_CHANGED:
932 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
933 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
934 setBlockNotSent(event->p);
937 infostream << "Server: MEET_OTHER" << std::endl;
938 prof.add("MEET_OTHER", 1);
939 for(std::set<v3s16>::iterator
940 i = event->modified_blocks.begin();
941 i != event->modified_blocks.end(); ++i) {
946 prof.add("unknown", 1);
947 infostream << "WARNING: Server: Unknown MapEditEvent "
948 << ((u32)event->type) << std::endl;
953 Set blocks not sent to far players
955 if(!far_players.empty()) {
956 // Convert list format to that wanted by SetBlocksNotSent
957 std::map<v3s16, MapBlock*> modified_blocks2;
958 for(std::set<v3s16>::iterator
959 i = event->modified_blocks.begin();
960 i != event->modified_blocks.end(); ++i) {
961 modified_blocks2[*i] =
962 m_env->getMap().getBlockNoCreateNoEx(*i);
965 // Set blocks not sent
966 for(std::vector<u16>::iterator
967 i = far_players.begin();
968 i != far_players.end(); ++i) {
969 if(RemoteClient *client = getClient(*i))
970 client->SetBlocksNotSent(modified_blocks2);
976 /*// Don't send too many at a time
978 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
982 if(event_count >= 5){
983 infostream<<"Server: MapEditEvents:"<<std::endl;
984 prof.print(infostream);
985 } else if(event_count != 0){
986 verbosestream<<"Server: MapEditEvents:"<<std::endl;
987 prof.print(verbosestream);
993 Trigger emergethread (it somehow gets to a non-triggered but
994 bysy state sometimes)
997 float &counter = m_emergethread_trigger_timer;
1003 m_emerge->startThreads();
1007 // Save map, players and auth stuff
1009 float &counter = m_savemap_timer;
1011 if(counter >= g_settings->getFloat("server_map_save_interval"))
1014 JMutexAutoLock lock(m_env_mutex);
1016 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1019 if (m_banmanager->isModified()) {
1020 m_banmanager->save();
1023 // Save changed parts of map
1024 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1027 m_env->saveLoadedPlayers();
1029 // Save environment metadata
1035 void Server::Receive()
1037 DSTACK(__FUNCTION_NAME);
1038 SharedBuffer<u8> data;
1042 m_con.Receive(&pkt);
1043 peer_id = pkt.getPeerId();
1046 catch(con::InvalidIncomingDataException &e) {
1047 infostream<<"Server::Receive(): "
1048 "InvalidIncomingDataException: what()="
1049 <<e.what()<<std::endl;
1051 catch(SerializationError &e) {
1052 infostream<<"Server::Receive(): "
1053 "SerializationError: what()="
1054 <<e.what()<<std::endl;
1056 catch(ClientStateError &e) {
1057 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1058 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1059 L"Try reconnecting or updating your client");
1061 catch(con::PeerNotFoundException &e) {
1066 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1068 std::string playername = "";
1069 PlayerSAO *playersao = NULL;
1072 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1073 if (client != NULL) {
1074 playername = client->getName();
1075 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1077 } catch (std::exception &e) {
1083 RemotePlayer *player =
1084 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1086 // If failed, cancel
1087 if ((playersao == NULL) || (player == NULL)) {
1088 if (player && player->peer_id != 0) {
1089 actionstream << "Server: Failed to emerge player \"" << playername
1090 << "\" (player allocated to an another client)" << std::endl;
1091 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1092 L"name. If your client closed unexpectedly, try again in "
1095 errorstream << "Server: " << playername << ": Failed to emerge player"
1097 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1103 Send complete position information
1105 SendMovePlayer(peer_id);
1108 SendPlayerPrivileges(peer_id);
1110 // Send inventory formspec
1111 SendPlayerInventoryFormspec(peer_id);
1114 SendInventory(playersao);
1117 SendPlayerHPOrDie(playersao);
1120 SendPlayerBreath(peer_id);
1122 // Show death screen if necessary
1123 if(player->isDead())
1124 SendDeathscreen(peer_id, false, v3f(0,0,0));
1126 // Note things in chat if not in simple singleplayer mode
1127 if(!m_simple_singleplayer_mode) {
1128 // Send information about server to player in chat
1129 SendChatMessage(peer_id, getStatusString());
1131 // Send information about joining in chat
1133 std::wstring name = L"unknown";
1134 Player *player = m_env->getPlayer(peer_id);
1136 name = narrow_to_wide(player->getName());
1138 std::wstring message;
1141 message += L" joined the game.";
1142 SendChatMessage(PEER_ID_INEXISTENT,message);
1145 Address addr = getPeerAddress(player->peer_id);
1146 std::string ip_str = addr.serializeString();
1147 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1152 std::vector<std::string> names = m_clients.getPlayerNames();
1154 actionstream<<player->getName() <<" joins game. List of players: ";
1156 for (std::vector<std::string>::iterator i = names.begin();
1157 i != names.end(); i++) {
1158 actionstream << *i << " ";
1161 actionstream << player->getName() <<std::endl;
1166 inline void Server::handleCommand(NetworkPacket* pkt)
1168 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1169 (this->*opHandle.handler)(pkt);
1172 void Server::ProcessData(NetworkPacket *pkt)
1174 DSTACK(__FUNCTION_NAME);
1175 // Environment is locked first.
1176 JMutexAutoLock envlock(m_env_mutex);
1178 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1179 u32 peer_id = pkt->getPeerId();
1182 Address address = getPeerAddress(peer_id);
1183 std::string addr_s = address.serializeString();
1185 if(m_banmanager->isIpBanned(addr_s)) {
1186 std::string ban_name = m_banmanager->getBanName(addr_s);
1187 infostream << "Server: A banned client tried to connect from "
1188 << addr_s << "; banned name was "
1189 << ban_name << std::endl;
1190 // This actually doesn't seem to transfer to the client
1191 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1192 + utf8_to_wide(ban_name));
1196 catch(con::PeerNotFoundException &e) {
1198 * no peer for this packet found
1199 * most common reason is peer timeout, e.g. peer didn't
1200 * respond for some time, your server was overloaded or
1203 infostream << "Server::ProcessData(): Canceling: peer "
1204 << peer_id << " not found" << std::endl;
1209 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1211 // Command must be handled into ToServerCommandHandler
1212 if (command >= TOSERVER_NUM_MSG_TYPES) {
1213 infostream << "Server: Ignoring unknown command "
1214 << command << std::endl;
1218 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1223 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1225 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1226 errorstream << "Server::ProcessData(): Cancelling: Peer"
1227 " serialization format invalid or not initialized."
1228 " Skipping incoming command=" << command << std::endl;
1232 /* Handle commands related to client startup */
1233 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1238 if (m_clients.getClientState(peer_id) < CS_Active) {
1239 if (command == TOSERVER_PLAYERPOS) return;
1241 errorstream << "Got packet command: " << command << " for peer id "
1242 << peer_id << " but client isn't active yet. Dropping packet "
1248 } catch (SendFailedException &e) {
1249 errorstream << "Server::ProcessData(): SendFailedException: "
1250 << "what=" << e.what()
1252 } catch (PacketError &e) {
1253 actionstream << "Server::ProcessData(): PacketError: "
1254 << "what=" << e.what()
1259 void Server::setTimeOfDay(u32 time)
1261 m_env->setTimeOfDay(time);
1262 m_time_of_day_send_timer = 0;
1265 void Server::onMapEditEvent(MapEditEvent *event)
1267 if(m_ignore_map_edit_events)
1269 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1271 MapEditEvent *e = event->clone();
1272 m_unsent_map_edit_queue.push(e);
1275 Inventory* Server::getInventory(const InventoryLocation &loc)
1278 case InventoryLocation::UNDEFINED:
1279 case InventoryLocation::CURRENT_PLAYER:
1281 case InventoryLocation::PLAYER:
1283 Player *player = m_env->getPlayer(loc.name.c_str());
1286 PlayerSAO *playersao = player->getPlayerSAO();
1289 return playersao->getInventory();
1292 case InventoryLocation::NODEMETA:
1294 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1297 return meta->getInventory();
1300 case InventoryLocation::DETACHED:
1302 if(m_detached_inventories.count(loc.name) == 0)
1304 return m_detached_inventories[loc.name];
1308 sanity_check(false); // abort
1313 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1316 case InventoryLocation::UNDEFINED:
1318 case InventoryLocation::PLAYER:
1323 Player *player = m_env->getPlayer(loc.name.c_str());
1326 PlayerSAO *playersao = player->getPlayerSAO();
1330 SendInventory(playersao);
1333 case InventoryLocation::NODEMETA:
1335 v3s16 blockpos = getNodeBlockPos(loc.p);
1337 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1339 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1341 setBlockNotSent(blockpos);
1344 case InventoryLocation::DETACHED:
1346 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1350 sanity_check(false); // abort
1355 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1357 std::vector<u16> clients = m_clients.getClientIDs();
1359 // Set the modified blocks unsent for all the clients
1360 for (std::vector<u16>::iterator i = clients.begin();
1361 i != clients.end(); ++i) {
1362 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1363 client->SetBlocksNotSent(block);
1368 void Server::peerAdded(con::Peer *peer)
1370 DSTACK(__FUNCTION_NAME);
1371 verbosestream<<"Server::peerAdded(): peer->id="
1372 <<peer->id<<std::endl;
1375 c.type = con::PEER_ADDED;
1376 c.peer_id = peer->id;
1378 m_peer_change_queue.push(c);
1381 void Server::deletingPeer(con::Peer *peer, bool timeout)
1383 DSTACK(__FUNCTION_NAME);
1384 verbosestream<<"Server::deletingPeer(): peer->id="
1385 <<peer->id<<", timeout="<<timeout<<std::endl;
1387 m_clients.event(peer->id, CSE_Disconnect);
1389 c.type = con::PEER_REMOVED;
1390 c.peer_id = peer->id;
1391 c.timeout = timeout;
1392 m_peer_change_queue.push(c);
1395 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1397 *retval = m_con.getPeerStat(peer_id,type);
1398 if (*retval == -1) return false;
1402 bool Server::getClientInfo(
1411 std::string* vers_string
1414 *state = m_clients.getClientState(peer_id);
1416 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1418 if (client == NULL) {
1423 *uptime = client->uptime();
1424 *ser_vers = client->serialization_version;
1425 *prot_vers = client->net_proto_version;
1427 *major = client->getMajor();
1428 *minor = client->getMinor();
1429 *patch = client->getPatch();
1430 *vers_string = client->getPatch();
1437 void Server::handlePeerChanges()
1439 while(m_peer_change_queue.size() > 0)
1441 con::PeerChange c = m_peer_change_queue.front();
1442 m_peer_change_queue.pop();
1444 verbosestream<<"Server: Handling peer change: "
1445 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1450 case con::PEER_ADDED:
1451 m_clients.CreateClient(c.peer_id);
1454 case con::PEER_REMOVED:
1455 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1459 FATAL_ERROR("Invalid peer change event received!");
1465 void Server::Send(NetworkPacket* pkt)
1467 m_clients.send(pkt->getPeerId(),
1468 clientCommandFactoryTable[pkt->getCommand()].channel,
1470 clientCommandFactoryTable[pkt->getCommand()].reliable);
1473 void Server::SendMovement(u16 peer_id)
1475 DSTACK(__FUNCTION_NAME);
1476 std::ostringstream os(std::ios_base::binary);
1478 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1480 pkt << g_settings->getFloat("movement_acceleration_default");
1481 pkt << g_settings->getFloat("movement_acceleration_air");
1482 pkt << g_settings->getFloat("movement_acceleration_fast");
1483 pkt << g_settings->getFloat("movement_speed_walk");
1484 pkt << g_settings->getFloat("movement_speed_crouch");
1485 pkt << g_settings->getFloat("movement_speed_fast");
1486 pkt << g_settings->getFloat("movement_speed_climb");
1487 pkt << g_settings->getFloat("movement_speed_jump");
1488 pkt << g_settings->getFloat("movement_liquid_fluidity");
1489 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1490 pkt << g_settings->getFloat("movement_liquid_sink");
1491 pkt << g_settings->getFloat("movement_gravity");
1496 void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
1498 if (!g_settings->getBool("enable_damage"))
1501 u16 peer_id = playersao->getPeerID();
1502 bool is_alive = playersao->getHP() > 0;
1505 SendPlayerHP(peer_id);
1510 void Server::SendHP(u16 peer_id, u8 hp)
1512 DSTACK(__FUNCTION_NAME);
1514 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1519 void Server::SendBreath(u16 peer_id, u16 breath)
1521 DSTACK(__FUNCTION_NAME);
1523 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1524 pkt << (u16) breath;
1528 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason,
1529 const std::string &custom_reason, bool reconnect)
1531 assert(reason < SERVER_ACCESSDENIED_MAX);
1533 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1535 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1536 pkt << custom_reason;
1537 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1538 reason == SERVER_ACCESSDENIED_CRASH)
1539 pkt << custom_reason << (u8)reconnect;
1543 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1545 DSTACK(__FUNCTION_NAME);
1547 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1552 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1553 v3f camera_point_target)
1555 DSTACK(__FUNCTION_NAME);
1557 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1558 pkt << set_camera_point_target << camera_point_target;
1562 void Server::SendItemDef(u16 peer_id,
1563 IItemDefManager *itemdef, u16 protocol_version)
1565 DSTACK(__FUNCTION_NAME);
1567 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1571 u32 length of the next item
1572 zlib-compressed serialized ItemDefManager
1574 std::ostringstream tmp_os(std::ios::binary);
1575 itemdef->serialize(tmp_os, protocol_version);
1576 std::ostringstream tmp_os2(std::ios::binary);
1577 compressZlib(tmp_os.str(), tmp_os2);
1578 pkt.putLongString(tmp_os2.str());
1581 verbosestream << "Server: Sending item definitions to id(" << peer_id
1582 << "): size=" << pkt.getSize() << std::endl;
1587 void Server::SendNodeDef(u16 peer_id,
1588 INodeDefManager *nodedef, u16 protocol_version)
1590 DSTACK(__FUNCTION_NAME);
1592 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1596 u32 length of the next item
1597 zlib-compressed serialized NodeDefManager
1599 std::ostringstream tmp_os(std::ios::binary);
1600 nodedef->serialize(tmp_os, protocol_version);
1601 std::ostringstream tmp_os2(std::ios::binary);
1602 compressZlib(tmp_os.str(), tmp_os2);
1604 pkt.putLongString(tmp_os2.str());
1607 verbosestream << "Server: Sending node definitions to id(" << peer_id
1608 << "): size=" << pkt.getSize() << std::endl;
1614 Non-static send methods
1617 void Server::SendInventory(PlayerSAO* playerSAO)
1619 DSTACK(__FUNCTION_NAME);
1621 UpdateCrafting(playerSAO->getPlayer());
1627 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1629 std::ostringstream os;
1630 playerSAO->getInventory()->serialize(os);
1632 std::string s = os.str();
1634 pkt.putRawString(s.c_str(), s.size());
1638 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1640 DSTACK(__FUNCTION_NAME);
1642 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1645 if (peer_id != PEER_ID_INEXISTENT) {
1649 m_clients.sendToAll(0, &pkt, true);
1653 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1654 const std::string &formname)
1656 DSTACK(__FUNCTION_NAME);
1658 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1660 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1666 // Spawns a particle on peer with peer_id
1667 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1668 float expirationtime, float size, bool collisiondetection,
1669 bool vertical, std::string texture)
1671 DSTACK(__FUNCTION_NAME);
1673 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1675 pkt << pos << velocity << acceleration << expirationtime
1676 << size << collisiondetection;
1677 pkt.putLongString(texture);
1680 if (peer_id != PEER_ID_INEXISTENT) {
1684 m_clients.sendToAll(0, &pkt, true);
1688 // Adds a ParticleSpawner on peer with peer_id
1689 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1690 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1691 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1693 DSTACK(__FUNCTION_NAME);
1695 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1697 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1698 << minacc << maxacc << minexptime << maxexptime << minsize
1699 << maxsize << collisiondetection;
1701 pkt.putLongString(texture);
1703 pkt << id << vertical;
1705 if (peer_id != PEER_ID_INEXISTENT) {
1709 m_clients.sendToAll(0, &pkt, true);
1713 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1715 DSTACK(__FUNCTION_NAME);
1717 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1719 // Ugly error in this packet
1722 if (peer_id != PEER_ID_INEXISTENT) {
1726 m_clients.sendToAll(0, &pkt, true);
1731 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1733 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1735 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1736 << form->text << form->number << form->item << form->dir
1737 << form->align << form->offset << form->world_pos << form->size;
1742 void Server::SendHUDRemove(u16 peer_id, u32 id)
1744 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1749 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1751 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1752 pkt << id << (u8) stat;
1756 case HUD_STAT_SCALE:
1757 case HUD_STAT_ALIGN:
1758 case HUD_STAT_OFFSET:
1759 pkt << *(v2f *) value;
1763 pkt << *(std::string *) value;
1765 case HUD_STAT_WORLD_POS:
1766 pkt << *(v3f *) value;
1769 pkt << *(v2s32 *) value;
1771 case HUD_STAT_NUMBER:
1775 pkt << *(u32 *) value;
1782 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1784 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1786 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1788 pkt << flags << mask;
1793 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1795 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1796 pkt << param << value;
1800 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1801 const std::string &type, const std::vector<std::string> ¶ms)
1803 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1804 pkt << bgcolor << type << (u16) params.size();
1806 for(size_t i=0; i<params.size(); i++)
1812 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1815 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1818 pkt << do_override << (u16) (ratio * 65535);
1823 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1825 DSTACK(__FUNCTION_NAME);
1827 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1828 pkt << time << time_speed;
1830 if (peer_id == PEER_ID_INEXISTENT) {
1831 m_clients.sendToAll(0, &pkt, true);
1838 void Server::SendPlayerHP(u16 peer_id)
1840 DSTACK(__FUNCTION_NAME);
1841 PlayerSAO *playersao = getPlayerSAO(peer_id);
1842 // In some rare case, if the player is disconnected
1843 // while Lua call l_punch, for example, this can be NULL
1847 SendHP(peer_id, playersao->getHP());
1848 m_script->player_event(playersao,"health_changed");
1850 // Send to other clients
1851 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1852 ActiveObjectMessage aom(playersao->getId(), true, str);
1853 playersao->m_messages_out.push(aom);
1856 void Server::SendPlayerBreath(u16 peer_id)
1858 DSTACK(__FUNCTION_NAME);
1859 PlayerSAO *playersao = getPlayerSAO(peer_id);
1862 m_script->player_event(playersao, "breath_changed");
1863 SendBreath(peer_id, playersao->getBreath());
1866 void Server::SendMovePlayer(u16 peer_id)
1868 DSTACK(__FUNCTION_NAME);
1869 Player *player = m_env->getPlayer(peer_id);
1872 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1873 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1876 v3f pos = player->getPosition();
1877 f32 pitch = player->getPitch();
1878 f32 yaw = player->getYaw();
1879 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1880 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1881 << " pitch=" << pitch
1889 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1891 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1894 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1895 << animation_frames[3] << animation_speed;
1900 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1902 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1903 pkt << first << third;
1906 void Server::SendPlayerPrivileges(u16 peer_id)
1908 Player *player = m_env->getPlayer(peer_id);
1910 if(player->peer_id == PEER_ID_INEXISTENT)
1913 std::set<std::string> privs;
1914 m_script->getAuth(player->getName(), NULL, &privs);
1916 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1917 pkt << (u16) privs.size();
1919 for(std::set<std::string>::const_iterator i = privs.begin();
1920 i != privs.end(); i++) {
1927 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1929 Player *player = m_env->getPlayer(peer_id);
1931 if(player->peer_id == PEER_ID_INEXISTENT)
1934 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1935 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1939 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1941 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1942 pkt.putRawString(datas.c_str(), datas.size());
1944 return pkt.getSize();
1947 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1949 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1950 datas.size(), peer_id);
1952 pkt.putRawString(datas.c_str(), datas.size());
1954 m_clients.send(pkt.getPeerId(),
1955 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1960 s32 Server::playSound(const SimpleSoundSpec &spec,
1961 const ServerSoundParams ¶ms)
1963 // Find out initial position of sound
1964 bool pos_exists = false;
1965 v3f pos = params.getPos(m_env, &pos_exists);
1966 // If position is not found while it should be, cancel sound
1967 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1970 // Filter destination clients
1971 std::vector<u16> dst_clients;
1972 if(params.to_player != "")
1974 Player *player = m_env->getPlayer(params.to_player.c_str());
1976 infostream<<"Server::playSound: Player \""<<params.to_player
1977 <<"\" not found"<<std::endl;
1980 if(player->peer_id == PEER_ID_INEXISTENT){
1981 infostream<<"Server::playSound: Player \""<<params.to_player
1982 <<"\" not connected"<<std::endl;
1985 dst_clients.push_back(player->peer_id);
1988 std::vector<u16> clients = m_clients.getClientIDs();
1990 for(std::vector<u16>::iterator
1991 i = clients.begin(); i != clients.end(); ++i) {
1992 Player *player = m_env->getPlayer(*i);
1997 if(player->getPosition().getDistanceFrom(pos) >
1998 params.max_hear_distance)
2001 dst_clients.push_back(*i);
2005 if(dst_clients.empty())
2009 s32 id = m_next_sound_id++;
2010 // The sound will exist as a reference in m_playing_sounds
2011 m_playing_sounds[id] = ServerPlayingSound();
2012 ServerPlayingSound &psound = m_playing_sounds[id];
2013 psound.params = params;
2015 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2016 pkt << id << spec.name << (float) (spec.gain * params.gain)
2017 << (u8) params.type << pos << params.object << params.loop;
2019 for(std::vector<u16>::iterator i = dst_clients.begin();
2020 i != dst_clients.end(); i++) {
2021 psound.clients.insert(*i);
2022 m_clients.send(*i, 0, &pkt, true);
2026 void Server::stopSound(s32 handle)
2028 // Get sound reference
2029 std::map<s32, ServerPlayingSound>::iterator i =
2030 m_playing_sounds.find(handle);
2031 if(i == m_playing_sounds.end())
2033 ServerPlayingSound &psound = i->second;
2035 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2038 for(std::set<u16>::iterator i = psound.clients.begin();
2039 i != psound.clients.end(); i++) {
2041 m_clients.send(*i, 0, &pkt, true);
2043 // Remove sound reference
2044 m_playing_sounds.erase(i);
2047 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2048 std::vector<u16> *far_players, float far_d_nodes)
2050 float maxd = far_d_nodes*BS;
2051 v3f p_f = intToFloat(p, BS);
2053 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2056 std::vector<u16> clients = m_clients.getClientIDs();
2057 for(std::vector<u16>::iterator i = clients.begin();
2058 i != clients.end(); ++i) {
2061 if(Player *player = m_env->getPlayer(*i)) {
2062 // If player is far away, only set modified blocks not sent
2063 v3f player_pos = player->getPosition();
2064 if(player_pos.getDistanceFrom(p_f) > maxd) {
2065 far_players->push_back(*i);
2072 m_clients.send(*i, 0, &pkt, true);
2076 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2077 std::vector<u16> *far_players, float far_d_nodes,
2078 bool remove_metadata)
2080 float maxd = far_d_nodes*BS;
2081 v3f p_f = intToFloat(p, BS);
2083 std::vector<u16> clients = m_clients.getClientIDs();
2084 for(std::vector<u16>::iterator i = clients.begin();
2085 i != clients.end(); ++i) {
2089 if(Player *player = m_env->getPlayer(*i)) {
2090 // If player is far away, only set modified blocks not sent
2091 v3f player_pos = player->getPosition();
2092 if(player_pos.getDistanceFrom(p_f) > maxd) {
2093 far_players->push_back(*i);
2099 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2101 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2103 pkt << p << n.param0 << n.param1 << n.param2
2104 << (u8) (remove_metadata ? 0 : 1);
2106 if (!remove_metadata) {
2107 if (client->net_proto_version <= 21) {
2108 // Old clients always clear metadata; fix it
2109 // by sending the full block again.
2110 client->SetBlockNotSent(p);
2117 if (pkt.getSize() > 0)
2118 m_clients.send(*i, 0, &pkt, true);
2122 void Server::setBlockNotSent(v3s16 p)
2124 std::vector<u16> clients = m_clients.getClientIDs();
2126 for(std::vector<u16>::iterator i = clients.begin();
2127 i != clients.end(); ++i) {
2128 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2129 client->SetBlockNotSent(p);
2134 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2136 DSTACK(__FUNCTION_NAME);
2138 v3s16 p = block->getPos();
2141 Create a packet with the block in the right format
2144 std::ostringstream os(std::ios_base::binary);
2145 block->serialize(os, ver, false);
2146 block->serializeNetworkSpecific(os, net_proto_version);
2147 std::string s = os.str();
2149 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2152 pkt.putRawString(s.c_str(), s.size());
2156 void Server::SendBlocks(float dtime)
2158 DSTACK(__FUNCTION_NAME);
2160 JMutexAutoLock envlock(m_env_mutex);
2161 //TODO check if one big lock could be faster then multiple small ones
2163 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2165 std::vector<PrioritySortedBlockTransfer> queue;
2167 s32 total_sending = 0;
2170 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2172 std::vector<u16> clients = m_clients.getClientIDs();
2175 for(std::vector<u16>::iterator i = clients.begin();
2176 i != clients.end(); ++i) {
2177 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2182 total_sending += client->SendingCount();
2183 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2189 // Lowest priority number comes first.
2190 // Lowest is most important.
2191 std::sort(queue.begin(), queue.end());
2194 for(u32 i=0; i<queue.size(); i++)
2196 //TODO: Calculate limit dynamically
2197 if(total_sending >= g_settings->getS32
2198 ("max_simultaneous_block_sends_server_total"))
2201 PrioritySortedBlockTransfer q = queue[i];
2203 MapBlock *block = NULL;
2206 block = m_env->getMap().getBlockNoCreate(q.pos);
2208 catch(InvalidPositionException &e)
2213 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2218 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2220 client->SentBlock(q.pos);
2226 void Server::fillMediaCache()
2228 DSTACK(__FUNCTION_NAME);
2230 infostream<<"Server: Calculating media file checksums"<<std::endl;
2232 // Collect all media file paths
2233 std::vector<std::string> paths;
2234 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2235 i != m_mods.end(); i++) {
2236 const ModSpec &mod = *i;
2237 paths.push_back(mod.path + DIR_DELIM + "textures");
2238 paths.push_back(mod.path + DIR_DELIM + "sounds");
2239 paths.push_back(mod.path + DIR_DELIM + "media");
2240 paths.push_back(mod.path + DIR_DELIM + "models");
2242 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2244 // Collect media file information from paths into cache
2245 for(std::vector<std::string>::iterator i = paths.begin();
2246 i != paths.end(); i++) {
2247 std::string mediapath = *i;
2248 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2249 for (u32 j = 0; j < dirlist.size(); j++) {
2250 if (dirlist[j].dir) // Ignode dirs
2252 std::string filename = dirlist[j].name;
2253 // If name contains illegal characters, ignore the file
2254 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2255 infostream<<"Server: ignoring illegal file name: \""
2256 << filename << "\"" << std::endl;
2259 // If name is not in a supported format, ignore it
2260 const char *supported_ext[] = {
2261 ".png", ".jpg", ".bmp", ".tga",
2262 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2264 ".x", ".b3d", ".md2", ".obj",
2267 if (removeStringEnd(filename, supported_ext) == ""){
2268 infostream << "Server: ignoring unsupported file extension: \""
2269 << filename << "\"" << std::endl;
2272 // Ok, attempt to load the file and add to cache
2273 std::string filepath = mediapath + DIR_DELIM + filename;
2275 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2277 errorstream << "Server::fillMediaCache(): Could not open \""
2278 << filename << "\" for reading" << std::endl;
2281 std::ostringstream tmp_os(std::ios_base::binary);
2285 fis.read(buf, 1024);
2286 std::streamsize len = fis.gcount();
2287 tmp_os.write(buf, len);
2296 errorstream<<"Server::fillMediaCache(): Failed to read \""
2297 << filename << "\"" << std::endl;
2300 if(tmp_os.str().length() == 0) {
2301 errorstream << "Server::fillMediaCache(): Empty file \""
2302 << filepath << "\"" << std::endl;
2307 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2309 unsigned char *digest = sha1.getDigest();
2310 std::string sha1_base64 = base64_encode(digest, 20);
2311 std::string sha1_hex = hex_encode((char*)digest, 20);
2315 m_media[filename] = MediaInfo(filepath, sha1_base64);
2316 verbosestream << "Server: " << sha1_hex << " is " << filename
2322 void Server::sendMediaAnnouncement(u16 peer_id)
2324 DSTACK(__FUNCTION_NAME);
2326 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2330 std::ostringstream os(std::ios_base::binary);
2332 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2333 pkt << (u16) m_media.size();
2335 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2336 i != m_media.end(); ++i) {
2337 pkt << i->first << i->second.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);
2554 void Server::DenySudoAccess(u16 peer_id)
2556 DSTACK(__FUNCTION_NAME);
2558 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2563 void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode reason,
2564 const std::string &str_reason, bool reconnect)
2566 if (proto_ver >= 25) {
2567 SendAccessDenied(peer_id, reason, str_reason);
2569 std::wstring wreason = utf8_to_wide(
2570 reason == SERVER_ACCESSDENIED_CUSTOM_STRING ? str_reason :
2571 accessDeniedStrings[(u8)reason]);
2572 SendAccessDenied_Legacy(peer_id, wreason);
2575 m_clients.event(peer_id, CSE_SetDenied);
2576 m_con.DisconnectPeer(peer_id);
2580 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2582 DSTACK(__FUNCTION_NAME);
2584 SendAccessDenied(peer_id, reason, custom_reason);
2585 m_clients.event(peer_id, CSE_SetDenied);
2586 m_con.DisconnectPeer(peer_id);
2589 // 13/03/15: remove this function when protocol version 25 will become
2590 // the minimum version for MT users, maybe in 1 year
2591 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2593 DSTACK(__FUNCTION_NAME);
2595 SendAccessDenied_Legacy(peer_id, reason);
2596 m_clients.event(peer_id, CSE_SetDenied);
2597 m_con.DisconnectPeer(peer_id);
2600 void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2602 DSTACK(__FUNCTION_NAME);
2605 RemoteClient* client = getClient(peer_id, CS_Invalid);
2607 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2609 // Right now, the auth mechs don't change between login and sudo mode.
2610 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2611 client->allowed_sudo_mechs = sudo_auth_mechs;
2613 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2614 << g_settings->getFloat("dedicated_server_step")
2618 m_clients.event(peer_id, CSE_AuthAccept);
2620 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2622 // We only support SRP right now
2623 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2625 resp_pkt << sudo_auth_mechs;
2627 m_clients.event(peer_id, CSE_SudoSuccess);
2631 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2633 DSTACK(__FUNCTION_NAME);
2634 std::wstring message;
2637 Clear references to playing sounds
2639 for(std::map<s32, ServerPlayingSound>::iterator
2640 i = m_playing_sounds.begin();
2641 i != m_playing_sounds.end();)
2643 ServerPlayingSound &psound = i->second;
2644 psound.clients.erase(peer_id);
2645 if(psound.clients.empty())
2646 m_playing_sounds.erase(i++);
2651 Player *player = m_env->getPlayer(peer_id);
2653 // Collect information about leaving in chat
2655 if(player != NULL && reason != CDR_DENY)
2657 std::wstring name = narrow_to_wide(player->getName());
2660 message += L" left the game.";
2661 if(reason == CDR_TIMEOUT)
2662 message += L" (timed out)";
2666 /* Run scripts and remove from environment */
2670 PlayerSAO *playersao = player->getPlayerSAO();
2673 m_script->on_leaveplayer(playersao);
2675 playersao->disconnected();
2683 if(player != NULL && reason != CDR_DENY) {
2684 std::ostringstream os(std::ios_base::binary);
2685 std::vector<u16> clients = m_clients.getClientIDs();
2687 for(std::vector<u16>::iterator i = clients.begin();
2688 i != clients.end(); ++i) {
2690 Player *player = m_env->getPlayer(*i);
2694 // Get name of player
2695 os << player->getName() << " ";
2698 actionstream << player->getName() << " "
2699 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2700 << " List of players: " << os.str() << std::endl;
2704 JMutexAutoLock env_lock(m_env_mutex);
2705 m_clients.DeleteClient(peer_id);
2709 // Send leave chat message to all remaining clients
2710 if(message.length() != 0)
2711 SendChatMessage(PEER_ID_INEXISTENT,message);
2714 void Server::UpdateCrafting(Player* player)
2716 DSTACK(__FUNCTION_NAME);
2718 // Get a preview for crafting
2720 InventoryLocation loc;
2721 loc.setPlayer(player->getName());
2722 std::vector<ItemStack> output_replacements;
2723 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2724 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2726 // Put the new preview in
2727 InventoryList *plist = player->inventory.getList("craftpreview");
2728 sanity_check(plist);
2729 sanity_check(plist->getSize() >= 1);
2730 plist->changeItem(0, preview);
2733 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2735 RemoteClient *client = getClientNoEx(peer_id,state_min);
2737 throw ClientNotFoundException("Client not found");
2741 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2743 return m_clients.getClientNoEx(peer_id, state_min);
2746 std::string Server::getPlayerName(u16 peer_id)
2748 Player *player = m_env->getPlayer(peer_id);
2750 return "[id="+itos(peer_id)+"]";
2751 return player->getName();
2754 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2756 Player *player = m_env->getPlayer(peer_id);
2759 return player->getPlayerSAO();
2762 std::wstring Server::getStatusString()
2764 std::wostringstream os(std::ios_base::binary);
2767 os<<L"version="<<narrow_to_wide(g_version_string);
2769 os<<L", uptime="<<m_uptime.get();
2771 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2772 // Information about clients
2775 std::vector<u16> clients = m_clients.getClientIDs();
2776 for(std::vector<u16>::iterator i = clients.begin();
2777 i != clients.end(); ++i) {
2779 Player *player = m_env->getPlayer(*i);
2780 // Get name of player
2781 std::wstring name = L"unknown";
2783 name = narrow_to_wide(player->getName());
2784 // Add name to information string
2792 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2793 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2794 if(g_settings->get("motd") != "")
2795 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2799 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2801 std::set<std::string> privs;
2802 m_script->getAuth(name, NULL, &privs);
2806 bool Server::checkPriv(const std::string &name, const std::string &priv)
2808 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2809 return (privs.count(priv) != 0);
2812 void Server::reportPrivsModified(const std::string &name)
2815 std::vector<u16> clients = m_clients.getClientIDs();
2816 for(std::vector<u16>::iterator i = clients.begin();
2817 i != clients.end(); ++i) {
2818 Player *player = m_env->getPlayer(*i);
2819 reportPrivsModified(player->getName());
2822 Player *player = m_env->getPlayer(name.c_str());
2825 SendPlayerPrivileges(player->peer_id);
2826 PlayerSAO *sao = player->getPlayerSAO();
2829 sao->updatePrivileges(
2830 getPlayerEffectivePrivs(name),
2835 void Server::reportInventoryFormspecModified(const std::string &name)
2837 Player *player = m_env->getPlayer(name.c_str());
2840 SendPlayerInventoryFormspec(player->peer_id);
2843 void Server::setIpBanned(const std::string &ip, const std::string &name)
2845 m_banmanager->add(ip, name);
2848 void Server::unsetIpBanned(const std::string &ip_or_name)
2850 m_banmanager->remove(ip_or_name);
2853 std::string Server::getBanDescription(const std::string &ip_or_name)
2855 return m_banmanager->getBanDescription(ip_or_name);
2858 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2860 // m_env will be NULL if the server is initializing
2864 Player *player = m_env->getPlayer(name);
2868 if (player->peer_id == PEER_ID_INEXISTENT)
2871 SendChatMessage(player->peer_id, msg);
2874 bool Server::showFormspec(const char *playername, const std::string &formspec,
2875 const std::string &formname)
2877 // m_env will be NULL if the server is initializing
2881 Player *player = m_env->getPlayer(playername);
2885 SendShowFormspecMessage(player->peer_id, formspec, formname);
2889 u32 Server::hudAdd(Player *player, HudElement *form)
2894 u32 id = player->addHud(form);
2896 SendHUDAdd(player->peer_id, id, form);
2901 bool Server::hudRemove(Player *player, u32 id) {
2905 HudElement* todel = player->removeHud(id);
2912 SendHUDRemove(player->peer_id, id);
2916 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data)
2921 SendHUDChange(player->peer_id, id, stat, data);
2925 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask)
2930 SendHUDSetFlags(player->peer_id, flags, mask);
2931 player->hud_flags = flags;
2933 PlayerSAO* playersao = player->getPlayerSAO();
2935 if (playersao == NULL)
2938 m_script->player_event(playersao, "hud_changed");
2942 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount)
2946 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2949 player->setHotbarItemcount(hotbar_itemcount);
2950 std::ostringstream os(std::ios::binary);
2951 writeS32(os, hotbar_itemcount);
2952 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2956 s32 Server::hudGetHotbarItemcount(Player *player)
2960 return player->getHotbarItemcount();
2963 void Server::hudSetHotbarImage(Player *player, std::string name)
2968 player->setHotbarImage(name);
2969 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2972 std::string Server::hudGetHotbarImage(Player *player)
2976 return player->getHotbarImage();
2979 void Server::hudSetHotbarSelectedImage(Player *player, std::string name)
2984 player->setHotbarSelectedImage(name);
2985 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2988 std::string Server::hudGetHotbarSelectedImage(Player *player)
2993 return player->getHotbarSelectedImage();
2996 bool Server::setLocalPlayerAnimations(Player *player,
2997 v2s32 animation_frames[4], f32 frame_speed)
3002 player->setLocalAnimations(animation_frames, frame_speed);
3003 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
3007 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
3012 player->eye_offset_first = first;
3013 player->eye_offset_third = third;
3014 SendEyeOffset(player->peer_id, first, third);
3018 bool Server::setSky(Player *player, const video::SColor &bgcolor,
3019 const std::string &type, const std::vector<std::string> ¶ms)
3024 player->setSky(bgcolor, type, params);
3025 SendSetSky(player->peer_id, bgcolor, type, params);
3029 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3035 player->overrideDayNightRatio(do_override, ratio);
3036 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3040 void Server::notifyPlayers(const std::wstring &msg)
3042 SendChatMessage(PEER_ID_INEXISTENT,msg);
3045 void Server::spawnParticle(const std::string &playername, v3f pos,
3046 v3f velocity, v3f acceleration,
3047 float expirationtime, float size, bool
3048 collisiondetection, bool vertical, const std::string &texture)
3050 // m_env will be NULL if the server is initializing
3054 u16 peer_id = PEER_ID_INEXISTENT;
3055 if (playername != "") {
3056 Player* player = m_env->getPlayer(playername.c_str());
3059 peer_id = player->peer_id;
3062 SendSpawnParticle(peer_id, pos, velocity, acceleration,
3063 expirationtime, size, collisiondetection, vertical, texture);
3066 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3067 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3068 float minexptime, float maxexptime, float minsize, float maxsize,
3069 bool collisiondetection, bool vertical, const std::string &texture,
3070 const std::string &playername)
3072 // m_env will be NULL if the server is initializing
3076 u16 peer_id = PEER_ID_INEXISTENT;
3077 if (playername != "") {
3078 Player* player = m_env->getPlayer(playername.c_str());
3081 peer_id = player->peer_id;
3085 for(;;) // look for unused particlespawner id
3088 if (std::find(m_particlespawner_ids.begin(),
3089 m_particlespawner_ids.end(), id)
3090 == m_particlespawner_ids.end())
3092 m_particlespawner_ids.push_back(id);
3097 SendAddParticleSpawner(peer_id, amount, spawntime,
3098 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3099 minexptime, maxexptime, minsize, maxsize,
3100 collisiondetection, vertical, texture, id);
3105 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3107 // m_env will be NULL if the server is initializing
3109 throw ServerError("Can't delete particle spawners during initialisation!");
3111 u16 peer_id = PEER_ID_INEXISTENT;
3112 if (playername != "") {
3113 Player* player = m_env->getPlayer(playername.c_str());
3116 peer_id = player->peer_id;
3119 m_particlespawner_ids.erase(
3120 std::remove(m_particlespawner_ids.begin(),
3121 m_particlespawner_ids.end(), id),
3122 m_particlespawner_ids.end());
3123 SendDeleteParticleSpawner(peer_id, id);
3126 Inventory* Server::createDetachedInventory(const std::string &name)
3128 if(m_detached_inventories.count(name) > 0){
3129 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3130 delete m_detached_inventories[name];
3132 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3134 Inventory *inv = new Inventory(m_itemdef);
3136 m_detached_inventories[name] = inv;
3137 //TODO find a better way to do this
3138 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3142 // actions: time-reversed list
3143 // Return value: success/failure
3144 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3145 std::list<std::string> *log)
3147 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3148 ServerMap *map = (ServerMap*)(&m_env->getMap());
3150 // Fail if no actions to handle
3151 if(actions.empty()){
3152 log->push_back("Nothing to do.");
3159 for(std::list<RollbackAction>::const_iterator
3160 i = actions.begin();
3161 i != actions.end(); i++)
3163 const RollbackAction &action = *i;
3165 bool success = action.applyRevert(map, this, this);
3168 std::ostringstream os;
3169 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3170 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3172 log->push_back(os.str());
3174 std::ostringstream os;
3175 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3176 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3178 log->push_back(os.str());
3182 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3183 <<" failed"<<std::endl;
3185 // Call it done if less than half failed
3186 return num_failed <= num_tried/2;
3189 // IGameDef interface
3191 IItemDefManager *Server::getItemDefManager()
3196 INodeDefManager *Server::getNodeDefManager()
3201 ICraftDefManager *Server::getCraftDefManager()
3205 ITextureSource *Server::getTextureSource()
3209 IShaderSource *Server::getShaderSource()
3213 scene::ISceneManager *Server::getSceneManager()
3218 u16 Server::allocateUnknownNodeId(const std::string &name)
3220 return m_nodedef->allocateDummy(name);
3223 ISoundManager *Server::getSoundManager()
3225 return &dummySoundManager;
3228 MtEventManager *Server::getEventManager()
3233 IWritableItemDefManager *Server::getWritableItemDefManager()
3238 IWritableNodeDefManager *Server::getWritableNodeDefManager()
3243 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3248 const ModSpec *Server::getModSpec(const std::string &modname) const
3250 std::vector<ModSpec>::const_iterator it;
3251 for (it = m_mods.begin(); it != m_mods.end(); ++it) {
3252 const ModSpec &mod = *it;
3253 if (mod.name == modname)
3259 void Server::getModNames(std::vector<std::string> &modlist)
3261 std::vector<ModSpec>::iterator it;
3262 for (it = m_mods.begin(); it != m_mods.end(); ++it)
3263 modlist.push_back(it->name);
3266 std::string Server::getBuiltinLuaPath()
3268 return porting::path_share + DIR_DELIM + "builtin";
3271 v3f Server::findSpawnPos()
3273 ServerMap &map = m_env->getServerMap();
3275 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3276 return nodeposf * BS;
3279 // Default position is static_spawnpoint
3280 // We will return it if we don't found a good place
3281 v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3283 s16 water_level = map.getWaterLevel();
3285 bool is_good = false;
3287 // Try to find a good place a few times
3288 for(s32 i = 0; i < 1000 && !is_good; i++) {
3290 // We're going to try to throw the player to this position
3291 v2s16 nodepos2d = v2s16(
3292 -range + (myrand() % (range * 2)),
3293 -range + (myrand() % (range * 2)));
3295 // Get ground height at point
3296 s16 groundheight = map.findGroundLevel(nodepos2d);
3297 if (groundheight <= water_level) // Don't go underwater
3299 if (groundheight > water_level + 6) // Don't go to high places
3302 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3305 for (s32 i = 0; i < 10; i++) {
3306 v3s16 blockpos = getNodeBlockPos(nodepos);
3307 map.emergeBlock(blockpos, true);
3308 content_t c = map.getNodeNoEx(nodepos).getContent();
3309 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3311 if (air_count >= 2){
3320 return intToFloat(nodepos, BS);
3323 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
3325 bool newplayer = false;
3328 Try to get an existing player
3330 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3332 // If player is already connected, cancel
3333 if(player != NULL && player->peer_id != 0)
3335 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3340 If player with the wanted peer_id already exists, cancel.
3342 if(m_env->getPlayer(peer_id) != NULL)
3344 infostream<<"emergePlayer(): Player with wrong name but same"
3345 " peer_id already exists"<<std::endl;
3349 // Load player if it isn't already loaded
3351 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3354 // Create player if it doesn't exist
3357 player = new RemotePlayer(this, name);
3358 // Set player position
3359 infostream<<"Server: Finding spawn place for player \""
3360 <<name<<"\""<<std::endl;
3361 v3f pos = findSpawnPos();
3362 player->setPosition(pos);
3364 // Make sure the player is saved
3365 player->setModified(true);
3367 // Add player to environment
3368 m_env->addPlayer(player);
3371 // Create a new player active object
3372 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3373 getPlayerEffectivePrivs(player->getName()),
3376 player->protocol_version = proto_version;
3378 /* Clean up old HUD elements from previous sessions */
3381 /* Add object to environment */
3382 m_env->addActiveObject(playersao);
3386 m_script->on_newplayer(playersao);
3392 void dedicated_server_loop(Server &server, bool &kill)
3394 DSTACK(__FUNCTION_NAME);
3396 verbosestream<<"dedicated_server_loop()"<<std::endl;
3398 IntervalLimiter m_profiler_interval;
3402 float steplen = g_settings->getFloat("dedicated_server_step");
3403 // This is kind of a hack but can be done like this
3404 // because server.step() is very light
3406 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3407 sleep_ms((int)(steplen*1000.0));
3409 server.step(steplen);
3411 if(server.getShutdownRequested() || kill)
3413 infostream<<"Dedicated server quitting"<<std::endl;
3415 if(g_settings->getBool("server_announce"))
3416 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3424 float profiler_print_interval =
3425 g_settings->getFloat("profiler_print_interval");
3426 if(profiler_print_interval != 0)
3428 if(m_profiler_interval.step(steplen, profiler_print_interval))
3430 infostream<<"Profiler:"<<std::endl;
3431 g_profiler->print(infostream);
3432 g_profiler->clear();