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"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/mathconstants.h"
63 #include "util/serialize.h"
64 #include "util/thread.h"
65 #include "defaultsettings.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 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 // Create rollback manager
247 m_rollback = new RollbackManager(m_path_world, this);
249 ModConfiguration modconf(m_path_world);
250 m_mods = modconf.getMods();
251 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
252 // complain about mods with unsatisfied dependencies
253 if(!modconf.isConsistent())
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
259 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
260 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
261 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
262 errorstream << " \"" << *dep_it << "\"";
263 errorstream << std::endl;
267 Settings worldmt_settings;
268 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
269 worldmt_settings.readConfigFile(worldmt.c_str());
270 std::vector<std::string> names = worldmt_settings.getNames();
271 std::set<std::string> load_mod_names;
272 for(std::vector<std::string>::iterator it = names.begin();
273 it != names.end(); ++it)
275 std::string name = *it;
276 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
277 load_mod_names.insert(name.substr(9));
279 // complain about mods declared to be loaded, but not found
280 for(std::vector<ModSpec>::iterator it = m_mods.begin();
281 it != m_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
284 it != unsatisfied_mods.end(); ++it)
285 load_mod_names.erase((*it).name);
286 if(!load_mod_names.empty())
288 errorstream << "The following mods could not be found:";
289 for(std::set<std::string>::iterator it = load_mod_names.begin();
290 it != load_mod_names.end(); ++it)
291 errorstream << " \"" << (*it) << "\"";
292 errorstream << std::endl;
296 JMutexAutoLock envlock(m_env_mutex);
298 // Load mapgen params from Settings
299 m_emerge->loadMapgenParams();
301 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
302 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
304 // Initialize scripting
305 infostream<<"Server: Initializing Lua"<<std::endl;
307 m_script = new GameScripting(this);
309 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
311 if (!m_script->loadScript(scriptpath))
312 throw ModError("Failed to load and run " + scriptpath);
315 infostream<<"Server: Loading mods: ";
316 for(std::vector<ModSpec>::iterator i = m_mods.begin();
317 i != m_mods.end(); i++){
318 const ModSpec &mod = *i;
319 infostream<<mod.name<<" ";
321 infostream<<std::endl;
322 // Load and run "mod" scripts
323 for(std::vector<ModSpec>::iterator i = m_mods.begin();
324 i != m_mods.end(); i++){
325 const ModSpec &mod = *i;
326 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
327 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
328 <<scriptpath<<"\"]"<<std::endl;
329 bool success = m_script->loadMod(scriptpath, mod.name);
331 errorstream<<"Server: Failed to load and run "
332 <<scriptpath<<std::endl;
333 throw ModError("Failed to load and run "+scriptpath);
337 // Read Textures and calculate sha1 sums
340 // Apply item aliases in the node definition manager
341 m_nodedef->updateAliases(m_itemdef);
343 m_nodedef->setNodeRegistrationStatus(true);
345 // Perform pending node name resolutions
346 m_nodedef->runNodeResolverCallbacks();
348 // Initialize Environment
349 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
351 m_clients.setEnv(m_env);
353 // Initialize mapgens
354 m_emerge->initMapgens();
356 // Give environment reference to scripting api
357 m_script->initializeEnvironment(m_env);
359 // Register us to receive map edit events
360 servermap->addEventReceiver(this);
362 // If file exists, load environment metadata
363 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
365 infostream<<"Server: Loading environment metadata"<<std::endl;
369 // Add some test ActiveBlockModifiers to environment
370 add_legacy_abms(m_env, m_nodedef);
372 m_liquid_transform_every = g_settings->getFloat("liquid_update");
377 infostream<<"Server destructing"<<std::endl;
379 // Send shutdown message
380 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
383 JMutexAutoLock envlock(m_env_mutex);
385 // Execute script shutdown hooks
386 m_script->on_shutdown();
388 infostream<<"Server: Saving players"<<std::endl;
389 m_env->saveLoadedPlayers();
391 infostream<<"Server: Saving environment metadata"<<std::endl;
399 // stop all emerge threads before deleting players that may have
400 // requested blocks to be emerged
401 m_emerge->stopThreads();
403 // Delete things in the reverse order of creation
406 // N.B. the EmergeManager should be deleted after the Environment since Map
407 // depends on EmergeManager to write its current params to the map meta
416 // Deinitialize scripting
417 infostream<<"Server: Deinitializing scripting"<<std::endl;
420 // Delete detached inventories
421 for (std::map<std::string, Inventory*>::iterator
422 i = m_detached_inventories.begin();
423 i != m_detached_inventories.end(); i++) {
428 void Server::start(Address bind_addr)
430 DSTACK(__FUNCTION_NAME);
432 m_bind_addr = bind_addr;
434 infostream<<"Starting server on "
435 << bind_addr.serializeString() <<"..."<<std::endl;
437 // Stop thread if already running
440 // Initialize connection
441 m_con.SetTimeoutMs(30);
442 m_con.Serve(bind_addr);
447 // ASCII art for the win!
449 <<" .__ __ __ "<<std::endl
450 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
451 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
452 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
453 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
454 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
455 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
456 actionstream<<"Server for gameid=\""<<m_gamespec.id
457 <<"\" listening on "<<bind_addr.serializeString()<<":"
458 <<bind_addr.getPort() << "."<<std::endl;
463 DSTACK(__FUNCTION_NAME);
465 infostream<<"Server: Stopping and waiting threads"<<std::endl;
467 // Stop threads (set run=false first so both start stopping)
469 //m_emergethread.setRun(false);
471 //m_emergethread.stop();
473 infostream<<"Server: Threads stopped"<<std::endl;
476 void Server::step(float dtime)
478 DSTACK(__FUNCTION_NAME);
483 JMutexAutoLock lock(m_step_dtime_mutex);
484 m_step_dtime += dtime;
486 // Throw if fatal error occurred in thread
487 std::string async_err = m_async_fatal_error.get();
489 throw ServerError(async_err);
493 void Server::AsyncRunStep(bool initial_step)
495 DSTACK(__FUNCTION_NAME);
497 g_profiler->add("Server::AsyncRunStep (num)", 1);
501 JMutexAutoLock lock1(m_step_dtime_mutex);
502 dtime = m_step_dtime;
506 // Send blocks to clients
510 if((dtime < 0.001) && (initial_step == false))
513 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
515 //infostream<<"Server steps "<<dtime<<std::endl;
516 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
519 JMutexAutoLock lock1(m_step_dtime_mutex);
520 m_step_dtime -= dtime;
527 m_uptime.set(m_uptime.get() + dtime);
533 Update time of day and overall game time
536 JMutexAutoLock envlock(m_env_mutex);
538 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
541 Send to clients at constant intervals
544 m_time_of_day_send_timer -= dtime;
545 if(m_time_of_day_send_timer < 0.0)
547 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
548 u16 time = m_env->getTimeOfDay();
549 float time_speed = g_settings->getFloat("time_speed");
550 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
555 JMutexAutoLock lock(m_env_mutex);
556 // Figure out and report maximum lag to environment
557 float max_lag = m_env->getMaxLagEstimate();
558 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
560 if(dtime > 0.1 && dtime > max_lag * 2.0)
561 infostream<<"Server: Maximum lag peaked to "<<dtime
565 m_env->reportMaxLagEstimate(max_lag);
567 ScopeProfiler sp(g_profiler, "SEnv step");
568 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
572 static const float map_timer_and_unload_dtime = 2.92;
573 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
575 JMutexAutoLock lock(m_env_mutex);
576 // Run Map's timers and unload unused data
577 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
578 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
579 g_settings->getFloat("server_unload_unused_data_timeout"));
590 JMutexAutoLock lock(m_env_mutex);
592 std::list<u16> clientids = m_clients.getClientIDs();
594 ScopeProfiler sp(g_profiler, "Server: handle players");
596 for(std::list<u16>::iterator
597 i = clientids.begin();
598 i != clientids.end(); ++i)
600 PlayerSAO *playersao = getPlayerSAO(*i);
601 if(playersao == NULL)
605 Handle player HPs (die if hp=0)
607 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
609 if(playersao->getHP() == 0)
616 Send player breath if changed
618 if(playersao->m_breath_not_sent) {
619 SendPlayerBreath(*i);
623 Send player inventories if necessary
625 if(playersao->m_moved) {
627 playersao->m_moved = false;
629 if(playersao->m_inventory_not_sent) {
636 /* Transform liquids */
637 m_liquid_transform_timer += dtime;
638 if(m_liquid_transform_timer >= m_liquid_transform_every)
640 m_liquid_transform_timer -= m_liquid_transform_every;
642 JMutexAutoLock lock(m_env_mutex);
644 ScopeProfiler sp(g_profiler, "Server: liquid transform");
646 std::map<v3s16, MapBlock*> modified_blocks;
647 m_env->getMap().transformLiquids(modified_blocks);
652 core::map<v3s16, MapBlock*> lighting_modified_blocks;
653 ServerMap &map = ((ServerMap&)m_env->getMap());
654 map.updateLighting(modified_blocks, lighting_modified_blocks);
656 // Add blocks modified by lighting to modified_blocks
657 for(core::map<v3s16, MapBlock*>::Iterator
658 i = lighting_modified_blocks.getIterator();
659 i.atEnd() == false; i++)
661 MapBlock *block = i.getNode()->getValue();
662 modified_blocks.insert(block->getPos(), block);
666 Set the modified blocks unsent for all the clients
668 if(!modified_blocks.empty())
670 SetBlocksNotSent(modified_blocks);
673 m_clients.step(dtime);
675 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
677 // send masterserver announce
679 float &counter = m_masterserver_timer;
680 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
681 g_settings->getBool("server_announce"))
683 ServerList::sendAnnounce(counter ? "update" : "start",
684 m_bind_addr.getPort(),
685 m_clients.getPlayerNames(),
687 m_env->getGameTime(),
690 m_emerge->params.mg_name,
699 Check added and deleted active objects
702 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
703 JMutexAutoLock envlock(m_env_mutex);
706 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
707 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
709 // Radius inside which objects are active
710 s16 radius = g_settings->getS16("active_object_send_range_blocks");
711 s16 player_radius = g_settings->getS16("player_transfer_distance");
713 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
714 !g_settings->getBool("unlimited_player_transfer_distance"))
715 player_radius = radius;
717 radius *= MAP_BLOCKSIZE;
718 player_radius *= MAP_BLOCKSIZE;
720 for(std::map<u16, RemoteClient*>::iterator
722 i != clients.end(); ++i)
724 RemoteClient *client = i->second;
726 // If definitions and textures have not been sent, don't
727 // send objects either
728 if (client->getState() < CS_DefinitionsSent)
731 Player *player = m_env->getPlayer(client->peer_id);
734 // This can happen if the client timeouts somehow
735 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
737 <<" has no associated player"<<std::endl;*/
740 v3s16 pos = floatToInt(player->getPosition(), BS);
742 std::set<u16> removed_objects;
743 std::set<u16> added_objects;
744 m_env->getRemovedActiveObjects(pos, radius, player_radius,
745 client->m_known_objects, removed_objects);
746 m_env->getAddedActiveObjects(pos, radius, player_radius,
747 client->m_known_objects, added_objects);
749 // Ignore if nothing happened
750 if(removed_objects.empty() && added_objects.empty())
752 //infostream<<"active objects: none changed"<<std::endl;
756 std::string data_buffer;
760 // Handle removed objects
761 writeU16((u8*)buf, removed_objects.size());
762 data_buffer.append(buf, 2);
763 for(std::set<u16>::iterator
764 i = removed_objects.begin();
765 i != removed_objects.end(); ++i)
769 ServerActiveObject* obj = m_env->getActiveObject(id);
771 // Add to data buffer for sending
772 writeU16((u8*)buf, id);
773 data_buffer.append(buf, 2);
775 // Remove from known objects
776 client->m_known_objects.erase(id);
778 if(obj && obj->m_known_by_count > 0)
779 obj->m_known_by_count--;
782 // Handle added objects
783 writeU16((u8*)buf, added_objects.size());
784 data_buffer.append(buf, 2);
785 for(std::set<u16>::iterator
786 i = added_objects.begin();
787 i != added_objects.end(); ++i)
791 ServerActiveObject* obj = m_env->getActiveObject(id);
794 u8 type = ACTIVEOBJECT_TYPE_INVALID;
796 infostream<<"WARNING: "<<__FUNCTION_NAME
797 <<": NULL object"<<std::endl;
799 type = obj->getSendType();
801 // Add to data buffer for sending
802 writeU16((u8*)buf, id);
803 data_buffer.append(buf, 2);
804 writeU8((u8*)buf, type);
805 data_buffer.append(buf, 1);
808 data_buffer.append(serializeLongString(
809 obj->getClientInitializationData(client->net_proto_version)));
811 data_buffer.append(serializeLongString(""));
813 // Add to known objects
814 client->m_known_objects.insert(id);
817 obj->m_known_by_count++;
820 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
821 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
824 verbosestream << "Server: Sent object remove/add: "
825 << removed_objects.size() << " removed, "
826 << added_objects.size() << " added, "
827 << "packet size is " << pkt->getSize() << std::endl;
838 JMutexAutoLock envlock(m_env_mutex);
839 ScopeProfiler sp(g_profiler, "Server: sending object messages");
842 // Value = data sent by object
843 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
845 // Get active object messages from environment
848 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
852 std::list<ActiveObjectMessage>* message_list = NULL;
853 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
854 n = buffered_messages.find(aom.id);
855 if(n == buffered_messages.end())
857 message_list = new std::list<ActiveObjectMessage>;
858 buffered_messages[aom.id] = message_list;
862 message_list = n->second;
864 message_list->push_back(aom);
868 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
869 // Route data to every client
870 for(std::map<u16, RemoteClient*>::iterator
872 i != clients.end(); ++i)
874 RemoteClient *client = i->second;
875 std::string reliable_data;
876 std::string unreliable_data;
877 // Go through all objects in message buffer
878 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
879 j = buffered_messages.begin();
880 j != buffered_messages.end(); ++j)
882 // If object is not known by client, skip it
884 if(client->m_known_objects.find(id) == client->m_known_objects.end())
886 // Get message list of object
887 std::list<ActiveObjectMessage>* list = j->second;
888 // Go through every message
889 for(std::list<ActiveObjectMessage>::iterator
890 k = list->begin(); k != list->end(); ++k)
892 // Compose the full new data with header
893 ActiveObjectMessage aom = *k;
894 std::string new_data;
897 writeU16((u8*)&buf[0], aom.id);
898 new_data.append(buf, 2);
900 new_data += serializeString(aom.datastring);
901 // Add data to buffer
903 reliable_data += new_data;
905 unreliable_data += new_data;
909 reliable_data and unreliable_data are now ready.
912 if(reliable_data.size() > 0) {
913 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
916 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
920 if(unreliable_data.size() > 0) {
921 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
924 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
930 // Clear buffered_messages
931 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
932 i = buffered_messages.begin();
933 i != buffered_messages.end(); ++i)
940 Send queued-for-sending map edit events.
943 // We will be accessing the environment
944 JMutexAutoLock lock(m_env_mutex);
946 // Don't send too many at a time
949 // Single change sending is disabled if queue size is not small
950 bool disable_single_change_sending = false;
951 if(m_unsent_map_edit_queue.size() >= 4)
952 disable_single_change_sending = true;
954 int event_count = m_unsent_map_edit_queue.size();
956 // We'll log the amount of each
959 while(m_unsent_map_edit_queue.size() != 0)
961 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
963 // Players far away from the change are stored here.
964 // Instead of sending the changes, MapBlocks are set not sent
966 std::list<u16> far_players;
968 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
970 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
971 prof.add("MEET_ADDNODE", 1);
972 if(disable_single_change_sending)
973 sendAddNode(event->p, event->n, event->already_known_by_peer,
974 &far_players, 5, event->type == MEET_ADDNODE);
976 sendAddNode(event->p, event->n, event->already_known_by_peer,
977 &far_players, 30, event->type == MEET_ADDNODE);
979 else if(event->type == MEET_REMOVENODE)
981 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
982 prof.add("MEET_REMOVENODE", 1);
983 if(disable_single_change_sending)
984 sendRemoveNode(event->p, event->already_known_by_peer,
987 sendRemoveNode(event->p, event->already_known_by_peer,
990 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
992 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
993 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
994 setBlockNotSent(event->p);
996 else if(event->type == MEET_OTHER)
998 infostream<<"Server: MEET_OTHER"<<std::endl;
999 prof.add("MEET_OTHER", 1);
1000 for(std::set<v3s16>::iterator
1001 i = event->modified_blocks.begin();
1002 i != event->modified_blocks.end(); ++i)
1004 setBlockNotSent(*i);
1009 prof.add("unknown", 1);
1010 infostream<<"WARNING: Server: Unknown MapEditEvent "
1011 <<((u32)event->type)<<std::endl;
1015 Set blocks not sent to far players
1017 if(!far_players.empty())
1019 // Convert list format to that wanted by SetBlocksNotSent
1020 std::map<v3s16, MapBlock*> modified_blocks2;
1021 for(std::set<v3s16>::iterator
1022 i = event->modified_blocks.begin();
1023 i != event->modified_blocks.end(); ++i)
1025 modified_blocks2[*i] =
1026 m_env->getMap().getBlockNoCreateNoEx(*i);
1028 // Set blocks not sent
1029 for(std::list<u16>::iterator
1030 i = far_players.begin();
1031 i != far_players.end(); ++i)
1034 RemoteClient *client = getClient(peer_id);
1037 client->SetBlocksNotSent(modified_blocks2);
1043 /*// Don't send too many at a time
1045 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1049 if(event_count >= 5){
1050 infostream<<"Server: MapEditEvents:"<<std::endl;
1051 prof.print(infostream);
1052 } else if(event_count != 0){
1053 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1054 prof.print(verbosestream);
1060 Trigger emergethread (it somehow gets to a non-triggered but
1061 bysy state sometimes)
1064 float &counter = m_emergethread_trigger_timer;
1070 m_emerge->startThreads();
1072 // Update m_enable_rollback_recording here too
1073 m_enable_rollback_recording =
1074 g_settings->getBool("enable_rollback_recording");
1078 // Save map, players and auth stuff
1080 float &counter = m_savemap_timer;
1082 if(counter >= g_settings->getFloat("server_map_save_interval"))
1085 JMutexAutoLock lock(m_env_mutex);
1087 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1090 if (m_banmanager->isModified()) {
1091 m_banmanager->save();
1094 // Save changed parts of map
1095 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1098 m_env->saveLoadedPlayers();
1100 // Save environment metadata
1106 void Server::Receive()
1108 DSTACK(__FUNCTION_NAME);
1109 SharedBuffer<u8> data;
1113 datasize = m_con.Receive(peer_id,data);
1114 ProcessData(*data, datasize, peer_id);
1116 catch(con::InvalidIncomingDataException &e) {
1117 infostream<<"Server::Receive(): "
1118 "InvalidIncomingDataException: what()="
1119 <<e.what()<<std::endl;
1121 catch(SerializationError &e) {
1122 infostream<<"Server::Receive(): "
1123 "SerializationError: what()="
1124 <<e.what()<<std::endl;
1126 catch(ClientStateError &e) {
1127 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1128 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1129 L"Try reconnecting or updating your client");
1131 catch(con::PeerNotFoundException &e) {
1136 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1138 std::string playername = "";
1139 PlayerSAO *playersao = NULL;
1142 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1143 if (client != NULL) {
1144 playername = client->getName();
1145 playersao = emergePlayer(playername.c_str(), peer_id);
1147 } catch (std::exception &e) {
1153 RemotePlayer *player =
1154 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1156 // If failed, cancel
1157 if((playersao == NULL) || (player == NULL)) {
1158 if(player && player->peer_id != 0) {
1159 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1160 <<" (player allocated to an another client)"<<std::endl;
1161 DenyAccess(peer_id, L"Another client is connected with this "
1162 L"name. If your client closed unexpectedly, try again in "
1165 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1167 DenyAccess(peer_id, L"Could not allocate player.");
1173 Send complete position information
1175 SendMovePlayer(peer_id);
1178 SendPlayerPrivileges(peer_id);
1180 // Send inventory formspec
1181 SendPlayerInventoryFormspec(peer_id);
1184 UpdateCrafting(peer_id);
1185 SendInventory(peer_id);
1188 if(g_settings->getBool("enable_damage"))
1189 SendPlayerHP(peer_id);
1192 SendPlayerBreath(peer_id);
1194 // Show death screen if necessary
1196 SendDeathscreen(peer_id, false, v3f(0,0,0));
1198 // Note things in chat if not in simple singleplayer mode
1199 if(!m_simple_singleplayer_mode) {
1200 // Send information about server to player in chat
1201 SendChatMessage(peer_id, getStatusString());
1203 // Send information about joining in chat
1205 std::wstring name = L"unknown";
1206 Player *player = m_env->getPlayer(peer_id);
1208 name = narrow_to_wide(player->getName());
1210 std::wstring message;
1213 message += L" joined the game.";
1214 SendChatMessage(PEER_ID_INEXISTENT,message);
1217 Address addr = getPeerAddress(player->peer_id);
1218 std::string ip_str = addr.serializeString();
1219 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1224 std::vector<std::string> names = m_clients.getPlayerNames();
1226 actionstream<<player->getName() <<" joins game. List of players: ";
1228 for (std::vector<std::string>::iterator i = names.begin();
1229 i != names.end(); i++) {
1230 actionstream << *i << " ";
1233 actionstream << player->getName() <<std::endl;
1238 inline void Server::handleCommand(NetworkPacket* pkt)
1240 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1241 (this->*opHandle.handler)(pkt);
1244 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1246 DSTACK(__FUNCTION_NAME);
1247 // Environment is locked first.
1248 JMutexAutoLock envlock(m_env_mutex);
1250 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1253 Address address = getPeerAddress(peer_id);
1254 std::string addr_s = address.serializeString();
1256 if(m_banmanager->isIpBanned(addr_s)) {
1257 std::string ban_name = m_banmanager->getBanName(addr_s);
1258 infostream << "Server: A banned client tried to connect from "
1259 << addr_s << "; banned name was "
1260 << ban_name << std::endl;
1261 // This actually doesn't seem to transfer to the client
1262 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1263 + narrow_to_wide(ban_name));
1267 catch(con::PeerNotFoundException &e) {
1269 * no peer for this packet found
1270 * most common reason is peer timeout, e.g. peer didn't
1271 * respond for some time, your server was overloaded or
1274 infostream << "Server::ProcessData(): Cancelling: peer "
1275 << peer_id << " not found" << std::endl;
1283 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1285 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1287 // Command must be handled into ToServerCommandHandler
1288 if (command >= TOSERVER_NUM_MSG_TYPES) {
1289 infostream << "Server: Ignoring unknown command "
1290 << command << std::endl;
1293 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1299 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1301 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1302 errorstream << "Server::ProcessData(): Cancelling: Peer"
1303 " serialization format invalid or not initialized."
1304 " Skipping incoming command=" << command << std::endl;
1310 /* Handle commands related to client startup */
1311 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1317 if (m_clients.getClientState(peer_id) < CS_Active) {
1318 if (command == TOSERVER_PLAYERPOS) return;
1320 errorstream << "Got packet command: " << command << " for peer id "
1321 << peer_id << " but client isn't active yet. Dropping packet "
1332 catch(SendFailedException &e) {
1333 errorstream << "Server::ProcessData(): SendFailedException: "
1334 << "what=" << e.what()
1339 void Server::setTimeOfDay(u32 time)
1341 m_env->setTimeOfDay(time);
1342 m_time_of_day_send_timer = 0;
1345 void Server::onMapEditEvent(MapEditEvent *event)
1347 if(m_ignore_map_edit_events)
1349 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1351 MapEditEvent *e = event->clone();
1352 m_unsent_map_edit_queue.push_back(e);
1355 Inventory* Server::getInventory(const InventoryLocation &loc)
1358 case InventoryLocation::UNDEFINED:
1359 case InventoryLocation::CURRENT_PLAYER:
1361 case InventoryLocation::PLAYER:
1363 Player *player = m_env->getPlayer(loc.name.c_str());
1366 PlayerSAO *playersao = player->getPlayerSAO();
1369 return playersao->getInventory();
1372 case InventoryLocation::NODEMETA:
1374 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1377 return meta->getInventory();
1380 case InventoryLocation::DETACHED:
1382 if(m_detached_inventories.count(loc.name) == 0)
1384 return m_detached_inventories[loc.name];
1392 void Server::setInventoryModified(const InventoryLocation &loc)
1395 case InventoryLocation::UNDEFINED:
1397 case InventoryLocation::PLAYER:
1399 Player *player = m_env->getPlayer(loc.name.c_str());
1402 PlayerSAO *playersao = player->getPlayerSAO();
1405 playersao->m_inventory_not_sent = true;
1406 playersao->m_wielded_item_not_sent = true;
1409 case InventoryLocation::NODEMETA:
1411 v3s16 blockpos = getNodeBlockPos(loc.p);
1413 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1415 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1417 setBlockNotSent(blockpos);
1420 case InventoryLocation::DETACHED:
1422 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1430 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1432 std::list<u16> clients = m_clients.getClientIDs();
1434 // Set the modified blocks unsent for all the clients
1435 for (std::list<u16>::iterator
1436 i = clients.begin();
1437 i != clients.end(); ++i) {
1438 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
1440 client->SetBlocksNotSent(block);
1445 void Server::peerAdded(con::Peer *peer)
1447 DSTACK(__FUNCTION_NAME);
1448 verbosestream<<"Server::peerAdded(): peer->id="
1449 <<peer->id<<std::endl;
1452 c.type = con::PEER_ADDED;
1453 c.peer_id = peer->id;
1455 m_peer_change_queue.push_back(c);
1458 void Server::deletingPeer(con::Peer *peer, bool timeout)
1460 DSTACK(__FUNCTION_NAME);
1461 verbosestream<<"Server::deletingPeer(): peer->id="
1462 <<peer->id<<", timeout="<<timeout<<std::endl;
1464 m_clients.event(peer->id, CSE_Disconnect);
1466 c.type = con::PEER_REMOVED;
1467 c.peer_id = peer->id;
1468 c.timeout = timeout;
1469 m_peer_change_queue.push_back(c);
1472 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1474 *retval = m_con.getPeerStat(peer_id,type);
1475 if (*retval == -1) return false;
1479 bool Server::getClientInfo(
1488 std::string* vers_string
1491 *state = m_clients.getClientState(peer_id);
1493 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1495 if (client == NULL) {
1500 *uptime = client->uptime();
1501 *ser_vers = client->serialization_version;
1502 *prot_vers = client->net_proto_version;
1504 *major = client->getMajor();
1505 *minor = client->getMinor();
1506 *patch = client->getPatch();
1507 *vers_string = client->getPatch();
1514 void Server::handlePeerChanges()
1516 while(m_peer_change_queue.size() > 0)
1518 con::PeerChange c = m_peer_change_queue.pop_front();
1520 verbosestream<<"Server: Handling peer change: "
1521 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1526 case con::PEER_ADDED:
1527 m_clients.CreateClient(c.peer_id);
1530 case con::PEER_REMOVED:
1531 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1535 assert("Invalid peer change event received!" == 0);
1541 void Server::Send(NetworkPacket* pkt)
1543 m_clients.send(pkt->getPeerId(),
1544 clientCommandFactoryTable[pkt->getCommand()].channel,
1546 clientCommandFactoryTable[pkt->getCommand()].reliable);
1549 void Server::SendMovement(u16 peer_id)
1551 DSTACK(__FUNCTION_NAME);
1552 std::ostringstream os(std::ios_base::binary);
1554 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1556 *pkt << g_settings->getFloat("movement_acceleration_default");
1557 *pkt << g_settings->getFloat("movement_acceleration_air");
1558 *pkt << g_settings->getFloat("movement_acceleration_fast");
1559 *pkt << g_settings->getFloat("movement_speed_walk");
1560 *pkt << g_settings->getFloat("movement_speed_crouch");
1561 *pkt << g_settings->getFloat("movement_speed_fast");
1562 *pkt << g_settings->getFloat("movement_speed_climb");
1563 *pkt << g_settings->getFloat("movement_speed_jump");
1564 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1565 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1566 *pkt << g_settings->getFloat("movement_liquid_sink");
1567 *pkt << g_settings->getFloat("movement_gravity");
1572 void Server::SendHP(u16 peer_id, u8 hp)
1574 DSTACK(__FUNCTION_NAME);
1576 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1581 void Server::SendBreath(u16 peer_id, u16 breath)
1583 DSTACK(__FUNCTION_NAME);
1585 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1586 *pkt << (u16) breath;
1590 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1592 DSTACK(__FUNCTION_NAME);
1594 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1599 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1600 v3f camera_point_target)
1602 DSTACK(__FUNCTION_NAME);
1604 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1605 *pkt << set_camera_point_target << camera_point_target;
1609 void Server::SendItemDef(u16 peer_id,
1610 IItemDefManager *itemdef, u16 protocol_version)
1612 DSTACK(__FUNCTION_NAME);
1614 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1618 u32 length of the next item
1619 zlib-compressed serialized ItemDefManager
1621 std::ostringstream tmp_os(std::ios::binary);
1622 itemdef->serialize(tmp_os, protocol_version);
1623 std::ostringstream tmp_os2(std::ios::binary);
1624 compressZlib(tmp_os.str(), tmp_os2);
1625 pkt->putLongString(tmp_os2.str());
1628 verbosestream << "Server: Sending item definitions to id(" << peer_id
1629 << "): size=" << pkt->getSize() << std::endl;
1634 void Server::SendNodeDef(u16 peer_id,
1635 INodeDefManager *nodedef, u16 protocol_version)
1637 DSTACK(__FUNCTION_NAME);
1639 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1643 u32 length of the next item
1644 zlib-compressed serialized NodeDefManager
1646 std::ostringstream tmp_os(std::ios::binary);
1647 nodedef->serialize(tmp_os, protocol_version);
1648 std::ostringstream tmp_os2(std::ios::binary);
1649 compressZlib(tmp_os.str(), tmp_os2);
1651 pkt->putLongString(tmp_os2.str());
1654 verbosestream << "Server: Sending node definitions to id(" << peer_id
1655 << "): size=" << pkt->getSize() << std::endl;
1661 Non-static send methods
1664 void Server::SendInventory(u16 peer_id)
1666 DSTACK(__FUNCTION_NAME);
1668 PlayerSAO *playersao = getPlayerSAO(peer_id);
1671 playersao->m_inventory_not_sent = false;
1677 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0, peer_id);
1679 std::ostringstream os;
1680 playersao->getInventory()->serialize(os);
1682 std::string s = os.str();
1684 pkt->putRawString(s.c_str(), s.size());
1688 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1690 DSTACK(__FUNCTION_NAME);
1692 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1695 if (peer_id != PEER_ID_INEXISTENT) {
1699 m_clients.sendToAll(0,pkt,true);
1703 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1704 const std::string &formname)
1706 DSTACK(__FUNCTION_NAME);
1708 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1710 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1716 // Spawns a particle on peer with peer_id
1717 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1718 float expirationtime, float size, bool collisiondetection,
1719 bool vertical, std::string texture)
1721 DSTACK(__FUNCTION_NAME);
1723 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1725 *pkt << pos << velocity << acceleration << expirationtime
1726 << size << collisiondetection;
1727 pkt->putLongString(texture);
1730 if (peer_id != PEER_ID_INEXISTENT) {
1734 m_clients.sendToAll(0,pkt,true);
1738 // Adds a ParticleSpawner on peer with peer_id
1739 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1740 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1741 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1743 DSTACK(__FUNCTION_NAME);
1745 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1747 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1748 << minacc << maxacc << minexptime << maxexptime << minsize
1749 << maxsize << collisiondetection;
1751 pkt->putLongString(texture);
1753 *pkt << id << vertical;
1755 if (peer_id != PEER_ID_INEXISTENT) {
1759 m_clients.sendToAll(0, pkt, true);
1763 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1765 DSTACK(__FUNCTION_NAME);
1767 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1769 // Ugly error in this packet
1772 if (peer_id != PEER_ID_INEXISTENT) {
1776 m_clients.sendToAll(0, pkt, true);
1781 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1783 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1785 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1786 << form->text << form->number << form->item << form->dir
1787 << form->align << form->offset << form->world_pos << form->size;
1792 void Server::SendHUDRemove(u16 peer_id, u32 id)
1794 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1799 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1801 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1802 *pkt << id << (u8) stat;
1806 case HUD_STAT_SCALE:
1807 case HUD_STAT_ALIGN:
1808 case HUD_STAT_OFFSET:
1809 *pkt << *(v2f *) value;
1813 *pkt << *(std::string *) value;
1815 case HUD_STAT_WORLD_POS:
1816 *pkt << *(v3f *) value;
1819 *pkt << *(v2s32 *) value;
1821 case HUD_STAT_NUMBER:
1825 *pkt << *(u32 *) value;
1832 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1834 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1836 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1838 *pkt << flags << mask;
1843 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1845 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1846 *pkt << param << value;
1850 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1851 const std::string &type, const std::vector<std::string> ¶ms)
1853 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1854 *pkt << bgcolor << type << (u16) params.size();
1856 for(size_t i=0; i<params.size(); i++)
1862 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1865 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1868 *pkt << do_override << (u16) (ratio * 65535);
1873 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1875 DSTACK(__FUNCTION_NAME);
1877 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1878 *pkt << time << time_speed;
1880 if (peer_id == PEER_ID_INEXISTENT) {
1881 m_clients.sendToAll(0, pkt, true);
1888 void Server::SendPlayerHP(u16 peer_id)
1890 DSTACK(__FUNCTION_NAME);
1891 PlayerSAO *playersao = getPlayerSAO(peer_id);
1893 playersao->m_hp_not_sent = false;
1894 SendHP(peer_id, playersao->getHP());
1895 m_script->player_event(playersao,"health_changed");
1897 // Send to other clients
1898 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1899 ActiveObjectMessage aom(playersao->getId(), true, str);
1900 playersao->m_messages_out.push_back(aom);
1903 void Server::SendPlayerBreath(u16 peer_id)
1905 DSTACK(__FUNCTION_NAME);
1906 PlayerSAO *playersao = getPlayerSAO(peer_id);
1908 playersao->m_breath_not_sent = false;
1909 m_script->player_event(playersao,"breath_changed");
1910 SendBreath(peer_id, playersao->getBreath());
1913 void Server::SendMovePlayer(u16 peer_id)
1915 DSTACK(__FUNCTION_NAME);
1916 Player *player = m_env->getPlayer(peer_id);
1919 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1920 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1923 v3f pos = player->getPosition();
1924 f32 pitch = player->getPitch();
1925 f32 yaw = player->getYaw();
1926 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1927 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1936 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1938 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1941 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1942 << animation_frames[3] << animation_speed;
1947 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1949 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1950 *pkt << first << third;
1953 void Server::SendPlayerPrivileges(u16 peer_id)
1955 Player *player = m_env->getPlayer(peer_id);
1957 if(player->peer_id == PEER_ID_INEXISTENT)
1960 std::set<std::string> privs;
1961 m_script->getAuth(player->getName(), NULL, &privs);
1963 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1964 *pkt << (u16) privs.size();
1966 for(std::set<std::string>::const_iterator i = privs.begin();
1967 i != privs.end(); i++) {
1974 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1976 Player *player = m_env->getPlayer(peer_id);
1978 if(player->peer_id == PEER_ID_INEXISTENT)
1981 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1982 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1986 s32 Server::playSound(const SimpleSoundSpec &spec,
1987 const ServerSoundParams ¶ms)
1989 // Find out initial position of sound
1990 bool pos_exists = false;
1991 v3f pos = params.getPos(m_env, &pos_exists);
1992 // If position is not found while it should be, cancel sound
1993 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1996 // Filter destination clients
1997 std::list<u16> dst_clients;
1998 if(params.to_player != "")
2000 Player *player = m_env->getPlayer(params.to_player.c_str());
2002 infostream<<"Server::playSound: Player \""<<params.to_player
2003 <<"\" not found"<<std::endl;
2006 if(player->peer_id == PEER_ID_INEXISTENT){
2007 infostream<<"Server::playSound: Player \""<<params.to_player
2008 <<"\" not connected"<<std::endl;
2011 dst_clients.push_back(player->peer_id);
2015 std::list<u16> clients = m_clients.getClientIDs();
2017 for(std::list<u16>::iterator
2018 i = clients.begin(); i != clients.end(); ++i)
2020 Player *player = m_env->getPlayer(*i);
2024 if(player->getPosition().getDistanceFrom(pos) >
2025 params.max_hear_distance)
2028 dst_clients.push_back(*i);
2031 if(dst_clients.empty())
2035 s32 id = m_next_sound_id++;
2036 // The sound will exist as a reference in m_playing_sounds
2037 m_playing_sounds[id] = ServerPlayingSound();
2038 ServerPlayingSound &psound = m_playing_sounds[id];
2039 psound.params = params;
2040 for(std::list<u16>::iterator i = dst_clients.begin();
2041 i != dst_clients.end(); i++)
2042 psound.clients.insert(*i);
2044 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
2045 *pkt << id << spec.name << (float) (spec.gain * params.gain)
2046 << (u8) params.type << pos << params.object << params.loop;
2047 for(std::list<u16>::iterator i = dst_clients.begin();
2048 i != dst_clients.end(); i++) {
2050 m_clients.send(*i, 0, pkt, true, false);
2055 void Server::stopSound(s32 handle)
2057 // Get sound reference
2058 std::map<s32, ServerPlayingSound>::iterator i =
2059 m_playing_sounds.find(handle);
2060 if(i == m_playing_sounds.end())
2062 ServerPlayingSound &psound = i->second;
2064 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2067 for(std::set<u16>::iterator i = psound.clients.begin();
2068 i != psound.clients.end(); i++) {
2070 m_clients.send(*i, 0, pkt, true, false);
2073 // Remove sound reference
2074 m_playing_sounds.erase(i);
2077 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2078 std::list<u16> *far_players, float far_d_nodes)
2080 float maxd = far_d_nodes*BS;
2081 v3f p_f = intToFloat(p, BS);
2083 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 2 + 2 + 2);
2086 std::list<u16> clients = m_clients.getClientIDs();
2087 for(std::list<u16>::iterator
2088 i = clients.begin();
2089 i != clients.end(); ++i)
2094 Player *player = m_env->getPlayer(*i);
2097 // If player is far away, only set modified blocks not sent
2098 v3f player_pos = player->getPosition();
2099 if(player_pos.getDistanceFrom(p_f) > maxd)
2101 far_players->push_back(*i);
2108 m_clients.send(*i, 0, pkt, true, false);
2110 // This loop needs the deletion of the packet here
2114 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2115 std::list<u16> *far_players, float far_d_nodes,
2116 bool remove_metadata)
2118 float maxd = far_d_nodes*BS;
2119 v3f p_f = intToFloat(p, BS);
2121 std::list<u16> clients = m_clients.getClientIDs();
2122 for(std::list<u16>::iterator
2123 i = clients.begin();
2124 i != clients.end(); ++i)
2130 Player *player = m_env->getPlayer(*i);
2133 // If player is far away, only set modified blocks not sent
2134 v3f player_pos = player->getPosition();
2135 if(player_pos.getDistanceFrom(p_f) > maxd)
2137 far_players->push_back(*i);
2143 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 0);
2145 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2147 *pkt << p << n.param0 << n.param1 << n.param2
2148 << (u8) (remove_metadata ? 0 : 1);
2150 if (!remove_metadata) {
2151 if (client->net_proto_version <= 21) {
2152 // Old clients always clear metadata; fix it
2153 // by sending the full block again.
2154 client->SetBlockNotSent(p);
2161 if (pkt->getSize() > 0)
2162 m_clients.send(*i, 0, pkt, true);
2166 void Server::setBlockNotSent(v3s16 p)
2168 std::list<u16> clients = m_clients.getClientIDs();
2170 for(std::list<u16>::iterator
2171 i = clients.begin();
2172 i != clients.end(); ++i)
2174 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2175 client->SetBlockNotSent(p);
2180 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2182 DSTACK(__FUNCTION_NAME);
2184 v3s16 p = block->getPos();
2187 Create a packet with the block in the right format
2190 std::ostringstream os(std::ios_base::binary);
2191 block->serialize(os, ver, false);
2192 block->serializeNetworkSpecific(os, net_proto_version);
2193 std::string s = os.str();
2195 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2196 2 + 2 + 2 + 2 + s.size(), peer_id);
2199 pkt->putRawString(s.c_str(), s.size());
2203 void Server::SendBlocks(float dtime)
2205 DSTACK(__FUNCTION_NAME);
2207 JMutexAutoLock envlock(m_env_mutex);
2208 //TODO check if one big lock could be faster then multiple small ones
2210 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2212 std::vector<PrioritySortedBlockTransfer> queue;
2214 s32 total_sending = 0;
2217 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2219 std::list<u16> clients = m_clients.getClientIDs();
2222 for(std::list<u16>::iterator
2223 i = clients.begin();
2224 i != clients.end(); ++i)
2226 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2231 total_sending += client->SendingCount();
2232 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2238 // Lowest priority number comes first.
2239 // Lowest is most important.
2240 std::sort(queue.begin(), queue.end());
2243 for(u32 i=0; i<queue.size(); i++)
2245 //TODO: Calculate limit dynamically
2246 if(total_sending >= g_settings->getS32
2247 ("max_simultaneous_block_sends_server_total"))
2250 PrioritySortedBlockTransfer q = queue[i];
2252 MapBlock *block = NULL;
2255 block = m_env->getMap().getBlockNoCreate(q.pos);
2257 catch(InvalidPositionException &e)
2262 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2267 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2269 client->SentBlock(q.pos);
2275 void Server::fillMediaCache()
2277 DSTACK(__FUNCTION_NAME);
2279 infostream<<"Server: Calculating media file checksums"<<std::endl;
2281 // Collect all media file paths
2282 std::list<std::string> paths;
2283 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2284 i != m_mods.end(); i++){
2285 const ModSpec &mod = *i;
2286 paths.push_back(mod.path + DIR_DELIM + "textures");
2287 paths.push_back(mod.path + DIR_DELIM + "sounds");
2288 paths.push_back(mod.path + DIR_DELIM + "media");
2289 paths.push_back(mod.path + DIR_DELIM + "models");
2291 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2293 // Collect media file information from paths into cache
2294 for(std::list<std::string>::iterator i = paths.begin();
2295 i != paths.end(); i++)
2297 std::string mediapath = *i;
2298 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2299 for(u32 j=0; j<dirlist.size(); j++){
2300 if(dirlist[j].dir) // Ignode dirs
2302 std::string filename = dirlist[j].name;
2303 // If name contains illegal characters, ignore the file
2304 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2305 infostream<<"Server: ignoring illegal file name: \""
2306 <<filename<<"\""<<std::endl;
2309 // If name is not in a supported format, ignore it
2310 const char *supported_ext[] = {
2311 ".png", ".jpg", ".bmp", ".tga",
2312 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2314 ".x", ".b3d", ".md2", ".obj",
2317 if(removeStringEnd(filename, supported_ext) == ""){
2318 infostream<<"Server: ignoring unsupported file extension: \""
2319 <<filename<<"\""<<std::endl;
2322 // Ok, attempt to load the file and add to cache
2323 std::string filepath = mediapath + DIR_DELIM + filename;
2325 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2326 if(fis.good() == false){
2327 errorstream<<"Server::fillMediaCache(): Could not open \""
2328 <<filename<<"\" for reading"<<std::endl;
2331 std::ostringstream tmp_os(std::ios_base::binary);
2335 fis.read(buf, 1024);
2336 std::streamsize len = fis.gcount();
2337 tmp_os.write(buf, len);
2346 errorstream<<"Server::fillMediaCache(): Failed to read \""
2347 <<filename<<"\""<<std::endl;
2350 if(tmp_os.str().length() == 0){
2351 errorstream<<"Server::fillMediaCache(): Empty file \""
2352 <<filepath<<"\""<<std::endl;
2357 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2359 unsigned char *digest = sha1.getDigest();
2360 std::string sha1_base64 = base64_encode(digest, 20);
2361 std::string sha1_hex = hex_encode((char*)digest, 20);
2365 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2366 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2371 struct SendableMediaAnnouncement
2374 std::string sha1_digest;
2376 SendableMediaAnnouncement(const std::string &name_="",
2377 const std::string &sha1_digest_=""):
2379 sha1_digest(sha1_digest_)
2383 void Server::sendMediaAnnouncement(u16 peer_id)
2385 DSTACK(__FUNCTION_NAME);
2387 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2390 std::list<SendableMediaAnnouncement> file_announcements;
2392 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2393 i != m_media.end(); i++){
2395 file_announcements.push_back(
2396 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2400 std::ostringstream os(std::ios_base::binary);
2407 u16 length of sha1_digest
2412 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2413 *pkt << (u16) file_announcements.size();
2415 for(std::list<SendableMediaAnnouncement>::iterator
2416 j = file_announcements.begin();
2417 j != file_announcements.end(); ++j) {
2418 *pkt << j->name << j->sha1_digest;
2421 *pkt << g_settings->get("remote_media");
2425 struct SendableMedia
2431 SendableMedia(const std::string &name_="", const std::string &path_="",
2432 const std::string &data_=""):
2439 void Server::sendRequestedMedia(u16 peer_id,
2440 const std::list<std::string> &tosend)
2442 DSTACK(__FUNCTION_NAME);
2444 verbosestream<<"Server::sendRequestedMedia(): "
2445 <<"Sending files to client"<<std::endl;
2449 // Put 5kB in one bunch (this is not accurate)
2450 u32 bytes_per_bunch = 5000;
2452 std::vector< std::list<SendableMedia> > file_bunches;
2453 file_bunches.push_back(std::list<SendableMedia>());
2455 u32 file_size_bunch_total = 0;
2457 for(std::list<std::string>::const_iterator i = tosend.begin();
2458 i != tosend.end(); ++i)
2460 const std::string &name = *i;
2462 if(m_media.find(name) == m_media.end()) {
2463 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2464 <<"unknown file \""<<(name)<<"\""<<std::endl;
2468 //TODO get path + name
2469 std::string tpath = m_media[name].path;
2472 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2473 if(fis.good() == false){
2474 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2475 <<tpath<<"\" for reading"<<std::endl;
2478 std::ostringstream tmp_os(std::ios_base::binary);
2482 fis.read(buf, 1024);
2483 std::streamsize len = fis.gcount();
2484 tmp_os.write(buf, len);
2485 file_size_bunch_total += len;
2494 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2495 <<name<<"\""<<std::endl;
2498 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2499 <<tname<<"\""<<std::endl;*/
2501 file_bunches[file_bunches.size()-1].push_back(
2502 SendableMedia(name, tpath, tmp_os.str()));
2504 // Start next bunch if got enough data
2505 if(file_size_bunch_total >= bytes_per_bunch) {
2506 file_bunches.push_back(std::list<SendableMedia>());
2507 file_size_bunch_total = 0;
2512 /* Create and send packets */
2514 u16 num_bunches = file_bunches.size();
2515 for(u16 i = 0; i < num_bunches; i++) {
2518 u16 total number of texture bunches
2519 u16 index of this bunch
2520 u32 number of files in this bunch
2529 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2530 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2532 for(std::list<SendableMedia>::iterator
2533 j = file_bunches[i].begin();
2534 j != file_bunches[i].end(); ++j) {
2536 pkt->putLongString(j->data);
2539 verbosestream << "Server::sendRequestedMedia(): bunch "
2540 << i << "/" << num_bunches
2541 << " files=" << file_bunches[i].size()
2542 << " size=" << pkt->getSize() << std::endl;
2547 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2549 if(m_detached_inventories.count(name) == 0) {
2550 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2553 Inventory *inv = m_detached_inventories[name];
2554 std::ostringstream os(std::ios_base::binary);
2556 os << serializeString(name);
2560 std::string s = os.str();
2562 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2563 pkt->putRawString(s.c_str(), s.size());
2565 if (peer_id != PEER_ID_INEXISTENT) {
2569 m_clients.sendToAll(0, pkt, true);
2573 void Server::sendDetachedInventories(u16 peer_id)
2575 DSTACK(__FUNCTION_NAME);
2577 for(std::map<std::string, Inventory*>::iterator
2578 i = m_detached_inventories.begin();
2579 i != m_detached_inventories.end(); i++) {
2580 const std::string &name = i->first;
2581 //Inventory *inv = i->second;
2582 sendDetachedInventory(name, peer_id);
2590 void Server::DiePlayer(u16 peer_id)
2592 DSTACK(__FUNCTION_NAME);
2594 PlayerSAO *playersao = getPlayerSAO(peer_id);
2597 infostream<<"Server::DiePlayer(): Player "
2598 <<playersao->getPlayer()->getName()
2599 <<" dies"<<std::endl;
2601 playersao->setHP(0);
2603 // Trigger scripted stuff
2604 m_script->on_dieplayer(playersao);
2606 SendPlayerHP(peer_id);
2607 SendDeathscreen(peer_id, false, v3f(0,0,0));
2610 void Server::RespawnPlayer(u16 peer_id)
2612 DSTACK(__FUNCTION_NAME);
2614 PlayerSAO *playersao = getPlayerSAO(peer_id);
2617 infostream<<"Server::RespawnPlayer(): Player "
2618 <<playersao->getPlayer()->getName()
2619 <<" respawns"<<std::endl;
2621 playersao->setHP(PLAYER_MAX_HP);
2622 playersao->setBreath(PLAYER_MAX_BREATH);
2624 bool repositioned = m_script->on_respawnplayer(playersao);
2626 v3f pos = findSpawnPos(m_env->getServerMap());
2627 playersao->setPos(pos);
2631 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2633 DSTACK(__FUNCTION_NAME);
2635 SendAccessDenied(peer_id, reason);
2636 m_clients.event(peer_id, CSE_SetDenied);
2637 m_con.DisconnectPeer(peer_id);
2640 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2642 DSTACK(__FUNCTION_NAME);
2643 std::wstring message;
2646 Clear references to playing sounds
2648 for(std::map<s32, ServerPlayingSound>::iterator
2649 i = m_playing_sounds.begin();
2650 i != m_playing_sounds.end();)
2652 ServerPlayingSound &psound = i->second;
2653 psound.clients.erase(peer_id);
2654 if(psound.clients.empty())
2655 m_playing_sounds.erase(i++);
2660 Player *player = m_env->getPlayer(peer_id);
2662 // Collect information about leaving in chat
2664 if(player != NULL && reason != CDR_DENY)
2666 std::wstring name = narrow_to_wide(player->getName());
2669 message += L" left the game.";
2670 if(reason == CDR_TIMEOUT)
2671 message += L" (timed out)";
2675 /* Run scripts and remove from environment */
2679 PlayerSAO *playersao = player->getPlayerSAO();
2682 m_script->on_leaveplayer(playersao);
2684 playersao->disconnected();
2692 if(player != NULL && reason != CDR_DENY)
2694 std::ostringstream os(std::ios_base::binary);
2695 std::list<u16> clients = m_clients.getClientIDs();
2697 for(std::list<u16>::iterator
2698 i = clients.begin();
2699 i != clients.end(); ++i)
2702 Player *player = m_env->getPlayer(*i);
2705 // Get name of player
2706 os<<player->getName()<<" ";
2709 actionstream<<player->getName()<<" "
2710 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2711 <<" List of players: "<<os.str()<<std::endl;
2715 JMutexAutoLock env_lock(m_env_mutex);
2716 m_clients.DeleteClient(peer_id);
2720 // Send leave chat message to all remaining clients
2721 if(message.length() != 0)
2722 SendChatMessage(PEER_ID_INEXISTENT,message);
2725 void Server::UpdateCrafting(u16 peer_id)
2727 DSTACK(__FUNCTION_NAME);
2729 Player* player = m_env->getPlayer(peer_id);
2732 // Get a preview for crafting
2734 InventoryLocation loc;
2735 loc.setPlayer(player->getName());
2736 getCraftingResult(&player->inventory, preview, false, this);
2737 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2739 // Put the new preview in
2740 InventoryList *plist = player->inventory.getList("craftpreview");
2742 assert(plist->getSize() >= 1);
2743 plist->changeItem(0, preview);
2746 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2748 RemoteClient *client = getClientNoEx(peer_id,state_min);
2750 throw ClientNotFoundException("Client not found");
2754 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2756 return m_clients.getClientNoEx(peer_id, state_min);
2759 std::string Server::getPlayerName(u16 peer_id)
2761 Player *player = m_env->getPlayer(peer_id);
2763 return "[id="+itos(peer_id)+"]";
2764 return player->getName();
2767 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2769 Player *player = m_env->getPlayer(peer_id);
2772 return player->getPlayerSAO();
2775 std::wstring Server::getStatusString()
2777 std::wostringstream os(std::ios_base::binary);
2780 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2782 os<<L", uptime="<<m_uptime.get();
2784 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2785 // Information about clients
2788 std::list<u16> clients = m_clients.getClientIDs();
2789 for(std::list<u16>::iterator i = clients.begin();
2790 i != clients.end(); ++i)
2793 Player *player = m_env->getPlayer(*i);
2794 // Get name of player
2795 std::wstring name = L"unknown";
2797 name = narrow_to_wide(player->getName());
2798 // Add name to information string
2806 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2807 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2808 if(g_settings->get("motd") != "")
2809 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2813 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2815 std::set<std::string> privs;
2816 m_script->getAuth(name, NULL, &privs);
2820 bool Server::checkPriv(const std::string &name, const std::string &priv)
2822 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2823 return (privs.count(priv) != 0);
2826 void Server::reportPrivsModified(const std::string &name)
2829 std::list<u16> clients = m_clients.getClientIDs();
2830 for(std::list<u16>::iterator
2831 i = clients.begin();
2832 i != clients.end(); ++i){
2833 Player *player = m_env->getPlayer(*i);
2834 reportPrivsModified(player->getName());
2837 Player *player = m_env->getPlayer(name.c_str());
2840 SendPlayerPrivileges(player->peer_id);
2841 PlayerSAO *sao = player->getPlayerSAO();
2844 sao->updatePrivileges(
2845 getPlayerEffectivePrivs(name),
2850 void Server::reportInventoryFormspecModified(const std::string &name)
2852 Player *player = m_env->getPlayer(name.c_str());
2855 SendPlayerInventoryFormspec(player->peer_id);
2858 void Server::setIpBanned(const std::string &ip, const std::string &name)
2860 m_banmanager->add(ip, name);
2863 void Server::unsetIpBanned(const std::string &ip_or_name)
2865 m_banmanager->remove(ip_or_name);
2868 std::string Server::getBanDescription(const std::string &ip_or_name)
2870 return m_banmanager->getBanDescription(ip_or_name);
2873 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2875 Player *player = m_env->getPlayer(name);
2879 if (player->peer_id == PEER_ID_INEXISTENT)
2882 SendChatMessage(player->peer_id, msg);
2885 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2887 Player *player = m_env->getPlayer(playername);
2891 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2895 SendShowFormspecMessage(player->peer_id, formspec, formname);
2899 u32 Server::hudAdd(Player *player, HudElement *form) {
2903 u32 id = player->addHud(form);
2905 SendHUDAdd(player->peer_id, id, form);
2910 bool Server::hudRemove(Player *player, u32 id) {
2914 HudElement* todel = player->removeHud(id);
2921 SendHUDRemove(player->peer_id, id);
2925 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2929 SendHUDChange(player->peer_id, id, stat, data);
2933 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2937 SendHUDSetFlags(player->peer_id, flags, mask);
2938 player->hud_flags = flags;
2940 PlayerSAO* playersao = player->getPlayerSAO();
2942 if (playersao == NULL)
2945 m_script->player_event(playersao, "hud_changed");
2949 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2952 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2955 std::ostringstream os(std::ios::binary);
2956 writeS32(os, hotbar_itemcount);
2957 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2961 void Server::hudSetHotbarImage(Player *player, std::string name) {
2965 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2968 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2972 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2975 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2980 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2984 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2989 SendEyeOffset(player->peer_id, first, third);
2993 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2994 const std::string &type, const std::vector<std::string> ¶ms)
2999 SendSetSky(player->peer_id, bgcolor, type, params);
3003 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3009 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3013 void Server::notifyPlayers(const std::wstring &msg)
3015 SendChatMessage(PEER_ID_INEXISTENT,msg);
3018 void Server::spawnParticle(const char *playername, v3f pos,
3019 v3f velocity, v3f acceleration,
3020 float expirationtime, float size, bool
3021 collisiondetection, bool vertical, std::string texture)
3023 Player *player = m_env->getPlayer(playername);
3026 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3027 expirationtime, size, collisiondetection, vertical, texture);
3030 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3031 float expirationtime, float size,
3032 bool collisiondetection, bool vertical, std::string texture)
3034 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3035 expirationtime, size, collisiondetection, vertical, texture);
3038 u32 Server::addParticleSpawner(const char *playername,
3039 u16 amount, float spawntime,
3040 v3f minpos, v3f maxpos,
3041 v3f minvel, v3f maxvel,
3042 v3f minacc, v3f maxacc,
3043 float minexptime, float maxexptime,
3044 float minsize, float maxsize,
3045 bool collisiondetection, bool vertical, std::string texture)
3047 Player *player = m_env->getPlayer(playername);
3052 for(;;) // look for unused particlespawner id
3055 if (std::find(m_particlespawner_ids.begin(),
3056 m_particlespawner_ids.end(), id)
3057 == m_particlespawner_ids.end())
3059 m_particlespawner_ids.push_back(id);
3064 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3065 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3066 minexptime, maxexptime, minsize, maxsize,
3067 collisiondetection, vertical, texture, id);
3072 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3073 v3f minpos, v3f maxpos,
3074 v3f minvel, v3f maxvel,
3075 v3f minacc, v3f maxacc,
3076 float minexptime, float maxexptime,
3077 float minsize, float maxsize,
3078 bool collisiondetection, bool vertical, std::string texture)
3081 for(;;) // look for unused particlespawner id
3084 if (std::find(m_particlespawner_ids.begin(),
3085 m_particlespawner_ids.end(), id)
3086 == m_particlespawner_ids.end())
3088 m_particlespawner_ids.push_back(id);
3093 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3094 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3095 minexptime, maxexptime, minsize, maxsize,
3096 collisiondetection, vertical, texture, id);
3101 void Server::deleteParticleSpawner(const char *playername, u32 id)
3103 Player *player = m_env->getPlayer(playername);
3107 m_particlespawner_ids.erase(
3108 std::remove(m_particlespawner_ids.begin(),
3109 m_particlespawner_ids.end(), id),
3110 m_particlespawner_ids.end());
3111 SendDeleteParticleSpawner(player->peer_id, id);
3114 void Server::deleteParticleSpawnerAll(u32 id)
3116 m_particlespawner_ids.erase(
3117 std::remove(m_particlespawner_ids.begin(),
3118 m_particlespawner_ids.end(), id),
3119 m_particlespawner_ids.end());
3120 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3123 Inventory* Server::createDetachedInventory(const std::string &name)
3125 if(m_detached_inventories.count(name) > 0){
3126 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3127 delete m_detached_inventories[name];
3129 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3131 Inventory *inv = new Inventory(m_itemdef);
3133 m_detached_inventories[name] = inv;
3134 //TODO find a better way to do this
3135 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3142 BoolScopeSet(bool *dst, bool val):
3145 m_orig_state = *m_dst;
3150 *m_dst = m_orig_state;
3157 // actions: time-reversed list
3158 // Return value: success/failure
3159 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3160 std::list<std::string> *log)
3162 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3163 ServerMap *map = (ServerMap*)(&m_env->getMap());
3165 // Fail if no actions to handle
3166 if(actions.empty()){
3167 log->push_back("Nothing to do.");
3174 for(std::list<RollbackAction>::const_iterator
3175 i = actions.begin();
3176 i != actions.end(); i++)
3178 const RollbackAction &action = *i;
3180 bool success = action.applyRevert(map, this, this);
3183 std::ostringstream os;
3184 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3185 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3187 log->push_back(os.str());
3189 std::ostringstream os;
3190 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3191 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3193 log->push_back(os.str());
3197 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3198 <<" failed"<<std::endl;
3200 // Call it done if less than half failed
3201 return num_failed <= num_tried/2;
3204 // IGameDef interface
3206 IItemDefManager* Server::getItemDefManager()
3210 INodeDefManager* Server::getNodeDefManager()
3214 ICraftDefManager* Server::getCraftDefManager()
3218 ITextureSource* Server::getTextureSource()
3222 IShaderSource* Server::getShaderSource()
3226 scene::ISceneManager* Server::getSceneManager()
3231 u16 Server::allocateUnknownNodeId(const std::string &name)
3233 return m_nodedef->allocateDummy(name);
3235 ISoundManager* Server::getSoundManager()
3237 return &dummySoundManager;
3239 MtEventManager* Server::getEventManager()
3244 IWritableItemDefManager* Server::getWritableItemDefManager()
3248 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3252 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3257 const ModSpec* Server::getModSpec(const std::string &modname)
3259 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3260 i != m_mods.end(); i++){
3261 const ModSpec &mod = *i;
3262 if(mod.name == modname)
3267 void Server::getModNames(std::list<std::string> &modlist)
3269 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3271 modlist.push_back(i->name);
3274 std::string Server::getBuiltinLuaPath()
3276 return porting::path_share + DIR_DELIM + "builtin";
3279 v3f findSpawnPos(ServerMap &map)
3281 //return v3f(50,50,50)*BS;
3286 nodepos = v2s16(0,0);
3291 s16 water_level = map.getWaterLevel();
3293 // Try to find a good place a few times
3294 for(s32 i=0; i<1000; i++)
3297 // We're going to try to throw the player to this position
3298 v2s16 nodepos2d = v2s16(
3299 -range + (myrand() % (range * 2)),
3300 -range + (myrand() % (range * 2)));
3302 // Get ground height at point
3303 s16 groundheight = map.findGroundLevel(nodepos2d);
3304 if (groundheight <= water_level) // Don't go underwater
3306 if (groundheight > water_level + 6) // Don't go to high places
3309 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3310 bool is_good = false;
3312 for (s32 i = 0; i < 10; i++) {
3313 v3s16 blockpos = getNodeBlockPos(nodepos);
3314 map.emergeBlock(blockpos, true);
3315 content_t c = map.getNodeNoEx(nodepos).getContent();
3316 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3318 if (air_count >= 2){
3326 // Found a good place
3327 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3333 return intToFloat(nodepos, BS);
3336 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3338 bool newplayer = false;
3341 Try to get an existing player
3343 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3345 // If player is already connected, cancel
3346 if(player != NULL && player->peer_id != 0)
3348 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3353 If player with the wanted peer_id already exists, cancel.
3355 if(m_env->getPlayer(peer_id) != NULL)
3357 infostream<<"emergePlayer(): Player with wrong name but same"
3358 " peer_id already exists"<<std::endl;
3362 // Load player if it isn't already loaded
3364 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3367 // Create player if it doesn't exist
3370 player = new RemotePlayer(this, name);
3371 // Set player position
3372 infostream<<"Server: Finding spawn place for player \""
3373 <<name<<"\""<<std::endl;
3374 v3f pos = findSpawnPos(m_env->getServerMap());
3375 player->setPosition(pos);
3377 // Make sure the player is saved
3378 player->setModified(true);
3380 // Add player to environment
3381 m_env->addPlayer(player);
3384 // Create a new player active object
3385 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3386 getPlayerEffectivePrivs(player->getName()),
3389 /* Clean up old HUD elements from previous sessions */
3392 /* Add object to environment */
3393 m_env->addActiveObject(playersao);
3397 m_script->on_newplayer(playersao);
3403 void dedicated_server_loop(Server &server, bool &kill)
3405 DSTACK(__FUNCTION_NAME);
3407 verbosestream<<"dedicated_server_loop()"<<std::endl;
3409 IntervalLimiter m_profiler_interval;
3413 float steplen = g_settings->getFloat("dedicated_server_step");
3414 // This is kind of a hack but can be done like this
3415 // because server.step() is very light
3417 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3418 sleep_ms((int)(steplen*1000.0));
3420 server.step(steplen);
3422 if(server.getShutdownRequested() || kill)
3424 infostream<<"Dedicated server quitting"<<std::endl;
3426 if(g_settings->getBool("server_announce"))
3427 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3435 float profiler_print_interval =
3436 g_settings->getFloat("profiler_print_interval");
3437 if(profiler_print_interval != 0)
3439 if(m_profiler_interval.step(steplen, profiler_print_interval))
3441 infostream<<"Profiler:"<<std::endl;
3442 g_profiler->print(infostream);
3443 g_profiler->clear();