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 // Throw if fatal error occurred in thread
483 std::string async_err = m_async_fatal_error.get();
485 throw ServerError(async_err);
489 void Server::AsyncRunStep(bool initial_step)
491 DSTACK(__FUNCTION_NAME);
493 g_profiler->add("Server::AsyncRunStep (num)", 1);
497 JMutexAutoLock lock1(m_step_dtime_mutex);
498 dtime = m_step_dtime;
502 // Send blocks to clients
506 if((dtime < 0.001) && (initial_step == false))
509 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
511 //infostream<<"Server steps "<<dtime<<std::endl;
512 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
515 JMutexAutoLock lock1(m_step_dtime_mutex);
516 m_step_dtime -= dtime;
523 m_uptime.set(m_uptime.get() + dtime);
529 Update time of day and overall game time
531 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
534 Send to clients at constant intervals
537 m_time_of_day_send_timer -= dtime;
538 if(m_time_of_day_send_timer < 0.0) {
539 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
540 u16 time = m_env->getTimeOfDay();
541 float time_speed = g_settings->getFloat("time_speed");
542 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
546 JMutexAutoLock lock(m_env_mutex);
547 // Figure out and report maximum lag to environment
548 float max_lag = m_env->getMaxLagEstimate();
549 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
551 if(dtime > 0.1 && dtime > max_lag * 2.0)
552 infostream<<"Server: Maximum lag peaked to "<<dtime
556 m_env->reportMaxLagEstimate(max_lag);
558 ScopeProfiler sp(g_profiler, "SEnv step");
559 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
563 static const float map_timer_and_unload_dtime = 2.92;
564 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
566 JMutexAutoLock lock(m_env_mutex);
567 // Run Map's timers and unload unused data
568 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
569 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
570 g_settings->getFloat("server_unload_unused_data_timeout"));
577 /* Transform liquids */
578 m_liquid_transform_timer += dtime;
579 if(m_liquid_transform_timer >= m_liquid_transform_every)
581 m_liquid_transform_timer -= m_liquid_transform_every;
583 JMutexAutoLock lock(m_env_mutex);
585 ScopeProfiler sp(g_profiler, "Server: liquid transform");
587 std::map<v3s16, MapBlock*> modified_blocks;
588 m_env->getMap().transformLiquids(modified_blocks);
593 core::map<v3s16, MapBlock*> lighting_modified_blocks;
594 ServerMap &map = ((ServerMap&)m_env->getMap());
595 map.updateLighting(modified_blocks, lighting_modified_blocks);
597 // Add blocks modified by lighting to modified_blocks
598 for(core::map<v3s16, MapBlock*>::Iterator
599 i = lighting_modified_blocks.getIterator();
600 i.atEnd() == false; i++)
602 MapBlock *block = i.getNode()->getValue();
603 modified_blocks.insert(block->getPos(), block);
607 Set the modified blocks unsent for all the clients
609 if(!modified_blocks.empty())
611 SetBlocksNotSent(modified_blocks);
614 m_clients.step(dtime);
616 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
618 // send masterserver announce
620 float &counter = m_masterserver_timer;
621 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
622 g_settings->getBool("server_announce"))
624 ServerList::sendAnnounce(counter ? "update" : "start",
625 m_bind_addr.getPort(),
626 m_clients.getPlayerNames(),
628 m_env->getGameTime(),
631 m_emerge->params.mg_name,
640 Check added and deleted active objects
643 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
644 JMutexAutoLock envlock(m_env_mutex);
647 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
648 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
650 // Radius inside which objects are active
651 s16 radius = g_settings->getS16("active_object_send_range_blocks");
652 s16 player_radius = g_settings->getS16("player_transfer_distance");
654 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
655 !g_settings->getBool("unlimited_player_transfer_distance"))
656 player_radius = radius;
658 radius *= MAP_BLOCKSIZE;
659 player_radius *= MAP_BLOCKSIZE;
661 for(std::map<u16, RemoteClient*>::iterator
663 i != clients.end(); ++i)
665 RemoteClient *client = i->second;
667 // If definitions and textures have not been sent, don't
668 // send objects either
669 if (client->getState() < CS_DefinitionsSent)
672 Player *player = m_env->getPlayer(client->peer_id);
675 // This can happen if the client timeouts somehow
676 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
678 <<" has no associated player"<<std::endl;*/
681 v3s16 pos = floatToInt(player->getPosition(), BS);
683 std::set<u16> removed_objects;
684 std::set<u16> added_objects;
685 m_env->getRemovedActiveObjects(pos, radius, player_radius,
686 client->m_known_objects, removed_objects);
687 m_env->getAddedActiveObjects(pos, radius, player_radius,
688 client->m_known_objects, added_objects);
690 // Ignore if nothing happened
691 if(removed_objects.empty() && added_objects.empty())
693 //infostream<<"active objects: none changed"<<std::endl;
697 std::string data_buffer;
701 // Handle removed objects
702 writeU16((u8*)buf, removed_objects.size());
703 data_buffer.append(buf, 2);
704 for(std::set<u16>::iterator
705 i = removed_objects.begin();
706 i != removed_objects.end(); ++i)
710 ServerActiveObject* obj = m_env->getActiveObject(id);
712 // Add to data buffer for sending
713 writeU16((u8*)buf, id);
714 data_buffer.append(buf, 2);
716 // Remove from known objects
717 client->m_known_objects.erase(id);
719 if(obj && obj->m_known_by_count > 0)
720 obj->m_known_by_count--;
723 // Handle added objects
724 writeU16((u8*)buf, added_objects.size());
725 data_buffer.append(buf, 2);
726 for(std::set<u16>::iterator
727 i = added_objects.begin();
728 i != added_objects.end(); ++i)
732 ServerActiveObject* obj = m_env->getActiveObject(id);
735 u8 type = ACTIVEOBJECT_TYPE_INVALID;
737 infostream<<"WARNING: "<<__FUNCTION_NAME
738 <<": NULL object"<<std::endl;
740 type = obj->getSendType();
742 // Add to data buffer for sending
743 writeU16((u8*)buf, id);
744 data_buffer.append(buf, 2);
745 writeU8((u8*)buf, type);
746 data_buffer.append(buf, 1);
749 data_buffer.append(serializeLongString(
750 obj->getClientInitializationData(client->net_proto_version)));
752 data_buffer.append(serializeLongString(""));
754 // Add to known objects
755 client->m_known_objects.insert(id);
758 obj->m_known_by_count++;
761 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
762 verbosestream << "Server: Sent object remove/add: "
763 << removed_objects.size() << " removed, "
764 << added_objects.size() << " added, "
765 << "packet size is " << pktSize << std::endl;
774 JMutexAutoLock envlock(m_env_mutex);
775 ScopeProfiler sp(g_profiler, "Server: sending object messages");
778 // Value = data sent by object
779 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
781 // Get active object messages from environment
783 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
787 std::vector<ActiveObjectMessage>* message_list = NULL;
788 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
789 n = buffered_messages.find(aom.id);
790 if (n == buffered_messages.end()) {
791 message_list = new std::vector<ActiveObjectMessage>;
792 buffered_messages[aom.id] = message_list;
795 message_list = n->second;
797 message_list->push_back(aom);
801 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
802 // Route data to every client
803 for (std::map<u16, RemoteClient*>::iterator
805 i != clients.end(); ++i) {
806 RemoteClient *client = i->second;
807 std::string reliable_data;
808 std::string unreliable_data;
809 // Go through all objects in message buffer
810 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
811 j = buffered_messages.begin();
812 j != buffered_messages.end(); ++j) {
813 // If object is not known by client, skip it
815 if (client->m_known_objects.find(id) == client->m_known_objects.end())
818 // Get message list of object
819 std::vector<ActiveObjectMessage>* list = j->second;
820 // Go through every message
821 for (std::vector<ActiveObjectMessage>::iterator
822 k = list->begin(); k != list->end(); ++k) {
823 // Compose the full new data with header
824 ActiveObjectMessage aom = *k;
825 std::string new_data;
828 writeU16((u8*)&buf[0], aom.id);
829 new_data.append(buf, 2);
831 new_data += serializeString(aom.datastring);
832 // Add data to buffer
834 reliable_data += new_data;
836 unreliable_data += new_data;
840 reliable_data and unreliable_data are now ready.
843 if(reliable_data.size() > 0) {
844 SendActiveObjectMessages(client->peer_id, reliable_data);
847 if(unreliable_data.size() > 0) {
848 SendActiveObjectMessages(client->peer_id, unreliable_data);
853 // Clear buffered_messages
854 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
855 i = buffered_messages.begin();
856 i != buffered_messages.end(); ++i) {
862 Send queued-for-sending map edit events.
865 // We will be accessing the environment
866 JMutexAutoLock lock(m_env_mutex);
868 // Don't send too many at a time
871 // Single change sending is disabled if queue size is not small
872 bool disable_single_change_sending = false;
873 if(m_unsent_map_edit_queue.size() >= 4)
874 disable_single_change_sending = true;
876 int event_count = m_unsent_map_edit_queue.size();
878 // We'll log the amount of each
881 while(m_unsent_map_edit_queue.size() != 0)
883 MapEditEvent* event = m_unsent_map_edit_queue.front();
884 m_unsent_map_edit_queue.pop();
886 // Players far away from the change are stored here.
887 // Instead of sending the changes, MapBlocks are set not sent
889 std::vector<u16> far_players;
891 switch (event->type) {
894 prof.add("MEET_ADDNODE", 1);
895 sendAddNode(event->p, event->n, event->already_known_by_peer,
896 &far_players, disable_single_change_sending ? 5 : 30,
897 event->type == MEET_ADDNODE);
899 case MEET_REMOVENODE:
900 prof.add("MEET_REMOVENODE", 1);
901 sendRemoveNode(event->p, event->already_known_by_peer,
902 &far_players, disable_single_change_sending ? 5 : 30);
904 case MEET_BLOCK_NODE_METADATA_CHANGED:
905 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
906 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
907 setBlockNotSent(event->p);
910 infostream << "Server: MEET_OTHER" << std::endl;
911 prof.add("MEET_OTHER", 1);
912 for(std::set<v3s16>::iterator
913 i = event->modified_blocks.begin();
914 i != event->modified_blocks.end(); ++i) {
919 prof.add("unknown", 1);
920 infostream << "WARNING: Server: Unknown MapEditEvent "
921 << ((u32)event->type) << std::endl;
926 Set blocks not sent to far players
928 if(!far_players.empty()) {
929 // Convert list format to that wanted by SetBlocksNotSent
930 std::map<v3s16, MapBlock*> modified_blocks2;
931 for(std::set<v3s16>::iterator
932 i = event->modified_blocks.begin();
933 i != event->modified_blocks.end(); ++i) {
934 modified_blocks2[*i] =
935 m_env->getMap().getBlockNoCreateNoEx(*i);
938 // Set blocks not sent
939 for(std::vector<u16>::iterator
940 i = far_players.begin();
941 i != far_players.end(); ++i) {
942 if(RemoteClient *client = getClient(*i))
943 client->SetBlocksNotSent(modified_blocks2);
949 /*// Don't send too many at a time
951 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
955 if(event_count >= 5){
956 infostream<<"Server: MapEditEvents:"<<std::endl;
957 prof.print(infostream);
958 } else if(event_count != 0){
959 verbosestream<<"Server: MapEditEvents:"<<std::endl;
960 prof.print(verbosestream);
966 Trigger emergethread (it somehow gets to a non-triggered but
967 bysy state sometimes)
970 float &counter = m_emergethread_trigger_timer;
976 m_emerge->startThreads();
980 // Save map, players and auth stuff
982 float &counter = m_savemap_timer;
984 if(counter >= g_settings->getFloat("server_map_save_interval"))
987 JMutexAutoLock lock(m_env_mutex);
989 ScopeProfiler sp(g_profiler, "Server: saving stuff");
992 if (m_banmanager->isModified()) {
993 m_banmanager->save();
996 // Save changed parts of map
997 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1000 m_env->saveLoadedPlayers();
1002 // Save environment metadata
1008 void Server::Receive()
1010 DSTACK(__FUNCTION_NAME);
1011 SharedBuffer<u8> data;
1015 datasize = m_con.Receive(peer_id,data);
1016 ProcessData(*data, datasize, peer_id);
1018 catch(con::InvalidIncomingDataException &e) {
1019 infostream<<"Server::Receive(): "
1020 "InvalidIncomingDataException: what()="
1021 <<e.what()<<std::endl;
1023 catch(SerializationError &e) {
1024 infostream<<"Server::Receive(): "
1025 "SerializationError: what()="
1026 <<e.what()<<std::endl;
1028 catch(ClientStateError &e) {
1029 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1030 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1031 L"Try reconnecting or updating your client");
1033 catch(con::PeerNotFoundException &e) {
1038 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1040 std::string playername = "";
1041 PlayerSAO *playersao = NULL;
1044 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1045 if (client != NULL) {
1046 playername = client->getName();
1047 playersao = emergePlayer(playername.c_str(), peer_id);
1049 } catch (std::exception &e) {
1055 RemotePlayer *player =
1056 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1058 // If failed, cancel
1059 if((playersao == NULL) || (player == NULL)) {
1060 if(player && player->peer_id != 0) {
1061 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1062 <<" (player allocated to an another client)"<<std::endl;
1063 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1064 L"name. If your client closed unexpectedly, try again in "
1067 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1069 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1075 Send complete position information
1077 SendMovePlayer(peer_id);
1080 SendPlayerPrivileges(peer_id);
1082 // Send inventory formspec
1083 SendPlayerInventoryFormspec(peer_id);
1086 SendInventory(playersao);
1089 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1092 SendPlayerBreath(peer_id);
1094 // Show death screen if necessary
1095 if(player->isDead())
1096 SendDeathscreen(peer_id, false, v3f(0,0,0));
1098 // Note things in chat if not in simple singleplayer mode
1099 if(!m_simple_singleplayer_mode) {
1100 // Send information about server to player in chat
1101 SendChatMessage(peer_id, getStatusString());
1103 // Send information about joining in chat
1105 std::wstring name = L"unknown";
1106 Player *player = m_env->getPlayer(peer_id);
1108 name = narrow_to_wide(player->getName());
1110 std::wstring message;
1113 message += L" joined the game.";
1114 SendChatMessage(PEER_ID_INEXISTENT,message);
1117 Address addr = getPeerAddress(player->peer_id);
1118 std::string ip_str = addr.serializeString();
1119 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1124 std::vector<std::string> names = m_clients.getPlayerNames();
1126 actionstream<<player->getName() <<" joins game. List of players: ";
1128 for (std::vector<std::string>::iterator i = names.begin();
1129 i != names.end(); i++) {
1130 actionstream << *i << " ";
1133 actionstream << player->getName() <<std::endl;
1138 inline void Server::handleCommand(NetworkPacket* pkt)
1140 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1141 (this->*opHandle.handler)(pkt);
1144 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1146 DSTACK(__FUNCTION_NAME);
1147 // Environment is locked first.
1148 JMutexAutoLock envlock(m_env_mutex);
1150 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1153 Address address = getPeerAddress(peer_id);
1154 std::string addr_s = address.serializeString();
1156 if(m_banmanager->isIpBanned(addr_s)) {
1157 std::string ban_name = m_banmanager->getBanName(addr_s);
1158 infostream << "Server: A banned client tried to connect from "
1159 << addr_s << "; banned name was "
1160 << ban_name << std::endl;
1161 // This actually doesn't seem to transfer to the client
1162 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1163 + narrow_to_wide(ban_name));
1167 catch(con::PeerNotFoundException &e) {
1169 * no peer for this packet found
1170 * most common reason is peer timeout, e.g. peer didn't
1171 * respond for some time, your server was overloaded or
1174 infostream << "Server::ProcessData(): Cancelling: peer "
1175 << peer_id << " not found" << std::endl;
1183 NetworkPacket pkt(data, datasize, peer_id);
1185 ToServerCommand command = (ToServerCommand) pkt.getCommand();
1187 // Command must be handled into ToServerCommandHandler
1188 if (command >= TOSERVER_NUM_MSG_TYPES) {
1189 infostream << "Server: Ignoring unknown command "
1190 << command << std::endl;
1193 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1194 handleCommand(&pkt);
1198 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1200 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1201 errorstream << "Server::ProcessData(): Cancelling: Peer"
1202 " serialization format invalid or not initialized."
1203 " Skipping incoming command=" << command << std::endl;
1207 /* Handle commands related to client startup */
1208 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1209 handleCommand(&pkt);
1213 if (m_clients.getClientState(peer_id) < CS_Active) {
1214 if (command == TOSERVER_PLAYERPOS) return;
1216 errorstream << "Got packet command: " << command << " for peer id "
1217 << peer_id << " but client isn't active yet. Dropping packet "
1222 handleCommand(&pkt);
1224 catch(SendFailedException &e) {
1225 errorstream << "Server::ProcessData(): SendFailedException: "
1226 << "what=" << e.what()
1231 void Server::setTimeOfDay(u32 time)
1233 m_env->setTimeOfDay(time);
1234 m_time_of_day_send_timer = 0;
1237 void Server::onMapEditEvent(MapEditEvent *event)
1239 if(m_ignore_map_edit_events)
1241 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1243 MapEditEvent *e = event->clone();
1244 m_unsent_map_edit_queue.push(e);
1247 Inventory* Server::getInventory(const InventoryLocation &loc)
1250 case InventoryLocation::UNDEFINED:
1251 case InventoryLocation::CURRENT_PLAYER:
1253 case InventoryLocation::PLAYER:
1255 Player *player = m_env->getPlayer(loc.name.c_str());
1258 PlayerSAO *playersao = player->getPlayerSAO();
1261 return playersao->getInventory();
1264 case InventoryLocation::NODEMETA:
1266 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1269 return meta->getInventory();
1272 case InventoryLocation::DETACHED:
1274 if(m_detached_inventories.count(loc.name) == 0)
1276 return m_detached_inventories[loc.name];
1280 sanity_check(false); // abort
1285 void Server::setInventoryModified(const InventoryLocation &loc)
1288 case InventoryLocation::UNDEFINED:
1290 case InventoryLocation::PLAYER:
1292 Player *player = m_env->getPlayer(loc.name.c_str());
1295 PlayerSAO *playersao = player->getPlayerSAO();
1299 SendInventory(playersao);
1302 case InventoryLocation::NODEMETA:
1304 v3s16 blockpos = getNodeBlockPos(loc.p);
1306 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1308 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1310 setBlockNotSent(blockpos);
1313 case InventoryLocation::DETACHED:
1315 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1319 sanity_check(false); // abort
1324 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1326 std::vector<u16> clients = m_clients.getClientIDs();
1328 // Set the modified blocks unsent for all the clients
1329 for (std::vector<u16>::iterator i = clients.begin();
1330 i != clients.end(); ++i) {
1331 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1332 client->SetBlocksNotSent(block);
1337 void Server::peerAdded(con::Peer *peer)
1339 DSTACK(__FUNCTION_NAME);
1340 verbosestream<<"Server::peerAdded(): peer->id="
1341 <<peer->id<<std::endl;
1344 c.type = con::PEER_ADDED;
1345 c.peer_id = peer->id;
1347 m_peer_change_queue.push(c);
1350 void Server::deletingPeer(con::Peer *peer, bool timeout)
1352 DSTACK(__FUNCTION_NAME);
1353 verbosestream<<"Server::deletingPeer(): peer->id="
1354 <<peer->id<<", timeout="<<timeout<<std::endl;
1356 m_clients.event(peer->id, CSE_Disconnect);
1358 c.type = con::PEER_REMOVED;
1359 c.peer_id = peer->id;
1360 c.timeout = timeout;
1361 m_peer_change_queue.push(c);
1364 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1366 *retval = m_con.getPeerStat(peer_id,type);
1367 if (*retval == -1) return false;
1371 bool Server::getClientInfo(
1380 std::string* vers_string
1383 *state = m_clients.getClientState(peer_id);
1385 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1387 if (client == NULL) {
1392 *uptime = client->uptime();
1393 *ser_vers = client->serialization_version;
1394 *prot_vers = client->net_proto_version;
1396 *major = client->getMajor();
1397 *minor = client->getMinor();
1398 *patch = client->getPatch();
1399 *vers_string = client->getPatch();
1406 void Server::handlePeerChanges()
1408 while(m_peer_change_queue.size() > 0)
1410 con::PeerChange c = m_peer_change_queue.front();
1411 m_peer_change_queue.pop();
1413 verbosestream<<"Server: Handling peer change: "
1414 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1419 case con::PEER_ADDED:
1420 m_clients.CreateClient(c.peer_id);
1423 case con::PEER_REMOVED:
1424 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1428 FATAL_ERROR("Invalid peer change event received!");
1434 void Server::Send(NetworkPacket* pkt)
1436 m_clients.send(pkt->getPeerId(),
1437 clientCommandFactoryTable[pkt->getCommand()].channel,
1439 clientCommandFactoryTable[pkt->getCommand()].reliable);
1442 void Server::SendMovement(u16 peer_id)
1444 DSTACK(__FUNCTION_NAME);
1445 std::ostringstream os(std::ios_base::binary);
1447 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1449 pkt << g_settings->getFloat("movement_acceleration_default");
1450 pkt << g_settings->getFloat("movement_acceleration_air");
1451 pkt << g_settings->getFloat("movement_acceleration_fast");
1452 pkt << g_settings->getFloat("movement_speed_walk");
1453 pkt << g_settings->getFloat("movement_speed_crouch");
1454 pkt << g_settings->getFloat("movement_speed_fast");
1455 pkt << g_settings->getFloat("movement_speed_climb");
1456 pkt << g_settings->getFloat("movement_speed_jump");
1457 pkt << g_settings->getFloat("movement_liquid_fluidity");
1458 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1459 pkt << g_settings->getFloat("movement_liquid_sink");
1460 pkt << g_settings->getFloat("movement_gravity");
1465 void Server::SendHP(u16 peer_id, u8 hp)
1467 DSTACK(__FUNCTION_NAME);
1469 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1474 void Server::SendBreath(u16 peer_id, u16 breath)
1476 DSTACK(__FUNCTION_NAME);
1478 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1479 pkt << (u16) breath;
1483 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
1485 DSTACK(__FUNCTION_NAME);
1487 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1490 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1491 pkt << custom_reason;
1496 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1498 DSTACK(__FUNCTION_NAME);
1500 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1505 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1506 v3f camera_point_target)
1508 DSTACK(__FUNCTION_NAME);
1510 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1511 pkt << set_camera_point_target << camera_point_target;
1515 void Server::SendItemDef(u16 peer_id,
1516 IItemDefManager *itemdef, u16 protocol_version)
1518 DSTACK(__FUNCTION_NAME);
1520 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1524 u32 length of the next item
1525 zlib-compressed serialized ItemDefManager
1527 std::ostringstream tmp_os(std::ios::binary);
1528 itemdef->serialize(tmp_os, protocol_version);
1529 std::ostringstream tmp_os2(std::ios::binary);
1530 compressZlib(tmp_os.str(), tmp_os2);
1531 pkt.putLongString(tmp_os2.str());
1534 verbosestream << "Server: Sending item definitions to id(" << peer_id
1535 << "): size=" << pkt.getSize() << std::endl;
1540 void Server::SendNodeDef(u16 peer_id,
1541 INodeDefManager *nodedef, u16 protocol_version)
1543 DSTACK(__FUNCTION_NAME);
1545 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1549 u32 length of the next item
1550 zlib-compressed serialized NodeDefManager
1552 std::ostringstream tmp_os(std::ios::binary);
1553 nodedef->serialize(tmp_os, protocol_version);
1554 std::ostringstream tmp_os2(std::ios::binary);
1555 compressZlib(tmp_os.str(), tmp_os2);
1557 pkt.putLongString(tmp_os2.str());
1560 verbosestream << "Server: Sending node definitions to id(" << peer_id
1561 << "): size=" << pkt.getSize() << std::endl;
1567 Non-static send methods
1570 void Server::SendInventory(PlayerSAO* playerSAO)
1572 DSTACK(__FUNCTION_NAME);
1574 UpdateCrafting(playerSAO->getPlayer());
1580 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1582 std::ostringstream os;
1583 playerSAO->getInventory()->serialize(os);
1585 std::string s = os.str();
1587 pkt.putRawString(s.c_str(), s.size());
1591 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1593 DSTACK(__FUNCTION_NAME);
1595 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1598 if (peer_id != PEER_ID_INEXISTENT) {
1602 m_clients.sendToAll(0, &pkt, true);
1606 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1607 const std::string &formname)
1609 DSTACK(__FUNCTION_NAME);
1611 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1613 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1619 // Spawns a particle on peer with peer_id
1620 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1621 float expirationtime, float size, bool collisiondetection,
1622 bool vertical, std::string texture)
1624 DSTACK(__FUNCTION_NAME);
1626 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1628 pkt << pos << velocity << acceleration << expirationtime
1629 << size << collisiondetection;
1630 pkt.putLongString(texture);
1633 if (peer_id != PEER_ID_INEXISTENT) {
1637 m_clients.sendToAll(0, &pkt, true);
1641 // Adds a ParticleSpawner on peer with peer_id
1642 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1643 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1644 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1646 DSTACK(__FUNCTION_NAME);
1648 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1650 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1651 << minacc << maxacc << minexptime << maxexptime << minsize
1652 << maxsize << collisiondetection;
1654 pkt.putLongString(texture);
1656 pkt << id << vertical;
1658 if (peer_id != PEER_ID_INEXISTENT) {
1662 m_clients.sendToAll(0, &pkt, true);
1666 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1668 DSTACK(__FUNCTION_NAME);
1670 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1672 // Ugly error in this packet
1675 if (peer_id != PEER_ID_INEXISTENT) {
1679 m_clients.sendToAll(0, &pkt, true);
1684 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1686 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1688 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1689 << form->text << form->number << form->item << form->dir
1690 << form->align << form->offset << form->world_pos << form->size;
1695 void Server::SendHUDRemove(u16 peer_id, u32 id)
1697 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1702 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1704 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1705 pkt << id << (u8) stat;
1709 case HUD_STAT_SCALE:
1710 case HUD_STAT_ALIGN:
1711 case HUD_STAT_OFFSET:
1712 pkt << *(v2f *) value;
1716 pkt << *(std::string *) value;
1718 case HUD_STAT_WORLD_POS:
1719 pkt << *(v3f *) value;
1722 pkt << *(v2s32 *) value;
1724 case HUD_STAT_NUMBER:
1728 pkt << *(u32 *) value;
1735 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1737 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1739 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1741 pkt << flags << mask;
1746 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1748 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1749 pkt << param << value;
1753 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1754 const std::string &type, const std::vector<std::string> ¶ms)
1756 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1757 pkt << bgcolor << type << (u16) params.size();
1759 for(size_t i=0; i<params.size(); i++)
1765 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1768 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1771 pkt << do_override << (u16) (ratio * 65535);
1776 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1778 DSTACK(__FUNCTION_NAME);
1780 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1781 pkt << time << time_speed;
1783 if (peer_id == PEER_ID_INEXISTENT) {
1784 m_clients.sendToAll(0, &pkt, true);
1791 void Server::SendPlayerHP(u16 peer_id)
1793 DSTACK(__FUNCTION_NAME);
1794 PlayerSAO *playersao = getPlayerSAO(peer_id);
1796 SendHP(peer_id, playersao->getHP());
1797 m_script->player_event(playersao,"health_changed");
1799 // Send to other clients
1800 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1801 ActiveObjectMessage aom(playersao->getId(), true, str);
1802 playersao->m_messages_out.push(aom);
1805 void Server::SendPlayerBreath(u16 peer_id)
1807 DSTACK(__FUNCTION_NAME);
1808 PlayerSAO *playersao = getPlayerSAO(peer_id);
1811 m_script->player_event(playersao, "breath_changed");
1812 SendBreath(peer_id, playersao->getBreath());
1815 void Server::SendMovePlayer(u16 peer_id)
1817 DSTACK(__FUNCTION_NAME);
1818 Player *player = m_env->getPlayer(peer_id);
1821 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1822 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1825 v3f pos = player->getPosition();
1826 f32 pitch = player->getPitch();
1827 f32 yaw = player->getYaw();
1828 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1829 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1830 << " pitch=" << pitch
1838 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1840 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1843 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1844 << animation_frames[3] << animation_speed;
1849 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1851 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1852 pkt << first << third;
1855 void Server::SendPlayerPrivileges(u16 peer_id)
1857 Player *player = m_env->getPlayer(peer_id);
1859 if(player->peer_id == PEER_ID_INEXISTENT)
1862 std::set<std::string> privs;
1863 m_script->getAuth(player->getName(), NULL, &privs);
1865 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1866 pkt << (u16) privs.size();
1868 for(std::set<std::string>::const_iterator i = privs.begin();
1869 i != privs.end(); i++) {
1876 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1878 Player *player = m_env->getPlayer(peer_id);
1880 if(player->peer_id == PEER_ID_INEXISTENT)
1883 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1884 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1888 u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1890 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, peer_id);
1891 pkt.putRawString(datas.c_str(), datas.size());
1893 return pkt.getSize();
1896 void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas)
1898 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1901 pkt.putRawString(datas.c_str(), datas.size());
1905 s32 Server::playSound(const SimpleSoundSpec &spec,
1906 const ServerSoundParams ¶ms)
1908 // Find out initial position of sound
1909 bool pos_exists = false;
1910 v3f pos = params.getPos(m_env, &pos_exists);
1911 // If position is not found while it should be, cancel sound
1912 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1915 // Filter destination clients
1916 std::vector<u16> dst_clients;
1917 if(params.to_player != "")
1919 Player *player = m_env->getPlayer(params.to_player.c_str());
1921 infostream<<"Server::playSound: Player \""<<params.to_player
1922 <<"\" not found"<<std::endl;
1925 if(player->peer_id == PEER_ID_INEXISTENT){
1926 infostream<<"Server::playSound: Player \""<<params.to_player
1927 <<"\" not connected"<<std::endl;
1930 dst_clients.push_back(player->peer_id);
1933 std::vector<u16> clients = m_clients.getClientIDs();
1935 for(std::vector<u16>::iterator
1936 i = clients.begin(); i != clients.end(); ++i) {
1937 Player *player = m_env->getPlayer(*i);
1942 if(player->getPosition().getDistanceFrom(pos) >
1943 params.max_hear_distance)
1946 dst_clients.push_back(*i);
1950 if(dst_clients.empty())
1954 s32 id = m_next_sound_id++;
1955 // The sound will exist as a reference in m_playing_sounds
1956 m_playing_sounds[id] = ServerPlayingSound();
1957 ServerPlayingSound &psound = m_playing_sounds[id];
1958 psound.params = params;
1960 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1961 pkt << id << spec.name << (float) (spec.gain * params.gain)
1962 << (u8) params.type << pos << params.object << params.loop;
1964 for(std::vector<u16>::iterator i = dst_clients.begin();
1965 i != dst_clients.end(); i++) {
1966 psound.clients.insert(*i);
1967 m_clients.send(*i, 0, &pkt, true);
1971 void Server::stopSound(s32 handle)
1973 // Get sound reference
1974 std::map<s32, ServerPlayingSound>::iterator i =
1975 m_playing_sounds.find(handle);
1976 if(i == m_playing_sounds.end())
1978 ServerPlayingSound &psound = i->second;
1980 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
1983 for(std::set<u16>::iterator i = psound.clients.begin();
1984 i != psound.clients.end(); i++) {
1986 m_clients.send(*i, 0, &pkt, true);
1988 // Remove sound reference
1989 m_playing_sounds.erase(i);
1992 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1993 std::vector<u16> *far_players, float far_d_nodes)
1995 float maxd = far_d_nodes*BS;
1996 v3f p_f = intToFloat(p, BS);
1998 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2001 std::vector<u16> clients = m_clients.getClientIDs();
2002 for(std::vector<u16>::iterator i = clients.begin();
2003 i != clients.end(); ++i) {
2006 if(Player *player = m_env->getPlayer(*i)) {
2007 // If player is far away, only set modified blocks not sent
2008 v3f player_pos = player->getPosition();
2009 if(player_pos.getDistanceFrom(p_f) > maxd) {
2010 far_players->push_back(*i);
2017 m_clients.send(*i, 0, &pkt, true);
2021 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2022 std::vector<u16> *far_players, float far_d_nodes,
2023 bool remove_metadata)
2025 float maxd = far_d_nodes*BS;
2026 v3f p_f = intToFloat(p, BS);
2028 std::vector<u16> clients = m_clients.getClientIDs();
2029 for(std::vector<u16>::iterator i = clients.begin();
2030 i != clients.end(); ++i) {
2034 if(Player *player = m_env->getPlayer(*i)) {
2035 // If player is far away, only set modified blocks not sent
2036 v3f player_pos = player->getPosition();
2037 if(player_pos.getDistanceFrom(p_f) > maxd) {
2038 far_players->push_back(*i);
2044 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2046 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2048 pkt << p << n.param0 << n.param1 << n.param2
2049 << (u8) (remove_metadata ? 0 : 1);
2051 if (!remove_metadata) {
2052 if (client->net_proto_version <= 21) {
2053 // Old clients always clear metadata; fix it
2054 // by sending the full block again.
2055 client->SetBlockNotSent(p);
2062 if (pkt.getSize() > 0)
2063 m_clients.send(*i, 0, &pkt, true);
2067 void Server::setBlockNotSent(v3s16 p)
2069 std::vector<u16> clients = m_clients.getClientIDs();
2071 for(std::vector<u16>::iterator i = clients.begin();
2072 i != clients.end(); ++i) {
2073 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2074 client->SetBlockNotSent(p);
2079 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2081 DSTACK(__FUNCTION_NAME);
2083 v3s16 p = block->getPos();
2086 Create a packet with the block in the right format
2089 std::ostringstream os(std::ios_base::binary);
2090 block->serialize(os, ver, false);
2091 block->serializeNetworkSpecific(os, net_proto_version);
2092 std::string s = os.str();
2094 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2097 pkt.putRawString(s.c_str(), s.size());
2101 void Server::SendBlocks(float dtime)
2103 DSTACK(__FUNCTION_NAME);
2105 JMutexAutoLock envlock(m_env_mutex);
2106 //TODO check if one big lock could be faster then multiple small ones
2108 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2110 std::vector<PrioritySortedBlockTransfer> queue;
2112 s32 total_sending = 0;
2115 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2117 std::vector<u16> clients = m_clients.getClientIDs();
2120 for(std::vector<u16>::iterator i = clients.begin();
2121 i != clients.end(); ++i) {
2122 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2127 total_sending += client->SendingCount();
2128 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2134 // Lowest priority number comes first.
2135 // Lowest is most important.
2136 std::sort(queue.begin(), queue.end());
2139 for(u32 i=0; i<queue.size(); i++)
2141 //TODO: Calculate limit dynamically
2142 if(total_sending >= g_settings->getS32
2143 ("max_simultaneous_block_sends_server_total"))
2146 PrioritySortedBlockTransfer q = queue[i];
2148 MapBlock *block = NULL;
2151 block = m_env->getMap().getBlockNoCreate(q.pos);
2153 catch(InvalidPositionException &e)
2158 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2163 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2165 client->SentBlock(q.pos);
2171 void Server::fillMediaCache()
2173 DSTACK(__FUNCTION_NAME);
2175 infostream<<"Server: Calculating media file checksums"<<std::endl;
2177 // Collect all media file paths
2178 std::vector<std::string> paths;
2179 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2180 i != m_mods.end(); i++) {
2181 const ModSpec &mod = *i;
2182 paths.push_back(mod.path + DIR_DELIM + "textures");
2183 paths.push_back(mod.path + DIR_DELIM + "sounds");
2184 paths.push_back(mod.path + DIR_DELIM + "media");
2185 paths.push_back(mod.path + DIR_DELIM + "models");
2187 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2189 // Collect media file information from paths into cache
2190 for(std::vector<std::string>::iterator i = paths.begin();
2191 i != paths.end(); i++) {
2192 std::string mediapath = *i;
2193 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2194 for (u32 j = 0; j < dirlist.size(); j++) {
2195 if (dirlist[j].dir) // Ignode dirs
2197 std::string filename = dirlist[j].name;
2198 // If name contains illegal characters, ignore the file
2199 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2200 infostream<<"Server: ignoring illegal file name: \""
2201 << filename << "\"" << std::endl;
2204 // If name is not in a supported format, ignore it
2205 const char *supported_ext[] = {
2206 ".png", ".jpg", ".bmp", ".tga",
2207 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2209 ".x", ".b3d", ".md2", ".obj",
2212 if (removeStringEnd(filename, supported_ext) == ""){
2213 infostream << "Server: ignoring unsupported file extension: \""
2214 << filename << "\"" << std::endl;
2217 // Ok, attempt to load the file and add to cache
2218 std::string filepath = mediapath + DIR_DELIM + filename;
2220 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2222 errorstream << "Server::fillMediaCache(): Could not open \""
2223 << filename << "\" for reading" << std::endl;
2226 std::ostringstream tmp_os(std::ios_base::binary);
2230 fis.read(buf, 1024);
2231 std::streamsize len = fis.gcount();
2232 tmp_os.write(buf, len);
2241 errorstream<<"Server::fillMediaCache(): Failed to read \""
2242 << filename << "\"" << std::endl;
2245 if(tmp_os.str().length() == 0) {
2246 errorstream << "Server::fillMediaCache(): Empty file \""
2247 << filepath << "\"" << std::endl;
2252 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2254 unsigned char *digest = sha1.getDigest();
2255 std::string sha1_base64 = base64_encode(digest, 20);
2256 std::string sha1_hex = hex_encode((char*)digest, 20);
2260 m_media[filename] = MediaInfo(filepath, sha1_base64);
2261 verbosestream << "Server: " << sha1_hex << " is " << filename
2267 struct SendableMediaAnnouncement
2270 std::string sha1_digest;
2272 SendableMediaAnnouncement(const std::string &name_="",
2273 const std::string &sha1_digest_=""):
2275 sha1_digest(sha1_digest_)
2279 void Server::sendMediaAnnouncement(u16 peer_id)
2281 DSTACK(__FUNCTION_NAME);
2283 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2286 std::vector<SendableMediaAnnouncement> file_announcements;
2288 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2289 i != m_media.end(); i++){
2291 file_announcements.push_back(
2292 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2296 std::ostringstream os(std::ios_base::binary);
2298 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2299 pkt << (u16) file_announcements.size();
2301 for (std::vector<SendableMediaAnnouncement>::iterator
2302 j = file_announcements.begin();
2303 j != file_announcements.end(); ++j) {
2304 pkt << j->name << j->sha1_digest;
2307 pkt << g_settings->get("remote_media");
2311 struct SendableMedia
2317 SendableMedia(const std::string &name_="", const std::string &path_="",
2318 const std::string &data_=""):
2325 void Server::sendRequestedMedia(u16 peer_id,
2326 const std::vector<std::string> &tosend)
2328 DSTACK(__FUNCTION_NAME);
2330 verbosestream<<"Server::sendRequestedMedia(): "
2331 <<"Sending files to client"<<std::endl;
2335 // Put 5kB in one bunch (this is not accurate)
2336 u32 bytes_per_bunch = 5000;
2338 std::vector< std::vector<SendableMedia> > file_bunches;
2339 file_bunches.push_back(std::vector<SendableMedia>());
2341 u32 file_size_bunch_total = 0;
2343 for(std::vector<std::string>::const_iterator i = tosend.begin();
2344 i != tosend.end(); ++i) {
2345 const std::string &name = *i;
2347 if(m_media.find(name) == m_media.end()) {
2348 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2349 <<"unknown file \""<<(name)<<"\""<<std::endl;
2353 //TODO get path + name
2354 std::string tpath = m_media[name].path;
2357 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2358 if(fis.good() == false){
2359 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2360 <<tpath<<"\" for reading"<<std::endl;
2363 std::ostringstream tmp_os(std::ios_base::binary);
2367 fis.read(buf, 1024);
2368 std::streamsize len = fis.gcount();
2369 tmp_os.write(buf, len);
2370 file_size_bunch_total += len;
2379 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2380 <<name<<"\""<<std::endl;
2383 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2384 <<tname<<"\""<<std::endl;*/
2386 file_bunches[file_bunches.size()-1].push_back(
2387 SendableMedia(name, tpath, tmp_os.str()));
2389 // Start next bunch if got enough data
2390 if(file_size_bunch_total >= bytes_per_bunch) {
2391 file_bunches.push_back(std::vector<SendableMedia>());
2392 file_size_bunch_total = 0;
2397 /* Create and send packets */
2399 u16 num_bunches = file_bunches.size();
2400 for(u16 i = 0; i < num_bunches; i++) {
2403 u16 total number of texture bunches
2404 u16 index of this bunch
2405 u32 number of files in this bunch
2414 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2415 pkt << num_bunches << i << (u32) file_bunches[i].size();
2417 for(std::vector<SendableMedia>::iterator
2418 j = file_bunches[i].begin();
2419 j != file_bunches[i].end(); ++j) {
2421 pkt.putLongString(j->data);
2424 verbosestream << "Server::sendRequestedMedia(): bunch "
2425 << i << "/" << num_bunches
2426 << " files=" << file_bunches[i].size()
2427 << " size=" << pkt.getSize() << std::endl;
2432 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2434 if(m_detached_inventories.count(name) == 0) {
2435 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2438 Inventory *inv = m_detached_inventories[name];
2439 std::ostringstream os(std::ios_base::binary);
2441 os << serializeString(name);
2445 std::string s = os.str();
2447 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2448 pkt.putRawString(s.c_str(), s.size());
2450 if (peer_id != PEER_ID_INEXISTENT) {
2454 m_clients.sendToAll(0, &pkt, true);
2458 void Server::sendDetachedInventories(u16 peer_id)
2460 DSTACK(__FUNCTION_NAME);
2462 for(std::map<std::string, Inventory*>::iterator
2463 i = m_detached_inventories.begin();
2464 i != m_detached_inventories.end(); i++) {
2465 const std::string &name = i->first;
2466 //Inventory *inv = i->second;
2467 sendDetachedInventory(name, peer_id);
2475 void Server::DiePlayer(u16 peer_id)
2477 DSTACK(__FUNCTION_NAME);
2479 PlayerSAO *playersao = getPlayerSAO(peer_id);
2482 infostream << "Server::DiePlayer(): Player "
2483 << playersao->getPlayer()->getName()
2484 << " dies" << std::endl;
2486 playersao->setHP(0);
2488 // Trigger scripted stuff
2489 m_script->on_dieplayer(playersao);
2491 SendPlayerHP(peer_id);
2492 SendDeathscreen(peer_id, false, v3f(0,0,0));
2495 void Server::RespawnPlayer(u16 peer_id)
2497 DSTACK(__FUNCTION_NAME);
2499 PlayerSAO *playersao = getPlayerSAO(peer_id);
2502 infostream << "Server::RespawnPlayer(): Player "
2503 << playersao->getPlayer()->getName()
2504 << " respawns" << std::endl;
2506 playersao->setHP(PLAYER_MAX_HP);
2507 playersao->setBreath(PLAYER_MAX_BREATH);
2509 SendPlayerHP(peer_id);
2510 SendPlayerBreath(peer_id);
2512 bool repositioned = m_script->on_respawnplayer(playersao);
2514 v3f pos = findSpawnPos(m_env->getServerMap());
2515 // setPos will send the new position to client
2516 playersao->setPos(pos);
2520 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2522 DSTACK(__FUNCTION_NAME);
2524 SendAccessDenied(peer_id, reason, custom_reason);
2525 m_clients.event(peer_id, CSE_SetDenied);
2526 m_con.DisconnectPeer(peer_id);
2529 // 13/03/15: remove this function when protocol version 25 will become
2530 // the minimum version for MT users, maybe in 1 year
2531 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2533 DSTACK(__FUNCTION_NAME);
2535 SendAccessDenied_Legacy(peer_id, reason);
2536 m_clients.event(peer_id, CSE_SetDenied);
2537 m_con.DisconnectPeer(peer_id);
2540 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2542 DSTACK(__FUNCTION_NAME);
2543 std::wstring message;
2546 Clear references to playing sounds
2548 for(std::map<s32, ServerPlayingSound>::iterator
2549 i = m_playing_sounds.begin();
2550 i != m_playing_sounds.end();)
2552 ServerPlayingSound &psound = i->second;
2553 psound.clients.erase(peer_id);
2554 if(psound.clients.empty())
2555 m_playing_sounds.erase(i++);
2560 Player *player = m_env->getPlayer(peer_id);
2562 // Collect information about leaving in chat
2564 if(player != NULL && reason != CDR_DENY)
2566 std::wstring name = narrow_to_wide(player->getName());
2569 message += L" left the game.";
2570 if(reason == CDR_TIMEOUT)
2571 message += L" (timed out)";
2575 /* Run scripts and remove from environment */
2579 PlayerSAO *playersao = player->getPlayerSAO();
2582 m_script->on_leaveplayer(playersao);
2584 playersao->disconnected();
2592 if(player != NULL && reason != CDR_DENY) {
2593 std::ostringstream os(std::ios_base::binary);
2594 std::vector<u16> clients = m_clients.getClientIDs();
2596 for(std::vector<u16>::iterator i = clients.begin();
2597 i != clients.end(); ++i) {
2599 Player *player = m_env->getPlayer(*i);
2603 // Get name of player
2604 os << player->getName() << " ";
2607 actionstream << player->getName() << " "
2608 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2609 << " List of players: " << os.str() << std::endl;
2613 JMutexAutoLock env_lock(m_env_mutex);
2614 m_clients.DeleteClient(peer_id);
2618 // Send leave chat message to all remaining clients
2619 if(message.length() != 0)
2620 SendChatMessage(PEER_ID_INEXISTENT,message);
2623 void Server::UpdateCrafting(Player* player)
2625 DSTACK(__FUNCTION_NAME);
2627 // Get a preview for crafting
2629 InventoryLocation loc;
2630 loc.setPlayer(player->getName());
2631 getCraftingResult(&player->inventory, preview, false, this);
2632 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2634 // Put the new preview in
2635 InventoryList *plist = player->inventory.getList("craftpreview");
2636 sanity_check(plist);
2637 sanity_check(plist->getSize() >= 1);
2638 plist->changeItem(0, preview);
2641 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2643 RemoteClient *client = getClientNoEx(peer_id,state_min);
2645 throw ClientNotFoundException("Client not found");
2649 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2651 return m_clients.getClientNoEx(peer_id, state_min);
2654 std::string Server::getPlayerName(u16 peer_id)
2656 Player *player = m_env->getPlayer(peer_id);
2658 return "[id="+itos(peer_id)+"]";
2659 return player->getName();
2662 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2664 Player *player = m_env->getPlayer(peer_id);
2667 return player->getPlayerSAO();
2670 std::wstring Server::getStatusString()
2672 std::wostringstream os(std::ios_base::binary);
2675 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2677 os<<L", uptime="<<m_uptime.get();
2679 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2680 // Information about clients
2683 std::vector<u16> clients = m_clients.getClientIDs();
2684 for(std::vector<u16>::iterator i = clients.begin();
2685 i != clients.end(); ++i) {
2687 Player *player = m_env->getPlayer(*i);
2688 // Get name of player
2689 std::wstring name = L"unknown";
2691 name = narrow_to_wide(player->getName());
2692 // Add name to information string
2700 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2701 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2702 if(g_settings->get("motd") != "")
2703 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2707 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2709 std::set<std::string> privs;
2710 m_script->getAuth(name, NULL, &privs);
2714 bool Server::checkPriv(const std::string &name, const std::string &priv)
2716 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2717 return (privs.count(priv) != 0);
2720 void Server::reportPrivsModified(const std::string &name)
2723 std::vector<u16> clients = m_clients.getClientIDs();
2724 for(std::vector<u16>::iterator i = clients.begin();
2725 i != clients.end(); ++i) {
2726 Player *player = m_env->getPlayer(*i);
2727 reportPrivsModified(player->getName());
2730 Player *player = m_env->getPlayer(name.c_str());
2733 SendPlayerPrivileges(player->peer_id);
2734 PlayerSAO *sao = player->getPlayerSAO();
2737 sao->updatePrivileges(
2738 getPlayerEffectivePrivs(name),
2743 void Server::reportInventoryFormspecModified(const std::string &name)
2745 Player *player = m_env->getPlayer(name.c_str());
2748 SendPlayerInventoryFormspec(player->peer_id);
2751 void Server::setIpBanned(const std::string &ip, const std::string &name)
2753 m_banmanager->add(ip, name);
2756 void Server::unsetIpBanned(const std::string &ip_or_name)
2758 m_banmanager->remove(ip_or_name);
2761 std::string Server::getBanDescription(const std::string &ip_or_name)
2763 return m_banmanager->getBanDescription(ip_or_name);
2766 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2768 Player *player = m_env->getPlayer(name);
2772 if (player->peer_id == PEER_ID_INEXISTENT)
2775 SendChatMessage(player->peer_id, msg);
2778 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2780 Player *player = m_env->getPlayer(playername);
2784 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2788 SendShowFormspecMessage(player->peer_id, formspec, formname);
2792 u32 Server::hudAdd(Player *player, HudElement *form) {
2796 u32 id = player->addHud(form);
2798 SendHUDAdd(player->peer_id, id, form);
2803 bool Server::hudRemove(Player *player, u32 id) {
2807 HudElement* todel = player->removeHud(id);
2814 SendHUDRemove(player->peer_id, id);
2818 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2822 SendHUDChange(player->peer_id, id, stat, data);
2826 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2830 SendHUDSetFlags(player->peer_id, flags, mask);
2831 player->hud_flags = flags;
2833 PlayerSAO* playersao = player->getPlayerSAO();
2835 if (playersao == NULL)
2838 m_script->player_event(playersao, "hud_changed");
2842 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2845 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2848 std::ostringstream os(std::ios::binary);
2849 writeS32(os, hotbar_itemcount);
2850 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2854 void Server::hudSetHotbarImage(Player *player, std::string name) {
2858 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2861 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2865 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2868 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2873 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2877 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2882 SendEyeOffset(player->peer_id, first, third);
2886 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2887 const std::string &type, const std::vector<std::string> ¶ms)
2892 SendSetSky(player->peer_id, bgcolor, type, params);
2896 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2902 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2906 void Server::notifyPlayers(const std::wstring &msg)
2908 SendChatMessage(PEER_ID_INEXISTENT,msg);
2911 void Server::spawnParticle(const char *playername, v3f pos,
2912 v3f velocity, v3f acceleration,
2913 float expirationtime, float size, bool
2914 collisiondetection, bool vertical, std::string texture)
2916 Player *player = m_env->getPlayer(playername);
2919 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2920 expirationtime, size, collisiondetection, vertical, texture);
2923 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2924 float expirationtime, float size,
2925 bool collisiondetection, bool vertical, std::string texture)
2927 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2928 expirationtime, size, collisiondetection, vertical, texture);
2931 u32 Server::addParticleSpawner(const char *playername,
2932 u16 amount, float spawntime,
2933 v3f minpos, v3f maxpos,
2934 v3f minvel, v3f maxvel,
2935 v3f minacc, v3f maxacc,
2936 float minexptime, float maxexptime,
2937 float minsize, float maxsize,
2938 bool collisiondetection, bool vertical, std::string texture)
2940 Player *player = m_env->getPlayer(playername);
2945 for(;;) // look for unused particlespawner id
2948 if (std::find(m_particlespawner_ids.begin(),
2949 m_particlespawner_ids.end(), id)
2950 == m_particlespawner_ids.end())
2952 m_particlespawner_ids.push_back(id);
2957 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2958 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2959 minexptime, maxexptime, minsize, maxsize,
2960 collisiondetection, vertical, texture, id);
2965 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2966 v3f minpos, v3f maxpos,
2967 v3f minvel, v3f maxvel,
2968 v3f minacc, v3f maxacc,
2969 float minexptime, float maxexptime,
2970 float minsize, float maxsize,
2971 bool collisiondetection, bool vertical, std::string texture)
2974 for(;;) // look for unused particlespawner id
2977 if (std::find(m_particlespawner_ids.begin(),
2978 m_particlespawner_ids.end(), id)
2979 == m_particlespawner_ids.end())
2981 m_particlespawner_ids.push_back(id);
2986 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2987 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2988 minexptime, maxexptime, minsize, maxsize,
2989 collisiondetection, vertical, texture, id);
2994 void Server::deleteParticleSpawner(const char *playername, u32 id)
2996 Player *player = m_env->getPlayer(playername);
3000 m_particlespawner_ids.erase(
3001 std::remove(m_particlespawner_ids.begin(),
3002 m_particlespawner_ids.end(), id),
3003 m_particlespawner_ids.end());
3004 SendDeleteParticleSpawner(player->peer_id, id);
3007 void Server::deleteParticleSpawnerAll(u32 id)
3009 m_particlespawner_ids.erase(
3010 std::remove(m_particlespawner_ids.begin(),
3011 m_particlespawner_ids.end(), id),
3012 m_particlespawner_ids.end());
3013 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3016 Inventory* Server::createDetachedInventory(const std::string &name)
3018 if(m_detached_inventories.count(name) > 0){
3019 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3020 delete m_detached_inventories[name];
3022 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3024 Inventory *inv = new Inventory(m_itemdef);
3026 m_detached_inventories[name] = inv;
3027 //TODO find a better way to do this
3028 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3035 BoolScopeSet(bool *dst, bool val):
3038 m_orig_state = *m_dst;
3043 *m_dst = m_orig_state;
3050 // actions: time-reversed list
3051 // Return value: success/failure
3052 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3053 std::list<std::string> *log)
3055 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3056 ServerMap *map = (ServerMap*)(&m_env->getMap());
3058 // Fail if no actions to handle
3059 if(actions.empty()){
3060 log->push_back("Nothing to do.");
3067 for(std::list<RollbackAction>::const_iterator
3068 i = actions.begin();
3069 i != actions.end(); i++)
3071 const RollbackAction &action = *i;
3073 bool success = action.applyRevert(map, this, this);
3076 std::ostringstream os;
3077 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3078 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3080 log->push_back(os.str());
3082 std::ostringstream os;
3083 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3084 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3086 log->push_back(os.str());
3090 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3091 <<" failed"<<std::endl;
3093 // Call it done if less than half failed
3094 return num_failed <= num_tried/2;
3097 // IGameDef interface
3099 IItemDefManager* Server::getItemDefManager()
3103 INodeDefManager* Server::getNodeDefManager()
3107 ICraftDefManager* Server::getCraftDefManager()
3111 ITextureSource* Server::getTextureSource()
3115 IShaderSource* Server::getShaderSource()
3119 scene::ISceneManager* Server::getSceneManager()
3124 u16 Server::allocateUnknownNodeId(const std::string &name)
3126 return m_nodedef->allocateDummy(name);
3128 ISoundManager* Server::getSoundManager()
3130 return &dummySoundManager;
3132 MtEventManager* Server::getEventManager()
3137 IWritableItemDefManager* Server::getWritableItemDefManager()
3141 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3145 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3150 const ModSpec* Server::getModSpec(const std::string &modname)
3152 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3153 i != m_mods.end(); i++){
3154 const ModSpec &mod = *i;
3155 if(mod.name == modname)
3160 void Server::getModNames(std::vector<std::string> &modlist)
3162 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3163 modlist.push_back(i->name);
3166 std::string Server::getBuiltinLuaPath()
3168 return porting::path_share + DIR_DELIM + "builtin";
3171 v3f findSpawnPos(ServerMap &map)
3173 //return v3f(50,50,50)*BS;
3178 nodepos = v2s16(0,0);
3183 s16 water_level = map.getWaterLevel();
3185 // Try to find a good place a few times
3186 for(s32 i=0; i<1000; i++)
3189 // We're going to try to throw the player to this position
3190 v2s16 nodepos2d = v2s16(
3191 -range + (myrand() % (range * 2)),
3192 -range + (myrand() % (range * 2)));
3194 // Get ground height at point
3195 s16 groundheight = map.findGroundLevel(nodepos2d);
3196 if (groundheight <= water_level) // Don't go underwater
3198 if (groundheight > water_level + 6) // Don't go to high places
3201 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3202 bool is_good = false;
3204 for (s32 i = 0; i < 10; i++) {
3205 v3s16 blockpos = getNodeBlockPos(nodepos);
3206 map.emergeBlock(blockpos, true);
3207 content_t c = map.getNodeNoEx(nodepos).getContent();
3208 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3210 if (air_count >= 2){
3218 // Found a good place
3219 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3225 return intToFloat(nodepos, BS);
3228 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3230 bool newplayer = false;
3233 Try to get an existing player
3235 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3237 // If player is already connected, cancel
3238 if(player != NULL && player->peer_id != 0)
3240 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3245 If player with the wanted peer_id already exists, cancel.
3247 if(m_env->getPlayer(peer_id) != NULL)
3249 infostream<<"emergePlayer(): Player with wrong name but same"
3250 " peer_id already exists"<<std::endl;
3254 // Load player if it isn't already loaded
3256 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3259 // Create player if it doesn't exist
3262 player = new RemotePlayer(this, name);
3263 // Set player position
3264 infostream<<"Server: Finding spawn place for player \""
3265 <<name<<"\""<<std::endl;
3266 v3f pos = findSpawnPos(m_env->getServerMap());
3267 player->setPosition(pos);
3269 // Make sure the player is saved
3270 player->setModified(true);
3272 // Add player to environment
3273 m_env->addPlayer(player);
3276 // Create a new player active object
3277 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3278 getPlayerEffectivePrivs(player->getName()),
3281 /* Clean up old HUD elements from previous sessions */
3284 /* Add object to environment */
3285 m_env->addActiveObject(playersao);
3289 m_script->on_newplayer(playersao);
3295 void dedicated_server_loop(Server &server, bool &kill)
3297 DSTACK(__FUNCTION_NAME);
3299 verbosestream<<"dedicated_server_loop()"<<std::endl;
3301 IntervalLimiter m_profiler_interval;
3305 float steplen = g_settings->getFloat("dedicated_server_step");
3306 // This is kind of a hack but can be done like this
3307 // because server.step() is very light
3309 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3310 sleep_ms((int)(steplen*1000.0));
3312 server.step(steplen);
3314 if(server.getShutdownRequested() || kill)
3316 infostream<<"Dedicated server quitting"<<std::endl;
3318 if(g_settings->getBool("server_announce"))
3319 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3327 float profiler_print_interval =
3328 g_settings->getFloat("profiler_print_interval");
3329 if(profiler_print_interval != 0)
3331 if(m_profiler_interval.step(steplen, profiler_print_interval))
3333 infostream<<"Profiler:"<<std::endl;
3334 g_profiler->print(infostream);
3335 g_profiler->clear();