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"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_game.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_abm.h"
52 #include "content_sao.h"
54 #include "sound.h" // dummySoundManager
55 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "util/thread.h"
62 #include "defaultsettings.h"
63 #include "util/base64.h"
64 #include "util/sha1.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public JThread
81 ServerThread(Server *server):
90 void * ServerThread::Thread()
92 log_register_thread("ServerThread");
94 DSTACK(__FUNCTION_NAME);
95 BEGIN_DEBUG_EXCEPTION_HANDLER
97 m_server->AsyncRunStep(true);
101 porting::setThreadName("ServerThread");
103 while(!StopRequested())
106 //TimeTaker timer("AsyncRunStep() + Receive()");
108 m_server->AsyncRunStep();
113 catch(con::NoIncomingDataException &e)
116 catch(con::PeerNotFoundException &e)
118 infostream<<"Server: PeerNotFoundException"<<std::endl;
120 catch(ClientNotFoundException &e)
123 catch(con::ConnectionBindFailed &e)
125 m_server->setAsyncFatalError(e.what());
129 m_server->setAsyncFatalError(e.what());
133 END_DEBUG_EXCEPTION_HANDLER(errorstream)
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
140 if(pos_exists) *pos_exists = false;
145 if(pos_exists) *pos_exists = true;
150 ServerActiveObject *sao = env->getActiveObject(object);
153 if(pos_exists) *pos_exists = true;
154 return sao->getBasePosition(); }
166 const std::string &path_world,
167 const SubgameSpec &gamespec,
168 bool simple_singleplayer_mode,
171 m_path_world(path_world),
172 m_gamespec(gamespec),
173 m_simple_singleplayer_mode(simple_singleplayer_mode),
174 m_async_fatal_error(""),
183 m_enable_rollback_recording(false),
186 m_itemdef(createItemDefManager()),
187 m_nodedef(createNodeDefManager()),
188 m_craftdef(createCraftDefManager()),
189 m_event(new EventManager()),
191 m_time_of_day_send_timer(0),
194 m_shutdown_requested(false),
195 m_ignore_map_edit_events(false),
196 m_ignore_map_edit_events_peer_id(0),
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Create world if it doesn't exist
226 if(!initializeWorld(m_path_world, m_gamespec.id))
227 throw ServerError("Failed to initialize world");
229 // Create server thread
230 m_thread = new ServerThread(this);
232 // Create emerge manager
233 m_emerge = new EmergeManager(this);
235 // Create ban manager
236 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
237 m_banmanager = new BanManager(ban_path);
239 ModConfiguration modconf(m_path_world);
240 m_mods = modconf.getMods();
241 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
242 // complain about mods with unsatisfied dependencies
243 if(!modconf.isConsistent())
245 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
246 it != unsatisfied_mods.end(); ++it)
249 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
250 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
251 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
252 errorstream << " \"" << *dep_it << "\"";
253 errorstream << std::endl;
257 Settings worldmt_settings;
258 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
259 worldmt_settings.readConfigFile(worldmt.c_str());
260 std::vector<std::string> names = worldmt_settings.getNames();
261 std::set<std::string> load_mod_names;
262 for(std::vector<std::string>::iterator it = names.begin();
263 it != names.end(); ++it)
265 std::string name = *it;
266 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
267 load_mod_names.insert(name.substr(9));
269 // complain about mods declared to be loaded, but not found
270 for(std::vector<ModSpec>::iterator it = m_mods.begin();
271 it != m_mods.end(); ++it)
272 load_mod_names.erase((*it).name);
273 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
274 it != unsatisfied_mods.end(); ++it)
275 load_mod_names.erase((*it).name);
276 if(!load_mod_names.empty())
278 errorstream << "The following mods could not be found:";
279 for(std::set<std::string>::iterator it = load_mod_names.begin();
280 it != load_mod_names.end(); ++it)
281 errorstream << " \"" << (*it) << "\"";
282 errorstream << std::endl;
286 JMutexAutoLock envlock(m_env_mutex);
288 // Load mapgen params from Settings
289 m_emerge->loadMapgenParams();
291 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
292 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
294 // Initialize scripting
295 infostream<<"Server: Initializing Lua"<<std::endl;
297 m_script = new GameScripting(this);
299 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
301 if (!m_script->loadScript(scriptpath))
302 throw ModError("Failed to load and run " + scriptpath);
305 infostream<<"Server: Loading mods: ";
306 for(std::vector<ModSpec>::iterator i = m_mods.begin();
307 i != m_mods.end(); i++){
308 const ModSpec &mod = *i;
309 infostream<<mod.name<<" ";
311 infostream<<std::endl;
312 // Load and run "mod" scripts
313 for(std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++){
315 const ModSpec &mod = *i;
316 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
317 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
318 <<scriptpath<<"\"]"<<std::endl;
319 bool success = m_script->loadMod(scriptpath, mod.name);
321 errorstream<<"Server: Failed to load and run "
322 <<scriptpath<<std::endl;
323 throw ModError("Failed to load and run "+scriptpath);
327 // Read Textures and calculate sha1 sums
330 // Apply item aliases in the node definition manager
331 m_nodedef->updateAliases(m_itemdef);
333 m_nodedef->setNodeRegistrationStatus(true);
335 // Perform pending node name resolutions
336 m_nodedef->runNodeResolverCallbacks();
338 // Initialize Environment
339 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
341 m_clients.setEnv(m_env);
343 // Initialize mapgens
344 m_emerge->initMapgens();
346 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
347 if (m_enable_rollback_recording) {
348 // Create rollback manager
349 m_rollback = new RollbackManager(m_path_world, this);
352 // Give environment reference to scripting api
353 m_script->initializeEnvironment(m_env);
355 // Register us to receive map edit events
356 servermap->addEventReceiver(this);
358 // If file exists, load environment metadata
359 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
361 infostream<<"Server: Loading environment metadata"<<std::endl;
365 // Add some test ActiveBlockModifiers to environment
366 add_legacy_abms(m_env, m_nodedef);
368 m_liquid_transform_every = g_settings->getFloat("liquid_update");
373 infostream<<"Server destructing"<<std::endl;
375 // Send shutdown message
376 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
379 JMutexAutoLock envlock(m_env_mutex);
381 // Execute script shutdown hooks
382 m_script->on_shutdown();
384 infostream<<"Server: Saving players"<<std::endl;
385 m_env->saveLoadedPlayers();
387 infostream<<"Server: Saving environment metadata"<<std::endl;
395 // stop all emerge threads before deleting players that may have
396 // requested blocks to be emerged
397 m_emerge->stopThreads();
399 // Delete things in the reverse order of creation
402 // N.B. the EmergeManager should be deleted after the Environment since Map
403 // depends on EmergeManager to write its current params to the map meta
412 // Deinitialize scripting
413 infostream<<"Server: Deinitializing scripting"<<std::endl;
416 // Delete detached inventories
417 for (std::map<std::string, Inventory*>::iterator
418 i = m_detached_inventories.begin();
419 i != m_detached_inventories.end(); i++) {
424 void Server::start(Address bind_addr)
426 DSTACK(__FUNCTION_NAME);
428 m_bind_addr = bind_addr;
430 infostream<<"Starting server on "
431 << bind_addr.serializeString() <<"..."<<std::endl;
433 // Stop thread if already running
436 // Initialize connection
437 m_con.SetTimeoutMs(30);
438 m_con.Serve(bind_addr);
443 // ASCII art for the win!
445 <<" .__ __ __ "<<std::endl
446 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
447 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
448 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
449 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
450 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
451 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
452 actionstream<<"Server for gameid=\""<<m_gamespec.id
453 <<"\" listening on "<<bind_addr.serializeString()<<":"
454 <<bind_addr.getPort() << "."<<std::endl;
459 DSTACK(__FUNCTION_NAME);
461 infostream<<"Server: Stopping and waiting threads"<<std::endl;
463 // Stop threads (set run=false first so both start stopping)
465 //m_emergethread.setRun(false);
467 //m_emergethread.stop();
469 infostream<<"Server: Threads stopped"<<std::endl;
472 void Server::step(float dtime)
474 DSTACK(__FUNCTION_NAME);
479 JMutexAutoLock lock(m_step_dtime_mutex);
480 m_step_dtime += dtime;
482 // Assert if fatal error occurred in thread
483 std::string async_err = m_async_fatal_error.get();
484 if(async_err != "") {
485 errorstream << "UNRECOVERABLE error occurred. Stopping server. "
486 << "Please fix the following error:" << std::endl
487 << async_err << std::endl;
492 void Server::AsyncRunStep(bool initial_step)
494 DSTACK(__FUNCTION_NAME);
496 g_profiler->add("Server::AsyncRunStep (num)", 1);
500 JMutexAutoLock lock1(m_step_dtime_mutex);
501 dtime = m_step_dtime;
505 // Send blocks to clients
509 if((dtime < 0.001) && (initial_step == false))
512 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
514 //infostream<<"Server steps "<<dtime<<std::endl;
515 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
518 JMutexAutoLock lock1(m_step_dtime_mutex);
519 m_step_dtime -= dtime;
526 m_uptime.set(m_uptime.get() + dtime);
532 Update time of day and overall game time
534 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
537 Send to clients at constant intervals
540 m_time_of_day_send_timer -= dtime;
541 if(m_time_of_day_send_timer < 0.0) {
542 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
543 u16 time = m_env->getTimeOfDay();
544 float time_speed = g_settings->getFloat("time_speed");
545 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
549 JMutexAutoLock lock(m_env_mutex);
550 // Figure out and report maximum lag to environment
551 float max_lag = m_env->getMaxLagEstimate();
552 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
554 if(dtime > 0.1 && dtime > max_lag * 2.0)
555 infostream<<"Server: Maximum lag peaked to "<<dtime
559 m_env->reportMaxLagEstimate(max_lag);
561 ScopeProfiler sp(g_profiler, "SEnv step");
562 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
566 static const float map_timer_and_unload_dtime = 2.92;
567 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
569 JMutexAutoLock lock(m_env_mutex);
570 // Run Map's timers and unload unused data
571 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
572 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
573 g_settings->getFloat("server_unload_unused_data_timeout"));
580 /* Transform liquids */
581 m_liquid_transform_timer += dtime;
582 if(m_liquid_transform_timer >= m_liquid_transform_every)
584 m_liquid_transform_timer -= m_liquid_transform_every;
586 JMutexAutoLock lock(m_env_mutex);
588 ScopeProfiler sp(g_profiler, "Server: liquid transform");
590 std::map<v3s16, MapBlock*> modified_blocks;
591 m_env->getMap().transformLiquids(modified_blocks);
596 core::map<v3s16, MapBlock*> lighting_modified_blocks;
597 ServerMap &map = ((ServerMap&)m_env->getMap());
598 map.updateLighting(modified_blocks, lighting_modified_blocks);
600 // Add blocks modified by lighting to modified_blocks
601 for(core::map<v3s16, MapBlock*>::Iterator
602 i = lighting_modified_blocks.getIterator();
603 i.atEnd() == false; i++)
605 MapBlock *block = i.getNode()->getValue();
606 modified_blocks.insert(block->getPos(), block);
610 Set the modified blocks unsent for all the clients
612 if(!modified_blocks.empty())
614 SetBlocksNotSent(modified_blocks);
617 m_clients.step(dtime);
619 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
621 // send masterserver announce
623 float &counter = m_masterserver_timer;
624 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
625 g_settings->getBool("server_announce"))
627 ServerList::sendAnnounce(counter ? "update" : "start",
628 m_bind_addr.getPort(),
629 m_clients.getPlayerNames(),
631 m_env->getGameTime(),
634 m_emerge->params.mg_name,
643 Check added and deleted active objects
646 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
647 JMutexAutoLock envlock(m_env_mutex);
650 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
651 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
653 // Radius inside which objects are active
654 s16 radius = g_settings->getS16("active_object_send_range_blocks");
655 s16 player_radius = g_settings->getS16("player_transfer_distance");
657 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
658 !g_settings->getBool("unlimited_player_transfer_distance"))
659 player_radius = radius;
661 radius *= MAP_BLOCKSIZE;
662 player_radius *= MAP_BLOCKSIZE;
664 for(std::map<u16, RemoteClient*>::iterator
666 i != clients.end(); ++i)
668 RemoteClient *client = i->second;
670 // If definitions and textures have not been sent, don't
671 // send objects either
672 if (client->getState() < CS_DefinitionsSent)
675 Player *player = m_env->getPlayer(client->peer_id);
678 // This can happen if the client timeouts somehow
679 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
681 <<" has no associated player"<<std::endl;*/
684 v3s16 pos = floatToInt(player->getPosition(), BS);
686 std::set<u16> removed_objects;
687 std::set<u16> added_objects;
688 m_env->getRemovedActiveObjects(pos, radius, player_radius,
689 client->m_known_objects, removed_objects);
690 m_env->getAddedActiveObjects(pos, radius, player_radius,
691 client->m_known_objects, added_objects);
693 // Ignore if nothing happened
694 if(removed_objects.empty() && added_objects.empty())
696 //infostream<<"active objects: none changed"<<std::endl;
700 std::string data_buffer;
704 // Handle removed objects
705 writeU16((u8*)buf, removed_objects.size());
706 data_buffer.append(buf, 2);
707 for(std::set<u16>::iterator
708 i = removed_objects.begin();
709 i != removed_objects.end(); ++i)
713 ServerActiveObject* obj = m_env->getActiveObject(id);
715 // Add to data buffer for sending
716 writeU16((u8*)buf, id);
717 data_buffer.append(buf, 2);
719 // Remove from known objects
720 client->m_known_objects.erase(id);
722 if(obj && obj->m_known_by_count > 0)
723 obj->m_known_by_count--;
726 // Handle added objects
727 writeU16((u8*)buf, added_objects.size());
728 data_buffer.append(buf, 2);
729 for(std::set<u16>::iterator
730 i = added_objects.begin();
731 i != added_objects.end(); ++i)
735 ServerActiveObject* obj = m_env->getActiveObject(id);
738 u8 type = ACTIVEOBJECT_TYPE_INVALID;
740 infostream<<"WARNING: "<<__FUNCTION_NAME
741 <<": NULL object"<<std::endl;
743 type = obj->getSendType();
745 // Add to data buffer for sending
746 writeU16((u8*)buf, id);
747 data_buffer.append(buf, 2);
748 writeU8((u8*)buf, type);
749 data_buffer.append(buf, 1);
752 data_buffer.append(serializeLongString(
753 obj->getClientInitializationData(client->net_proto_version)));
755 data_buffer.append(serializeLongString(""));
757 // Add to known objects
758 client->m_known_objects.insert(id);
761 obj->m_known_by_count++;
764 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
765 verbosestream << "Server: Sent object remove/add: "
766 << removed_objects.size() << " removed, "
767 << added_objects.size() << " added, "
768 << "packet size is " << pktSize << std::endl;
777 JMutexAutoLock envlock(m_env_mutex);
778 ScopeProfiler sp(g_profiler, "Server: sending object messages");
781 // Value = data sent by object
782 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
784 // Get active object messages from environment
786 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
790 std::vector<ActiveObjectMessage>* message_list = NULL;
791 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
792 n = buffered_messages.find(aom.id);
793 if (n == buffered_messages.end()) {
794 message_list = new std::vector<ActiveObjectMessage>;
795 buffered_messages[aom.id] = message_list;
798 message_list = n->second;
800 message_list->push_back(aom);
804 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
805 // Route data to every client
806 for (std::map<u16, RemoteClient*>::iterator
808 i != clients.end(); ++i) {
809 RemoteClient *client = i->second;
810 std::string reliable_data;
811 std::string unreliable_data;
812 // Go through all objects in message buffer
813 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
814 j = buffered_messages.begin();
815 j != buffered_messages.end(); ++j) {
816 // If object is not known by client, skip it
818 if (client->m_known_objects.find(id) == client->m_known_objects.end())
821 // Get message list of object
822 std::vector<ActiveObjectMessage>* list = j->second;
823 // Go through every message
824 for (std::vector<ActiveObjectMessage>::iterator
825 k = list->begin(); k != list->end(); ++k) {
826 // Compose the full new data with header
827 ActiveObjectMessage aom = *k;
828 std::string new_data;
831 writeU16((u8*)&buf[0], aom.id);
832 new_data.append(buf, 2);
834 new_data += serializeString(aom.datastring);
835 // Add data to buffer
837 reliable_data += new_data;
839 unreliable_data += new_data;
843 reliable_data and unreliable_data are now ready.
846 if(reliable_data.size() > 0) {
847 SendActiveObjectMessages(client->peer_id, reliable_data);
850 if(unreliable_data.size() > 0) {
851 SendActiveObjectMessages(client->peer_id, unreliable_data);
856 // Clear buffered_messages
857 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
858 i = buffered_messages.begin();
859 i != buffered_messages.end(); ++i) {
865 Send queued-for-sending map edit events.
868 // We will be accessing the environment
869 JMutexAutoLock lock(m_env_mutex);
871 // Don't send too many at a time
874 // Single change sending is disabled if queue size is not small
875 bool disable_single_change_sending = false;
876 if(m_unsent_map_edit_queue.size() >= 4)
877 disable_single_change_sending = true;
879 int event_count = m_unsent_map_edit_queue.size();
881 // We'll log the amount of each
884 while(m_unsent_map_edit_queue.size() != 0)
886 MapEditEvent* event = m_unsent_map_edit_queue.front();
887 m_unsent_map_edit_queue.pop();
889 // Players far away from the change are stored here.
890 // Instead of sending the changes, MapBlocks are set not sent
892 std::vector<u16> far_players;
894 switch (event->type) {
897 prof.add("MEET_ADDNODE", 1);
898 sendAddNode(event->p, event->n, event->already_known_by_peer,
899 &far_players, disable_single_change_sending ? 5 : 30,
900 event->type == MEET_ADDNODE);
902 case MEET_REMOVENODE:
903 prof.add("MEET_REMOVENODE", 1);
904 sendRemoveNode(event->p, event->already_known_by_peer,
905 &far_players, disable_single_change_sending ? 5 : 30);
907 case MEET_BLOCK_NODE_METADATA_CHANGED:
908 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
909 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
910 setBlockNotSent(event->p);
913 infostream << "Server: MEET_OTHER" << std::endl;
914 prof.add("MEET_OTHER", 1);
915 for(std::set<v3s16>::iterator
916 i = event->modified_blocks.begin();
917 i != event->modified_blocks.end(); ++i) {
922 prof.add("unknown", 1);
923 infostream << "WARNING: Server: Unknown MapEditEvent "
924 << ((u32)event->type) << std::endl;
929 Set blocks not sent to far players
931 if(!far_players.empty()) {
932 // Convert list format to that wanted by SetBlocksNotSent
933 std::map<v3s16, MapBlock*> modified_blocks2;
934 for(std::set<v3s16>::iterator
935 i = event->modified_blocks.begin();
936 i != event->modified_blocks.end(); ++i) {
937 modified_blocks2[*i] =
938 m_env->getMap().getBlockNoCreateNoEx(*i);
941 // Set blocks not sent
942 for(std::vector<u16>::iterator
943 i = far_players.begin();
944 i != far_players.end(); ++i) {
945 if(RemoteClient *client = getClient(*i))
946 client->SetBlocksNotSent(modified_blocks2);
952 /*// Don't send too many at a time
954 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
958 if(event_count >= 5){
959 infostream<<"Server: MapEditEvents:"<<std::endl;
960 prof.print(infostream);
961 } else if(event_count != 0){
962 verbosestream<<"Server: MapEditEvents:"<<std::endl;
963 prof.print(verbosestream);
969 Trigger emergethread (it somehow gets to a non-triggered but
970 bysy state sometimes)
973 float &counter = m_emergethread_trigger_timer;
979 m_emerge->startThreads();
983 // Save map, players and auth stuff
985 float &counter = m_savemap_timer;
987 if(counter >= g_settings->getFloat("server_map_save_interval"))
990 JMutexAutoLock lock(m_env_mutex);
992 ScopeProfiler sp(g_profiler, "Server: saving stuff");
995 if (m_banmanager->isModified()) {
996 m_banmanager->save();
999 // Save changed parts of map
1000 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1003 m_env->saveLoadedPlayers();
1005 // Save environment metadata
1011 void Server::Receive()
1013 DSTACK(__FUNCTION_NAME);
1014 SharedBuffer<u8> data;
1018 datasize = m_con.Receive(peer_id,data);
1019 ProcessData(*data, datasize, peer_id);
1021 catch(con::InvalidIncomingDataException &e) {
1022 infostream<<"Server::Receive(): "
1023 "InvalidIncomingDataException: what()="
1024 <<e.what()<<std::endl;
1026 catch(SerializationError &e) {
1027 infostream<<"Server::Receive(): "
1028 "SerializationError: what()="
1029 <<e.what()<<std::endl;
1031 catch(ClientStateError &e) {
1032 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1033 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1034 L"Try reconnecting or updating your client");
1036 catch(con::PeerNotFoundException &e) {
1041 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1043 std::string playername = "";
1044 PlayerSAO *playersao = NULL;
1047 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1048 if (client != NULL) {
1049 playername = client->getName();
1050 playersao = emergePlayer(playername.c_str(), peer_id);
1052 } catch (std::exception &e) {
1058 RemotePlayer *player =
1059 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1061 // If failed, cancel
1062 if((playersao == NULL) || (player == NULL)) {
1063 if(player && player->peer_id != 0) {
1064 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1065 <<" (player allocated to an another client)"<<std::endl;
1066 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1067 L"name. If your client closed unexpectedly, try again in "
1070 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1072 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1078 Send complete position information
1080 SendMovePlayer(peer_id);
1083 SendPlayerPrivileges(peer_id);
1085 // Send inventory formspec
1086 SendPlayerInventoryFormspec(peer_id);
1089 SendInventory(playersao);
1092 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1095 SendPlayerBreath(peer_id);
1097 // Show death screen if necessary
1098 if(player->isDead())
1099 SendDeathscreen(peer_id, false, v3f(0,0,0));
1101 // Note things in chat if not in simple singleplayer mode
1102 if(!m_simple_singleplayer_mode) {
1103 // Send information about server to player in chat
1104 SendChatMessage(peer_id, getStatusString());
1106 // Send information about joining in chat
1108 std::wstring name = L"unknown";
1109 Player *player = m_env->getPlayer(peer_id);
1111 name = narrow_to_wide(player->getName());
1113 std::wstring message;
1116 message += L" joined the game.";
1117 SendChatMessage(PEER_ID_INEXISTENT,message);
1120 Address addr = getPeerAddress(player->peer_id);
1121 std::string ip_str = addr.serializeString();
1122 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1127 std::vector<std::string> names = m_clients.getPlayerNames();
1129 actionstream<<player->getName() <<" joins game. List of players: ";
1131 for (std::vector<std::string>::iterator i = names.begin();
1132 i != names.end(); i++) {
1133 actionstream << *i << " ";
1136 actionstream << player->getName() <<std::endl;
1141 inline void Server::handleCommand(NetworkPacket* pkt)
1143 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1144 (this->*opHandle.handler)(pkt);
1147 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1149 DSTACK(__FUNCTION_NAME);
1150 // Environment is locked first.
1151 JMutexAutoLock envlock(m_env_mutex);
1153 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1156 Address address = getPeerAddress(peer_id);
1157 std::string addr_s = address.serializeString();
1159 if(m_banmanager->isIpBanned(addr_s)) {
1160 std::string ban_name = m_banmanager->getBanName(addr_s);
1161 infostream << "Server: A banned client tried to connect from "
1162 << addr_s << "; banned name was "
1163 << ban_name << std::endl;
1164 // This actually doesn't seem to transfer to the client
1165 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1166 + narrow_to_wide(ban_name));
1170 catch(con::PeerNotFoundException &e) {
1172 * no peer for this packet found
1173 * most common reason is peer timeout, e.g. peer didn't
1174 * respond for some time, your server was overloaded or
1177 infostream << "Server::ProcessData(): Cancelling: peer "
1178 << peer_id << " not found" << std::endl;
1186 NetworkPacket pkt(data, datasize, peer_id);
1188 ToServerCommand command = (ToServerCommand) pkt.getCommand();
1190 // Command must be handled into ToServerCommandHandler
1191 if (command >= TOSERVER_NUM_MSG_TYPES) {
1192 infostream << "Server: Ignoring unknown command "
1193 << command << std::endl;
1196 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1197 handleCommand(&pkt);
1201 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1203 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1204 errorstream << "Server::ProcessData(): Cancelling: Peer"
1205 " serialization format invalid or not initialized."
1206 " Skipping incoming command=" << command << std::endl;
1210 /* Handle commands related to client startup */
1211 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1212 handleCommand(&pkt);
1216 if (m_clients.getClientState(peer_id) < CS_Active) {
1217 if (command == TOSERVER_PLAYERPOS) return;
1219 errorstream << "Got packet command: " << command << " for peer id "
1220 << peer_id << " but client isn't active yet. Dropping packet "
1225 handleCommand(&pkt);
1227 catch(SendFailedException &e) {
1228 errorstream << "Server::ProcessData(): SendFailedException: "
1229 << "what=" << e.what()
1234 void Server::setTimeOfDay(u32 time)
1236 m_env->setTimeOfDay(time);
1237 m_time_of_day_send_timer = 0;
1240 void Server::onMapEditEvent(MapEditEvent *event)
1242 if(m_ignore_map_edit_events)
1244 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1246 MapEditEvent *e = event->clone();
1247 m_unsent_map_edit_queue.push(e);
1250 Inventory* Server::getInventory(const InventoryLocation &loc)
1253 case InventoryLocation::UNDEFINED:
1254 case InventoryLocation::CURRENT_PLAYER:
1256 case InventoryLocation::PLAYER:
1258 Player *player = m_env->getPlayer(loc.name.c_str());
1261 PlayerSAO *playersao = player->getPlayerSAO();
1264 return playersao->getInventory();
1267 case InventoryLocation::NODEMETA:
1269 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1272 return meta->getInventory();
1275 case InventoryLocation::DETACHED:
1277 if(m_detached_inventories.count(loc.name) == 0)
1279 return m_detached_inventories[loc.name];
1283 sanity_check(false); // abort
1288 void Server::setInventoryModified(const InventoryLocation &loc)
1291 case InventoryLocation::UNDEFINED:
1293 case InventoryLocation::PLAYER:
1295 Player *player = m_env->getPlayer(loc.name.c_str());
1298 PlayerSAO *playersao = player->getPlayerSAO();
1302 SendInventory(playersao);
1305 case InventoryLocation::NODEMETA:
1307 v3s16 blockpos = getNodeBlockPos(loc.p);
1309 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1311 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1313 setBlockNotSent(blockpos);
1316 case InventoryLocation::DETACHED:
1318 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1322 sanity_check(false); // abort
1327 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1329 std::vector<u16> clients = m_clients.getClientIDs();
1331 // Set the modified blocks unsent for all the clients
1332 for (std::vector<u16>::iterator i = clients.begin();
1333 i != clients.end(); ++i) {
1334 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1335 client->SetBlocksNotSent(block);
1340 void Server::peerAdded(con::Peer *peer)
1342 DSTACK(__FUNCTION_NAME);
1343 verbosestream<<"Server::peerAdded(): peer->id="
1344 <<peer->id<<std::endl;
1347 c.type = con::PEER_ADDED;
1348 c.peer_id = peer->id;
1350 m_peer_change_queue.push(c);
1353 void Server::deletingPeer(con::Peer *peer, bool timeout)
1355 DSTACK(__FUNCTION_NAME);
1356 verbosestream<<"Server::deletingPeer(): peer->id="
1357 <<peer->id<<", timeout="<<timeout<<std::endl;
1359 m_clients.event(peer->id, CSE_Disconnect);
1361 c.type = con::PEER_REMOVED;
1362 c.peer_id = peer->id;
1363 c.timeout = timeout;
1364 m_peer_change_queue.push(c);
1367 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1369 *retval = m_con.getPeerStat(peer_id,type);
1370 if (*retval == -1) return false;
1374 bool Server::getClientInfo(
1383 std::string* vers_string
1386 *state = m_clients.getClientState(peer_id);
1388 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1390 if (client == NULL) {
1395 *uptime = client->uptime();
1396 *ser_vers = client->serialization_version;
1397 *prot_vers = client->net_proto_version;
1399 *major = client->getMajor();
1400 *minor = client->getMinor();
1401 *patch = client->getPatch();
1402 *vers_string = client->getPatch();
1409 void Server::handlePeerChanges()
1411 while(m_peer_change_queue.size() > 0)
1413 con::PeerChange c = m_peer_change_queue.front();
1414 m_peer_change_queue.pop();
1416 verbosestream<<"Server: Handling peer change: "
1417 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1422 case con::PEER_ADDED:
1423 m_clients.CreateClient(c.peer_id);
1426 case con::PEER_REMOVED:
1427 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1431 FATAL_ERROR("Invalid peer change event received!");
1437 void Server::Send(NetworkPacket* pkt)
1439 m_clients.send(pkt->getPeerId(),
1440 clientCommandFactoryTable[pkt->getCommand()].channel,
1442 clientCommandFactoryTable[pkt->getCommand()].reliable);
1445 void Server::SendMovement(u16 peer_id)
1447 DSTACK(__FUNCTION_NAME);
1448 std::ostringstream os(std::ios_base::binary);
1450 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1452 pkt << g_settings->getFloat("movement_acceleration_default");
1453 pkt << g_settings->getFloat("movement_acceleration_air");
1454 pkt << g_settings->getFloat("movement_acceleration_fast");
1455 pkt << g_settings->getFloat("movement_speed_walk");
1456 pkt << g_settings->getFloat("movement_speed_crouch");
1457 pkt << g_settings->getFloat("movement_speed_fast");
1458 pkt << g_settings->getFloat("movement_speed_climb");
1459 pkt << g_settings->getFloat("movement_speed_jump");
1460 pkt << g_settings->getFloat("movement_liquid_fluidity");
1461 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1462 pkt << g_settings->getFloat("movement_liquid_sink");
1463 pkt << g_settings->getFloat("movement_gravity");
1468 void Server::SendHP(u16 peer_id, u8 hp)
1470 DSTACK(__FUNCTION_NAME);
1472 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1477 void Server::SendBreath(u16 peer_id, u16 breath)
1479 DSTACK(__FUNCTION_NAME);
1481 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1482 pkt << (u16) breath;
1486 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
1488 DSTACK(__FUNCTION_NAME);
1490 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1493 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1494 pkt << custom_reason;
1499 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1501 DSTACK(__FUNCTION_NAME);
1503 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1508 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1509 v3f camera_point_target)
1511 DSTACK(__FUNCTION_NAME);
1513 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1514 pkt << set_camera_point_target << camera_point_target;
1518 void Server::SendItemDef(u16 peer_id,
1519 IItemDefManager *itemdef, u16 protocol_version)
1521 DSTACK(__FUNCTION_NAME);
1523 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1527 u32 length of the next item
1528 zlib-compressed serialized ItemDefManager
1530 std::ostringstream tmp_os(std::ios::binary);
1531 itemdef->serialize(tmp_os, protocol_version);
1532 std::ostringstream tmp_os2(std::ios::binary);
1533 compressZlib(tmp_os.str(), tmp_os2);
1534 pkt.putLongString(tmp_os2.str());
1537 verbosestream << "Server: Sending item definitions to id(" << peer_id
1538 << "): size=" << pkt.getSize() << std::endl;
1543 void Server::SendNodeDef(u16 peer_id,
1544 INodeDefManager *nodedef, u16 protocol_version)
1546 DSTACK(__FUNCTION_NAME);
1548 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1552 u32 length of the next item
1553 zlib-compressed serialized NodeDefManager
1555 std::ostringstream tmp_os(std::ios::binary);
1556 nodedef->serialize(tmp_os, protocol_version);
1557 std::ostringstream tmp_os2(std::ios::binary);
1558 compressZlib(tmp_os.str(), tmp_os2);
1560 pkt.putLongString(tmp_os2.str());
1563 verbosestream << "Server: Sending node definitions to id(" << peer_id
1564 << "): size=" << pkt.getSize() << std::endl;
1570 Non-static send methods
1573 void Server::SendInventory(PlayerSAO* playerSAO)
1575 DSTACK(__FUNCTION_NAME);
1577 UpdateCrafting(playerSAO->getPlayer());
1583 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1585 std::ostringstream os;
1586 playerSAO->getInventory()->serialize(os);
1588 std::string s = os.str();
1590 pkt.putRawString(s.c_str(), s.size());
1594 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1596 DSTACK(__FUNCTION_NAME);
1598 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1601 if (peer_id != PEER_ID_INEXISTENT) {
1605 m_clients.sendToAll(0, &pkt, true);
1609 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1610 const std::string &formname)
1612 DSTACK(__FUNCTION_NAME);
1614 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1616 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1622 // Spawns a particle on peer with peer_id
1623 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1624 float expirationtime, float size, bool collisiondetection,
1625 bool vertical, std::string texture)
1627 DSTACK(__FUNCTION_NAME);
1629 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1631 pkt << pos << velocity << acceleration << expirationtime
1632 << size << collisiondetection;
1633 pkt.putLongString(texture);
1636 if (peer_id != PEER_ID_INEXISTENT) {
1640 m_clients.sendToAll(0, &pkt, true);
1644 // Adds a ParticleSpawner on peer with peer_id
1645 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1646 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1647 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1649 DSTACK(__FUNCTION_NAME);
1651 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1653 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1654 << minacc << maxacc << minexptime << maxexptime << minsize
1655 << maxsize << collisiondetection;
1657 pkt.putLongString(texture);
1659 pkt << id << vertical;
1661 if (peer_id != PEER_ID_INEXISTENT) {
1665 m_clients.sendToAll(0, &pkt, true);
1669 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1671 DSTACK(__FUNCTION_NAME);
1673 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1675 // Ugly error in this packet
1678 if (peer_id != PEER_ID_INEXISTENT) {
1682 m_clients.sendToAll(0, &pkt, true);
1687 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1689 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1691 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1692 << form->text << form->number << form->item << form->dir
1693 << form->align << form->offset << form->world_pos << form->size;
1698 void Server::SendHUDRemove(u16 peer_id, u32 id)
1700 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1705 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1707 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1708 pkt << id << (u8) stat;
1712 case HUD_STAT_SCALE:
1713 case HUD_STAT_ALIGN:
1714 case HUD_STAT_OFFSET:
1715 pkt << *(v2f *) value;
1719 pkt << *(std::string *) value;
1721 case HUD_STAT_WORLD_POS:
1722 pkt << *(v3f *) value;
1725 pkt << *(v2s32 *) value;
1727 case HUD_STAT_NUMBER:
1731 pkt << *(u32 *) value;
1738 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1740 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1742 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1744 pkt << flags << mask;
1749 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1751 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1752 pkt << param << value;
1756 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1757 const std::string &type, const std::vector<std::string> ¶ms)
1759 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1760 pkt << bgcolor << type << (u16) params.size();
1762 for(size_t i=0; i<params.size(); i++)
1768 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1771 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1774 pkt << do_override << (u16) (ratio * 65535);
1779 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1781 DSTACK(__FUNCTION_NAME);
1783 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1784 pkt << time << time_speed;
1786 if (peer_id == PEER_ID_INEXISTENT) {
1787 m_clients.sendToAll(0, &pkt, true);
1794 void Server::SendPlayerHP(u16 peer_id)
1796 DSTACK(__FUNCTION_NAME);
1797 PlayerSAO *playersao = getPlayerSAO(peer_id);
1799 SendHP(peer_id, playersao->getHP());
1800 m_script->player_event(playersao,"health_changed");
1802 // Send to other clients
1803 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1804 ActiveObjectMessage aom(playersao->getId(), true, str);
1805 playersao->m_messages_out.push(aom);
1808 void Server::SendPlayerBreath(u16 peer_id)
1810 DSTACK(__FUNCTION_NAME);
1811 PlayerSAO *playersao = getPlayerSAO(peer_id);
1814 m_script->player_event(playersao, "breath_changed");
1815 SendBreath(peer_id, playersao->getBreath());
1818 void Server::SendMovePlayer(u16 peer_id)
1820 DSTACK(__FUNCTION_NAME);
1821 Player *player = m_env->getPlayer(peer_id);
1824 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1825 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1828 v3f pos = player->getPosition();
1829 f32 pitch = player->getPitch();
1830 f32 yaw = player->getYaw();
1831 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1832 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1833 << " pitch=" << pitch
1841 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1843 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1846 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1847 << animation_frames[3] << animation_speed;
1852 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1854 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1855 pkt << first << third;
1858 void Server::SendPlayerPrivileges(u16 peer_id)
1860 Player *player = m_env->getPlayer(peer_id);
1862 if(player->peer_id == PEER_ID_INEXISTENT)
1865 std::set<std::string> privs;
1866 m_script->getAuth(player->getName(), NULL, &privs);
1868 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1869 pkt << (u16) privs.size();
1871 for(std::set<std::string>::const_iterator i = privs.begin();
1872 i != privs.end(); i++) {
1879 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1881 Player *player = m_env->getPlayer(peer_id);
1883 if(player->peer_id == PEER_ID_INEXISTENT)
1886 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1887 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1891 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1893 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, peer_id);
1894 pkt.putRawString(datas.c_str(), datas.size());
1896 return pkt.getSize();
1899 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas)
1901 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1904 pkt.putRawString(datas.c_str(), datas.size());
1908 s32 Server::playSound(const SimpleSoundSpec &spec,
1909 const ServerSoundParams ¶ms)
1911 // Find out initial position of sound
1912 bool pos_exists = false;
1913 v3f pos = params.getPos(m_env, &pos_exists);
1914 // If position is not found while it should be, cancel sound
1915 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1918 // Filter destination clients
1919 std::vector<u16> dst_clients;
1920 if(params.to_player != "")
1922 Player *player = m_env->getPlayer(params.to_player.c_str());
1924 infostream<<"Server::playSound: Player \""<<params.to_player
1925 <<"\" not found"<<std::endl;
1928 if(player->peer_id == PEER_ID_INEXISTENT){
1929 infostream<<"Server::playSound: Player \""<<params.to_player
1930 <<"\" not connected"<<std::endl;
1933 dst_clients.push_back(player->peer_id);
1936 std::vector<u16> clients = m_clients.getClientIDs();
1938 for(std::vector<u16>::iterator
1939 i = clients.begin(); i != clients.end(); ++i) {
1940 Player *player = m_env->getPlayer(*i);
1945 if(player->getPosition().getDistanceFrom(pos) >
1946 params.max_hear_distance)
1949 dst_clients.push_back(*i);
1953 if(dst_clients.empty())
1957 s32 id = m_next_sound_id++;
1958 // The sound will exist as a reference in m_playing_sounds
1959 m_playing_sounds[id] = ServerPlayingSound();
1960 ServerPlayingSound &psound = m_playing_sounds[id];
1961 psound.params = params;
1963 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1964 pkt << id << spec.name << (float) (spec.gain * params.gain)
1965 << (u8) params.type << pos << params.object << params.loop;
1967 for(std::vector<u16>::iterator i = dst_clients.begin();
1968 i != dst_clients.end(); i++) {
1969 psound.clients.insert(*i);
1970 m_clients.send(*i, 0, &pkt, true);
1974 void Server::stopSound(s32 handle)
1976 // Get sound reference
1977 std::map<s32, ServerPlayingSound>::iterator i =
1978 m_playing_sounds.find(handle);
1979 if(i == m_playing_sounds.end())
1981 ServerPlayingSound &psound = i->second;
1983 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
1986 for(std::set<u16>::iterator i = psound.clients.begin();
1987 i != psound.clients.end(); i++) {
1989 m_clients.send(*i, 0, &pkt, true);
1991 // Remove sound reference
1992 m_playing_sounds.erase(i);
1995 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1996 std::vector<u16> *far_players, float far_d_nodes)
1998 float maxd = far_d_nodes*BS;
1999 v3f p_f = intToFloat(p, BS);
2001 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2004 std::vector<u16> clients = m_clients.getClientIDs();
2005 for(std::vector<u16>::iterator i = clients.begin();
2006 i != clients.end(); ++i) {
2009 if(Player *player = m_env->getPlayer(*i)) {
2010 // If player is far away, only set modified blocks not sent
2011 v3f player_pos = player->getPosition();
2012 if(player_pos.getDistanceFrom(p_f) > maxd) {
2013 far_players->push_back(*i);
2020 m_clients.send(*i, 0, &pkt, true);
2024 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2025 std::vector<u16> *far_players, float far_d_nodes,
2026 bool remove_metadata)
2028 float maxd = far_d_nodes*BS;
2029 v3f p_f = intToFloat(p, BS);
2031 std::vector<u16> clients = m_clients.getClientIDs();
2032 for(std::vector<u16>::iterator i = clients.begin();
2033 i != clients.end(); ++i) {
2037 if(Player *player = m_env->getPlayer(*i)) {
2038 // If player is far away, only set modified blocks not sent
2039 v3f player_pos = player->getPosition();
2040 if(player_pos.getDistanceFrom(p_f) > maxd) {
2041 far_players->push_back(*i);
2047 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2049 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2051 pkt << p << n.param0 << n.param1 << n.param2
2052 << (u8) (remove_metadata ? 0 : 1);
2054 if (!remove_metadata) {
2055 if (client->net_proto_version <= 21) {
2056 // Old clients always clear metadata; fix it
2057 // by sending the full block again.
2058 client->SetBlockNotSent(p);
2065 if (pkt.getSize() > 0)
2066 m_clients.send(*i, 0, &pkt, true);
2070 void Server::setBlockNotSent(v3s16 p)
2072 std::vector<u16> clients = m_clients.getClientIDs();
2074 for(std::vector<u16>::iterator i = clients.begin();
2075 i != clients.end(); ++i) {
2076 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2077 client->SetBlockNotSent(p);
2082 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2084 DSTACK(__FUNCTION_NAME);
2086 v3s16 p = block->getPos();
2089 Create a packet with the block in the right format
2092 std::ostringstream os(std::ios_base::binary);
2093 block->serialize(os, ver, false);
2094 block->serializeNetworkSpecific(os, net_proto_version);
2095 std::string s = os.str();
2097 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2100 pkt.putRawString(s.c_str(), s.size());
2104 void Server::SendBlocks(float dtime)
2106 DSTACK(__FUNCTION_NAME);
2108 JMutexAutoLock envlock(m_env_mutex);
2109 //TODO check if one big lock could be faster then multiple small ones
2111 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2113 std::vector<PrioritySortedBlockTransfer> queue;
2115 s32 total_sending = 0;
2118 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2120 std::vector<u16> clients = m_clients.getClientIDs();
2123 for(std::vector<u16>::iterator i = clients.begin();
2124 i != clients.end(); ++i) {
2125 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2130 total_sending += client->SendingCount();
2131 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2137 // Lowest priority number comes first.
2138 // Lowest is most important.
2139 std::sort(queue.begin(), queue.end());
2142 for(u32 i=0; i<queue.size(); i++)
2144 //TODO: Calculate limit dynamically
2145 if(total_sending >= g_settings->getS32
2146 ("max_simultaneous_block_sends_server_total"))
2149 PrioritySortedBlockTransfer q = queue[i];
2151 MapBlock *block = NULL;
2154 block = m_env->getMap().getBlockNoCreate(q.pos);
2156 catch(InvalidPositionException &e)
2161 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2166 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2168 client->SentBlock(q.pos);
2174 void Server::fillMediaCache()
2176 DSTACK(__FUNCTION_NAME);
2178 infostream<<"Server: Calculating media file checksums"<<std::endl;
2180 // Collect all media file paths
2181 std::vector<std::string> paths;
2182 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2183 i != m_mods.end(); i++) {
2184 const ModSpec &mod = *i;
2185 paths.push_back(mod.path + DIR_DELIM + "textures");
2186 paths.push_back(mod.path + DIR_DELIM + "sounds");
2187 paths.push_back(mod.path + DIR_DELIM + "media");
2188 paths.push_back(mod.path + DIR_DELIM + "models");
2190 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2192 // Collect media file information from paths into cache
2193 for(std::vector<std::string>::iterator i = paths.begin();
2194 i != paths.end(); i++) {
2195 std::string mediapath = *i;
2196 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2197 for (u32 j = 0; j < dirlist.size(); j++) {
2198 if (dirlist[j].dir) // Ignode dirs
2200 std::string filename = dirlist[j].name;
2201 // If name contains illegal characters, ignore the file
2202 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2203 infostream<<"Server: ignoring illegal file name: \""
2204 << filename << "\"" << std::endl;
2207 // If name is not in a supported format, ignore it
2208 const char *supported_ext[] = {
2209 ".png", ".jpg", ".bmp", ".tga",
2210 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2212 ".x", ".b3d", ".md2", ".obj",
2215 if (removeStringEnd(filename, supported_ext) == ""){
2216 infostream << "Server: ignoring unsupported file extension: \""
2217 << filename << "\"" << std::endl;
2220 // Ok, attempt to load the file and add to cache
2221 std::string filepath = mediapath + DIR_DELIM + filename;
2223 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2225 errorstream << "Server::fillMediaCache(): Could not open \""
2226 << filename << "\" for reading" << std::endl;
2229 std::ostringstream tmp_os(std::ios_base::binary);
2233 fis.read(buf, 1024);
2234 std::streamsize len = fis.gcount();
2235 tmp_os.write(buf, len);
2244 errorstream<<"Server::fillMediaCache(): Failed to read \""
2245 << filename << "\"" << std::endl;
2248 if(tmp_os.str().length() == 0) {
2249 errorstream << "Server::fillMediaCache(): Empty file \""
2250 << filepath << "\"" << std::endl;
2255 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2257 unsigned char *digest = sha1.getDigest();
2258 std::string sha1_base64 = base64_encode(digest, 20);
2259 std::string sha1_hex = hex_encode((char*)digest, 20);
2263 m_media[filename] = MediaInfo(filepath, sha1_base64);
2264 verbosestream << "Server: " << sha1_hex << " is " << filename
2270 struct SendableMediaAnnouncement
2273 std::string sha1_digest;
2275 SendableMediaAnnouncement(const std::string &name_="",
2276 const std::string &sha1_digest_=""):
2278 sha1_digest(sha1_digest_)
2282 void Server::sendMediaAnnouncement(u16 peer_id)
2284 DSTACK(__FUNCTION_NAME);
2286 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2289 std::vector<SendableMediaAnnouncement> file_announcements;
2291 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2292 i != m_media.end(); i++){
2294 file_announcements.push_back(
2295 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2299 std::ostringstream os(std::ios_base::binary);
2301 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2302 pkt << (u16) file_announcements.size();
2304 for (std::vector<SendableMediaAnnouncement>::iterator
2305 j = file_announcements.begin();
2306 j != file_announcements.end(); ++j) {
2307 pkt << j->name << j->sha1_digest;
2310 pkt << g_settings->get("remote_media");
2314 struct SendableMedia
2320 SendableMedia(const std::string &name_="", const std::string &path_="",
2321 const std::string &data_=""):
2328 void Server::sendRequestedMedia(u16 peer_id,
2329 const std::vector<std::string> &tosend)
2331 DSTACK(__FUNCTION_NAME);
2333 verbosestream<<"Server::sendRequestedMedia(): "
2334 <<"Sending files to client"<<std::endl;
2338 // Put 5kB in one bunch (this is not accurate)
2339 u32 bytes_per_bunch = 5000;
2341 std::vector< std::vector<SendableMedia> > file_bunches;
2342 file_bunches.push_back(std::vector<SendableMedia>());
2344 u32 file_size_bunch_total = 0;
2346 for(std::vector<std::string>::const_iterator i = tosend.begin();
2347 i != tosend.end(); ++i) {
2348 const std::string &name = *i;
2350 if(m_media.find(name) == m_media.end()) {
2351 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2352 <<"unknown file \""<<(name)<<"\""<<std::endl;
2356 //TODO get path + name
2357 std::string tpath = m_media[name].path;
2360 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2361 if(fis.good() == false){
2362 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2363 <<tpath<<"\" for reading"<<std::endl;
2366 std::ostringstream tmp_os(std::ios_base::binary);
2370 fis.read(buf, 1024);
2371 std::streamsize len = fis.gcount();
2372 tmp_os.write(buf, len);
2373 file_size_bunch_total += len;
2382 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2383 <<name<<"\""<<std::endl;
2386 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2387 <<tname<<"\""<<std::endl;*/
2389 file_bunches[file_bunches.size()-1].push_back(
2390 SendableMedia(name, tpath, tmp_os.str()));
2392 // Start next bunch if got enough data
2393 if(file_size_bunch_total >= bytes_per_bunch) {
2394 file_bunches.push_back(std::vector<SendableMedia>());
2395 file_size_bunch_total = 0;
2400 /* Create and send packets */
2402 u16 num_bunches = file_bunches.size();
2403 for(u16 i = 0; i < num_bunches; i++) {
2406 u16 total number of texture bunches
2407 u16 index of this bunch
2408 u32 number of files in this bunch
2417 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2418 pkt << num_bunches << i << (u32) file_bunches[i].size();
2420 for(std::vector<SendableMedia>::iterator
2421 j = file_bunches[i].begin();
2422 j != file_bunches[i].end(); ++j) {
2424 pkt.putLongString(j->data);
2427 verbosestream << "Server::sendRequestedMedia(): bunch "
2428 << i << "/" << num_bunches
2429 << " files=" << file_bunches[i].size()
2430 << " size=" << pkt.getSize() << std::endl;
2435 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2437 if(m_detached_inventories.count(name) == 0) {
2438 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2441 Inventory *inv = m_detached_inventories[name];
2442 std::ostringstream os(std::ios_base::binary);
2444 os << serializeString(name);
2448 std::string s = os.str();
2450 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2451 pkt.putRawString(s.c_str(), s.size());
2453 if (peer_id != PEER_ID_INEXISTENT) {
2457 m_clients.sendToAll(0, &pkt, true);
2461 void Server::sendDetachedInventories(u16 peer_id)
2463 DSTACK(__FUNCTION_NAME);
2465 for(std::map<std::string, Inventory*>::iterator
2466 i = m_detached_inventories.begin();
2467 i != m_detached_inventories.end(); i++) {
2468 const std::string &name = i->first;
2469 //Inventory *inv = i->second;
2470 sendDetachedInventory(name, peer_id);
2478 void Server::DiePlayer(u16 peer_id)
2480 DSTACK(__FUNCTION_NAME);
2482 PlayerSAO *playersao = getPlayerSAO(peer_id);
2485 infostream << "Server::DiePlayer(): Player "
2486 << playersao->getPlayer()->getName()
2487 << " dies" << std::endl;
2489 playersao->setHP(0);
2491 // Trigger scripted stuff
2492 m_script->on_dieplayer(playersao);
2494 SendPlayerHP(peer_id);
2495 SendDeathscreen(peer_id, false, v3f(0,0,0));
2498 void Server::RespawnPlayer(u16 peer_id)
2500 DSTACK(__FUNCTION_NAME);
2502 PlayerSAO *playersao = getPlayerSAO(peer_id);
2505 infostream << "Server::RespawnPlayer(): Player "
2506 << playersao->getPlayer()->getName()
2507 << " respawns" << std::endl;
2509 playersao->setHP(PLAYER_MAX_HP);
2510 playersao->setBreath(PLAYER_MAX_BREATH);
2512 SendPlayerHP(peer_id);
2513 SendPlayerBreath(peer_id);
2515 bool repositioned = m_script->on_respawnplayer(playersao);
2517 v3f pos = findSpawnPos(m_env->getServerMap());
2518 // setPos will send the new position to client
2519 playersao->setPos(pos);
2523 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2525 DSTACK(__FUNCTION_NAME);
2527 SendAccessDenied(peer_id, reason, custom_reason);
2528 m_clients.event(peer_id, CSE_SetDenied);
2529 m_con.DisconnectPeer(peer_id);
2532 // 13/03/15: remove this function when protocol version 25 will become
2533 // the minimum version for MT users, maybe in 1 year
2534 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2536 DSTACK(__FUNCTION_NAME);
2538 SendAccessDenied_Legacy(peer_id, reason);
2539 m_clients.event(peer_id, CSE_SetDenied);
2540 m_con.DisconnectPeer(peer_id);
2543 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2545 DSTACK(__FUNCTION_NAME);
2546 std::wstring message;
2549 Clear references to playing sounds
2551 for(std::map<s32, ServerPlayingSound>::iterator
2552 i = m_playing_sounds.begin();
2553 i != m_playing_sounds.end();)
2555 ServerPlayingSound &psound = i->second;
2556 psound.clients.erase(peer_id);
2557 if(psound.clients.empty())
2558 m_playing_sounds.erase(i++);
2563 Player *player = m_env->getPlayer(peer_id);
2565 // Collect information about leaving in chat
2567 if(player != NULL && reason != CDR_DENY)
2569 std::wstring name = narrow_to_wide(player->getName());
2572 message += L" left the game.";
2573 if(reason == CDR_TIMEOUT)
2574 message += L" (timed out)";
2578 /* Run scripts and remove from environment */
2582 PlayerSAO *playersao = player->getPlayerSAO();
2585 m_script->on_leaveplayer(playersao);
2587 playersao->disconnected();
2595 if(player != NULL && reason != CDR_DENY) {
2596 std::ostringstream os(std::ios_base::binary);
2597 std::vector<u16> clients = m_clients.getClientIDs();
2599 for(std::vector<u16>::iterator i = clients.begin();
2600 i != clients.end(); ++i) {
2602 Player *player = m_env->getPlayer(*i);
2606 // Get name of player
2607 os << player->getName() << " ";
2610 actionstream << player->getName() << " "
2611 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2612 << " List of players: " << os.str() << std::endl;
2616 JMutexAutoLock env_lock(m_env_mutex);
2617 m_clients.DeleteClient(peer_id);
2621 // Send leave chat message to all remaining clients
2622 if(message.length() != 0)
2623 SendChatMessage(PEER_ID_INEXISTENT,message);
2626 void Server::UpdateCrafting(Player* player)
2628 DSTACK(__FUNCTION_NAME);
2630 // Get a preview for crafting
2632 InventoryLocation loc;
2633 loc.setPlayer(player->getName());
2634 getCraftingResult(&player->inventory, preview, false, this);
2635 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2637 // Put the new preview in
2638 InventoryList *plist = player->inventory.getList("craftpreview");
2639 sanity_check(plist);
2640 sanity_check(plist->getSize() >= 1);
2641 plist->changeItem(0, preview);
2644 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2646 RemoteClient *client = getClientNoEx(peer_id,state_min);
2648 throw ClientNotFoundException("Client not found");
2652 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2654 return m_clients.getClientNoEx(peer_id, state_min);
2657 std::string Server::getPlayerName(u16 peer_id)
2659 Player *player = m_env->getPlayer(peer_id);
2661 return "[id="+itos(peer_id)+"]";
2662 return player->getName();
2665 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2667 Player *player = m_env->getPlayer(peer_id);
2670 return player->getPlayerSAO();
2673 std::wstring Server::getStatusString()
2675 std::wostringstream os(std::ios_base::binary);
2678 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2680 os<<L", uptime="<<m_uptime.get();
2682 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2683 // Information about clients
2686 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);
2691 // Get name of player
2692 std::wstring name = L"unknown";
2694 name = narrow_to_wide(player->getName());
2695 // Add name to information string
2703 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2704 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2705 if(g_settings->get("motd") != "")
2706 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2710 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2712 std::set<std::string> privs;
2713 m_script->getAuth(name, NULL, &privs);
2717 bool Server::checkPriv(const std::string &name, const std::string &priv)
2719 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2720 return (privs.count(priv) != 0);
2723 void Server::reportPrivsModified(const std::string &name)
2726 std::vector<u16> clients = m_clients.getClientIDs();
2727 for(std::vector<u16>::iterator i = clients.begin();
2728 i != clients.end(); ++i) {
2729 Player *player = m_env->getPlayer(*i);
2730 reportPrivsModified(player->getName());
2733 Player *player = m_env->getPlayer(name.c_str());
2736 SendPlayerPrivileges(player->peer_id);
2737 PlayerSAO *sao = player->getPlayerSAO();
2740 sao->updatePrivileges(
2741 getPlayerEffectivePrivs(name),
2746 void Server::reportInventoryFormspecModified(const std::string &name)
2748 Player *player = m_env->getPlayer(name.c_str());
2751 SendPlayerInventoryFormspec(player->peer_id);
2754 void Server::setIpBanned(const std::string &ip, const std::string &name)
2756 m_banmanager->add(ip, name);
2759 void Server::unsetIpBanned(const std::string &ip_or_name)
2761 m_banmanager->remove(ip_or_name);
2764 std::string Server::getBanDescription(const std::string &ip_or_name)
2766 return m_banmanager->getBanDescription(ip_or_name);
2769 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2771 Player *player = m_env->getPlayer(name);
2775 if (player->peer_id == PEER_ID_INEXISTENT)
2778 SendChatMessage(player->peer_id, msg);
2781 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2783 Player *player = m_env->getPlayer(playername);
2787 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2791 SendShowFormspecMessage(player->peer_id, formspec, formname);
2795 u32 Server::hudAdd(Player *player, HudElement *form) {
2799 u32 id = player->addHud(form);
2801 SendHUDAdd(player->peer_id, id, form);
2806 bool Server::hudRemove(Player *player, u32 id) {
2810 HudElement* todel = player->removeHud(id);
2817 SendHUDRemove(player->peer_id, id);
2821 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2825 SendHUDChange(player->peer_id, id, stat, data);
2829 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2833 SendHUDSetFlags(player->peer_id, flags, mask);
2834 player->hud_flags = flags;
2836 PlayerSAO* playersao = player->getPlayerSAO();
2838 if (playersao == NULL)
2841 m_script->player_event(playersao, "hud_changed");
2845 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2848 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2851 std::ostringstream os(std::ios::binary);
2852 writeS32(os, hotbar_itemcount);
2853 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2857 void Server::hudSetHotbarImage(Player *player, std::string name) {
2861 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2864 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2868 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2871 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2876 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2880 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2885 SendEyeOffset(player->peer_id, first, third);
2889 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2890 const std::string &type, const std::vector<std::string> ¶ms)
2895 SendSetSky(player->peer_id, bgcolor, type, params);
2899 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2905 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2909 void Server::notifyPlayers(const std::wstring &msg)
2911 SendChatMessage(PEER_ID_INEXISTENT,msg);
2914 void Server::spawnParticle(const char *playername, v3f pos,
2915 v3f velocity, v3f acceleration,
2916 float expirationtime, float size, bool
2917 collisiondetection, bool vertical, std::string texture)
2919 Player *player = m_env->getPlayer(playername);
2922 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2923 expirationtime, size, collisiondetection, vertical, texture);
2926 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2927 float expirationtime, float size,
2928 bool collisiondetection, bool vertical, std::string texture)
2930 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2931 expirationtime, size, collisiondetection, vertical, texture);
2934 u32 Server::addParticleSpawner(const char *playername,
2935 u16 amount, float spawntime,
2936 v3f minpos, v3f maxpos,
2937 v3f minvel, v3f maxvel,
2938 v3f minacc, v3f maxacc,
2939 float minexptime, float maxexptime,
2940 float minsize, float maxsize,
2941 bool collisiondetection, bool vertical, std::string texture)
2943 Player *player = m_env->getPlayer(playername);
2948 for(;;) // look for unused particlespawner id
2951 if (std::find(m_particlespawner_ids.begin(),
2952 m_particlespawner_ids.end(), id)
2953 == m_particlespawner_ids.end())
2955 m_particlespawner_ids.push_back(id);
2960 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2961 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2962 minexptime, maxexptime, minsize, maxsize,
2963 collisiondetection, vertical, texture, id);
2968 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2969 v3f minpos, v3f maxpos,
2970 v3f minvel, v3f maxvel,
2971 v3f minacc, v3f maxacc,
2972 float minexptime, float maxexptime,
2973 float minsize, float maxsize,
2974 bool collisiondetection, bool vertical, std::string texture)
2977 for(;;) // look for unused particlespawner id
2980 if (std::find(m_particlespawner_ids.begin(),
2981 m_particlespawner_ids.end(), id)
2982 == m_particlespawner_ids.end())
2984 m_particlespawner_ids.push_back(id);
2989 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2990 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2991 minexptime, maxexptime, minsize, maxsize,
2992 collisiondetection, vertical, texture, id);
2997 void Server::deleteParticleSpawner(const char *playername, u32 id)
2999 Player *player = m_env->getPlayer(playername);
3003 m_particlespawner_ids.erase(
3004 std::remove(m_particlespawner_ids.begin(),
3005 m_particlespawner_ids.end(), id),
3006 m_particlespawner_ids.end());
3007 SendDeleteParticleSpawner(player->peer_id, id);
3010 void Server::deleteParticleSpawnerAll(u32 id)
3012 m_particlespawner_ids.erase(
3013 std::remove(m_particlespawner_ids.begin(),
3014 m_particlespawner_ids.end(), id),
3015 m_particlespawner_ids.end());
3016 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3019 Inventory* Server::createDetachedInventory(const std::string &name)
3021 if(m_detached_inventories.count(name) > 0){
3022 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3023 delete m_detached_inventories[name];
3025 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3027 Inventory *inv = new Inventory(m_itemdef);
3029 m_detached_inventories[name] = inv;
3030 //TODO find a better way to do this
3031 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3038 BoolScopeSet(bool *dst, bool val):
3041 m_orig_state = *m_dst;
3046 *m_dst = m_orig_state;
3053 // actions: time-reversed list
3054 // Return value: success/failure
3055 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3056 std::list<std::string> *log)
3058 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3059 ServerMap *map = (ServerMap*)(&m_env->getMap());
3061 // Fail if no actions to handle
3062 if(actions.empty()){
3063 log->push_back("Nothing to do.");
3070 for(std::list<RollbackAction>::const_iterator
3071 i = actions.begin();
3072 i != actions.end(); i++)
3074 const RollbackAction &action = *i;
3076 bool success = action.applyRevert(map, this, this);
3079 std::ostringstream os;
3080 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3081 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3083 log->push_back(os.str());
3085 std::ostringstream os;
3086 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3087 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3089 log->push_back(os.str());
3093 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3094 <<" failed"<<std::endl;
3096 // Call it done if less than half failed
3097 return num_failed <= num_tried/2;
3100 // IGameDef interface
3102 IItemDefManager* Server::getItemDefManager()
3106 INodeDefManager* Server::getNodeDefManager()
3110 ICraftDefManager* Server::getCraftDefManager()
3114 ITextureSource* Server::getTextureSource()
3118 IShaderSource* Server::getShaderSource()
3122 scene::ISceneManager* Server::getSceneManager()
3127 u16 Server::allocateUnknownNodeId(const std::string &name)
3129 return m_nodedef->allocateDummy(name);
3131 ISoundManager* Server::getSoundManager()
3133 return &dummySoundManager;
3135 MtEventManager* Server::getEventManager()
3140 IWritableItemDefManager* Server::getWritableItemDefManager()
3144 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3148 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3153 const ModSpec* Server::getModSpec(const std::string &modname)
3155 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3156 i != m_mods.end(); i++){
3157 const ModSpec &mod = *i;
3158 if(mod.name == modname)
3163 void Server::getModNames(std::vector<std::string> &modlist)
3165 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3166 modlist.push_back(i->name);
3169 std::string Server::getBuiltinLuaPath()
3171 return porting::path_share + DIR_DELIM + "builtin";
3174 v3f findSpawnPos(ServerMap &map)
3176 //return v3f(50,50,50)*BS;
3181 nodepos = v2s16(0,0);
3186 s16 water_level = map.getWaterLevel();
3188 // Try to find a good place a few times
3189 for(s32 i=0; i<1000; i++)
3192 // We're going to try to throw the player to this position
3193 v2s16 nodepos2d = v2s16(
3194 -range + (myrand() % (range * 2)),
3195 -range + (myrand() % (range * 2)));
3197 // Get ground height at point
3198 s16 groundheight = map.findGroundLevel(nodepos2d);
3199 if (groundheight <= water_level) // Don't go underwater
3201 if (groundheight > water_level + 6) // Don't go to high places
3204 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3205 bool is_good = false;
3207 for (s32 i = 0; i < 10; i++) {
3208 v3s16 blockpos = getNodeBlockPos(nodepos);
3209 map.emergeBlock(blockpos, true);
3210 content_t c = map.getNodeNoEx(nodepos).getContent();
3211 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3213 if (air_count >= 2){
3221 // Found a good place
3222 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3228 return intToFloat(nodepos, BS);
3231 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3233 bool newplayer = false;
3236 Try to get an existing player
3238 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3240 // If player is already connected, cancel
3241 if(player != NULL && player->peer_id != 0)
3243 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3248 If player with the wanted peer_id already exists, cancel.
3250 if(m_env->getPlayer(peer_id) != NULL)
3252 infostream<<"emergePlayer(): Player with wrong name but same"
3253 " peer_id already exists"<<std::endl;
3257 // Load player if it isn't already loaded
3259 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3262 // Create player if it doesn't exist
3265 player = new RemotePlayer(this, name);
3266 // Set player position
3267 infostream<<"Server: Finding spawn place for player \""
3268 <<name<<"\""<<std::endl;
3269 v3f pos = findSpawnPos(m_env->getServerMap());
3270 player->setPosition(pos);
3272 // Make sure the player is saved
3273 player->setModified(true);
3275 // Add player to environment
3276 m_env->addPlayer(player);
3279 // Create a new player active object
3280 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3281 getPlayerEffectivePrivs(player->getName()),
3284 /* Clean up old HUD elements from previous sessions */
3287 /* Add object to environment */
3288 m_env->addActiveObject(playersao);
3292 m_script->on_newplayer(playersao);
3298 void dedicated_server_loop(Server &server, bool &kill)
3300 DSTACK(__FUNCTION_NAME);
3302 verbosestream<<"dedicated_server_loop()"<<std::endl;
3304 IntervalLimiter m_profiler_interval;
3308 float steplen = g_settings->getFloat("dedicated_server_step");
3309 // This is kind of a hack but can be done like this
3310 // because server.step() is very light
3312 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3313 sleep_ms((int)(steplen*1000.0));
3315 server.step(steplen);
3317 if(server.getShutdownRequested() || kill)
3319 infostream<<"Dedicated server quitting"<<std::endl;
3321 if(g_settings->getBool("server_announce"))
3322 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3330 float profiler_print_interval =
3331 g_settings->getFloat("profiler_print_interval");
3332 if(profiler_print_interval != 0)
3334 if(m_profiler_interval.step(steplen, profiler_print_interval))
3336 infostream<<"Profiler:"<<std::endl;
3337 g_profiler->print(infostream);
3338 g_profiler->clear();