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 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
762 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
765 verbosestream << "Server: Sent object remove/add: "
766 << removed_objects.size() << " removed, "
767 << added_objects.size() << " added, "
768 << "packet size is " << pkt->getSize() << std::endl;
779 JMutexAutoLock envlock(m_env_mutex);
780 ScopeProfiler sp(g_profiler, "Server: sending object messages");
783 // Value = data sent by object
784 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
786 // Get active object messages from environment
788 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
792 std::vector<ActiveObjectMessage>* message_list = NULL;
793 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
794 n = buffered_messages.find(aom.id);
795 if (n == buffered_messages.end()) {
796 message_list = new std::vector<ActiveObjectMessage>;
797 buffered_messages[aom.id] = message_list;
800 message_list = n->second;
802 message_list->push_back(aom);
806 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
807 // Route data to every client
808 for (std::map<u16, RemoteClient*>::iterator
810 i != clients.end(); ++i) {
811 RemoteClient *client = i->second;
812 std::string reliable_data;
813 std::string unreliable_data;
814 // Go through all objects in message buffer
815 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
816 j = buffered_messages.begin();
817 j != buffered_messages.end(); ++j) {
818 // If object is not known by client, skip it
820 if (client->m_known_objects.find(id) == client->m_known_objects.end())
823 // Get message list of object
824 std::vector<ActiveObjectMessage>* list = j->second;
825 // Go through every message
826 for (std::vector<ActiveObjectMessage>::iterator
827 k = list->begin(); k != list->end(); ++k) {
828 // Compose the full new data with header
829 ActiveObjectMessage aom = *k;
830 std::string new_data;
833 writeU16((u8*)&buf[0], aom.id);
834 new_data.append(buf, 2);
836 new_data += serializeString(aom.datastring);
837 // Add data to buffer
839 reliable_data += new_data;
841 unreliable_data += new_data;
845 reliable_data and unreliable_data are now ready.
848 if(reliable_data.size() > 0) {
849 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
852 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
856 if(unreliable_data.size() > 0) {
857 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
860 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
866 // Clear buffered_messages
867 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
868 i = buffered_messages.begin();
869 i != buffered_messages.end(); ++i) {
875 Send queued-for-sending map edit events.
878 // We will be accessing the environment
879 JMutexAutoLock lock(m_env_mutex);
881 // Don't send too many at a time
884 // Single change sending is disabled if queue size is not small
885 bool disable_single_change_sending = false;
886 if(m_unsent_map_edit_queue.size() >= 4)
887 disable_single_change_sending = true;
889 int event_count = m_unsent_map_edit_queue.size();
891 // We'll log the amount of each
894 while(m_unsent_map_edit_queue.size() != 0)
896 MapEditEvent* event = m_unsent_map_edit_queue.front();
897 m_unsent_map_edit_queue.pop();
899 // Players far away from the change are stored here.
900 // Instead of sending the changes, MapBlocks are set not sent
902 std::vector<u16> far_players;
904 switch (event->type) {
907 prof.add("MEET_ADDNODE", 1);
908 sendAddNode(event->p, event->n, event->already_known_by_peer,
909 &far_players, disable_single_change_sending ? 5 : 30,
910 event->type == MEET_ADDNODE);
912 case MEET_REMOVENODE:
913 prof.add("MEET_REMOVENODE", 1);
914 sendRemoveNode(event->p, event->already_known_by_peer,
915 &far_players, disable_single_change_sending ? 5 : 30);
917 case MEET_BLOCK_NODE_METADATA_CHANGED:
918 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
919 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
920 setBlockNotSent(event->p);
923 infostream << "Server: MEET_OTHER" << std::endl;
924 prof.add("MEET_OTHER", 1);
925 for(std::set<v3s16>::iterator
926 i = event->modified_blocks.begin();
927 i != event->modified_blocks.end(); ++i) {
932 prof.add("unknown", 1);
933 infostream << "WARNING: Server: Unknown MapEditEvent "
934 << ((u32)event->type) << std::endl;
939 Set blocks not sent to far players
941 if(!far_players.empty()) {
942 // Convert list format to that wanted by SetBlocksNotSent
943 std::map<v3s16, MapBlock*> modified_blocks2;
944 for(std::set<v3s16>::iterator
945 i = event->modified_blocks.begin();
946 i != event->modified_blocks.end(); ++i) {
947 modified_blocks2[*i] =
948 m_env->getMap().getBlockNoCreateNoEx(*i);
951 // Set blocks not sent
952 for(std::vector<u16>::iterator
953 i = far_players.begin();
954 i != far_players.end(); ++i) {
955 if(RemoteClient *client = getClient(*i))
956 client->SetBlocksNotSent(modified_blocks2);
962 /*// Don't send too many at a time
964 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
968 if(event_count >= 5){
969 infostream<<"Server: MapEditEvents:"<<std::endl;
970 prof.print(infostream);
971 } else if(event_count != 0){
972 verbosestream<<"Server: MapEditEvents:"<<std::endl;
973 prof.print(verbosestream);
979 Trigger emergethread (it somehow gets to a non-triggered but
980 bysy state sometimes)
983 float &counter = m_emergethread_trigger_timer;
989 m_emerge->startThreads();
993 // Save map, players and auth stuff
995 float &counter = m_savemap_timer;
997 if(counter >= g_settings->getFloat("server_map_save_interval"))
1000 JMutexAutoLock lock(m_env_mutex);
1002 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1005 if (m_banmanager->isModified()) {
1006 m_banmanager->save();
1009 // Save changed parts of map
1010 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1013 m_env->saveLoadedPlayers();
1015 // Save environment metadata
1021 void Server::Receive()
1023 DSTACK(__FUNCTION_NAME);
1024 SharedBuffer<u8> data;
1028 datasize = m_con.Receive(peer_id,data);
1029 ProcessData(*data, datasize, peer_id);
1031 catch(con::InvalidIncomingDataException &e) {
1032 infostream<<"Server::Receive(): "
1033 "InvalidIncomingDataException: what()="
1034 <<e.what()<<std::endl;
1036 catch(SerializationError &e) {
1037 infostream<<"Server::Receive(): "
1038 "SerializationError: what()="
1039 <<e.what()<<std::endl;
1041 catch(ClientStateError &e) {
1042 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1043 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1044 L"Try reconnecting or updating your client");
1046 catch(con::PeerNotFoundException &e) {
1051 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1053 std::string playername = "";
1054 PlayerSAO *playersao = NULL;
1057 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1058 if (client != NULL) {
1059 playername = client->getName();
1060 playersao = emergePlayer(playername.c_str(), peer_id);
1062 } catch (std::exception &e) {
1068 RemotePlayer *player =
1069 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1071 // If failed, cancel
1072 if((playersao == NULL) || (player == NULL)) {
1073 if(player && player->peer_id != 0) {
1074 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1075 <<" (player allocated to an another client)"<<std::endl;
1076 DenyAccess(peer_id, L"Another client is connected with this "
1077 L"name. If your client closed unexpectedly, try again in "
1080 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1082 DenyAccess(peer_id, L"Could not allocate player.");
1088 Send complete position information
1090 SendMovePlayer(peer_id);
1093 SendPlayerPrivileges(peer_id);
1095 // Send inventory formspec
1096 SendPlayerInventoryFormspec(peer_id);
1099 SendInventory(playersao);
1102 if(g_settings->getBool("enable_damage"))
1103 SendPlayerHP(peer_id);
1106 SendPlayerBreath(peer_id);
1108 // Show death screen if necessary
1110 SendDeathscreen(peer_id, false, v3f(0,0,0));
1112 // Note things in chat if not in simple singleplayer mode
1113 if(!m_simple_singleplayer_mode) {
1114 // Send information about server to player in chat
1115 SendChatMessage(peer_id, getStatusString());
1117 // Send information about joining in chat
1119 std::wstring name = L"unknown";
1120 Player *player = m_env->getPlayer(peer_id);
1122 name = narrow_to_wide(player->getName());
1124 std::wstring message;
1127 message += L" joined the game.";
1128 SendChatMessage(PEER_ID_INEXISTENT,message);
1131 Address addr = getPeerAddress(player->peer_id);
1132 std::string ip_str = addr.serializeString();
1133 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1138 std::vector<std::string> names = m_clients.getPlayerNames();
1140 actionstream<<player->getName() <<" joins game. List of players: ";
1142 for (std::vector<std::string>::iterator i = names.begin();
1143 i != names.end(); i++) {
1144 actionstream << *i << " ";
1147 actionstream << player->getName() <<std::endl;
1152 inline void Server::handleCommand(NetworkPacket* pkt)
1154 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1155 (this->*opHandle.handler)(pkt);
1158 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1160 DSTACK(__FUNCTION_NAME);
1161 // Environment is locked first.
1162 JMutexAutoLock envlock(m_env_mutex);
1164 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1167 Address address = getPeerAddress(peer_id);
1168 std::string addr_s = address.serializeString();
1170 if(m_banmanager->isIpBanned(addr_s)) {
1171 std::string ban_name = m_banmanager->getBanName(addr_s);
1172 infostream << "Server: A banned client tried to connect from "
1173 << addr_s << "; banned name was "
1174 << ban_name << std::endl;
1175 // This actually doesn't seem to transfer to the client
1176 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1177 + narrow_to_wide(ban_name));
1181 catch(con::PeerNotFoundException &e) {
1183 * no peer for this packet found
1184 * most common reason is peer timeout, e.g. peer didn't
1185 * respond for some time, your server was overloaded or
1188 infostream << "Server::ProcessData(): Cancelling: peer "
1189 << peer_id << " not found" << std::endl;
1197 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1199 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1201 // Command must be handled into ToServerCommandHandler
1202 if (command >= TOSERVER_NUM_MSG_TYPES) {
1203 infostream << "Server: Ignoring unknown command "
1204 << command << std::endl;
1207 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1213 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1215 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1216 errorstream << "Server::ProcessData(): Cancelling: Peer"
1217 " serialization format invalid or not initialized."
1218 " Skipping incoming command=" << command << std::endl;
1224 /* Handle commands related to client startup */
1225 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1231 if (m_clients.getClientState(peer_id) < CS_Active) {
1232 if (command == TOSERVER_PLAYERPOS) return;
1234 errorstream << "Got packet command: " << command << " for peer id "
1235 << peer_id << " but client isn't active yet. Dropping packet "
1246 catch(SendFailedException &e) {
1247 errorstream << "Server::ProcessData(): SendFailedException: "
1248 << "what=" << e.what()
1253 void Server::setTimeOfDay(u32 time)
1255 m_env->setTimeOfDay(time);
1256 m_time_of_day_send_timer = 0;
1259 void Server::onMapEditEvent(MapEditEvent *event)
1261 if(m_ignore_map_edit_events)
1263 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1265 MapEditEvent *e = event->clone();
1266 m_unsent_map_edit_queue.push(e);
1269 Inventory* Server::getInventory(const InventoryLocation &loc)
1272 case InventoryLocation::UNDEFINED:
1273 case InventoryLocation::CURRENT_PLAYER:
1275 case InventoryLocation::PLAYER:
1277 Player *player = m_env->getPlayer(loc.name.c_str());
1280 PlayerSAO *playersao = player->getPlayerSAO();
1283 return playersao->getInventory();
1286 case InventoryLocation::NODEMETA:
1288 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1291 return meta->getInventory();
1294 case InventoryLocation::DETACHED:
1296 if(m_detached_inventories.count(loc.name) == 0)
1298 return m_detached_inventories[loc.name];
1302 sanity_check(false); // abort
1307 void Server::setInventoryModified(const InventoryLocation &loc)
1310 case InventoryLocation::UNDEFINED:
1312 case InventoryLocation::PLAYER:
1314 Player *player = m_env->getPlayer(loc.name.c_str());
1317 PlayerSAO *playersao = player->getPlayerSAO();
1321 SendInventory(playersao);
1324 case InventoryLocation::NODEMETA:
1326 v3s16 blockpos = getNodeBlockPos(loc.p);
1328 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1330 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1332 setBlockNotSent(blockpos);
1335 case InventoryLocation::DETACHED:
1337 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1341 sanity_check(false); // abort
1346 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1348 std::vector<u16> clients = m_clients.getClientIDs();
1350 // Set the modified blocks unsent for all the clients
1351 for (std::vector<u16>::iterator i = clients.begin();
1352 i != clients.end(); ++i) {
1353 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1354 client->SetBlocksNotSent(block);
1359 void Server::peerAdded(con::Peer *peer)
1361 DSTACK(__FUNCTION_NAME);
1362 verbosestream<<"Server::peerAdded(): peer->id="
1363 <<peer->id<<std::endl;
1366 c.type = con::PEER_ADDED;
1367 c.peer_id = peer->id;
1369 m_peer_change_queue.push(c);
1372 void Server::deletingPeer(con::Peer *peer, bool timeout)
1374 DSTACK(__FUNCTION_NAME);
1375 verbosestream<<"Server::deletingPeer(): peer->id="
1376 <<peer->id<<", timeout="<<timeout<<std::endl;
1378 m_clients.event(peer->id, CSE_Disconnect);
1380 c.type = con::PEER_REMOVED;
1381 c.peer_id = peer->id;
1382 c.timeout = timeout;
1383 m_peer_change_queue.push(c);
1386 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1388 *retval = m_con.getPeerStat(peer_id,type);
1389 if (*retval == -1) return false;
1393 bool Server::getClientInfo(
1402 std::string* vers_string
1405 *state = m_clients.getClientState(peer_id);
1407 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1409 if (client == NULL) {
1414 *uptime = client->uptime();
1415 *ser_vers = client->serialization_version;
1416 *prot_vers = client->net_proto_version;
1418 *major = client->getMajor();
1419 *minor = client->getMinor();
1420 *patch = client->getPatch();
1421 *vers_string = client->getPatch();
1428 void Server::handlePeerChanges()
1430 while(m_peer_change_queue.size() > 0)
1432 con::PeerChange c = m_peer_change_queue.front();
1433 m_peer_change_queue.pop();
1435 verbosestream<<"Server: Handling peer change: "
1436 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1441 case con::PEER_ADDED:
1442 m_clients.CreateClient(c.peer_id);
1445 case con::PEER_REMOVED:
1446 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1450 FATAL_ERROR("Invalid peer change event received!");
1456 void Server::Send(NetworkPacket* pkt)
1458 m_clients.send(pkt->getPeerId(),
1459 clientCommandFactoryTable[pkt->getCommand()].channel,
1461 clientCommandFactoryTable[pkt->getCommand()].reliable);
1464 void Server::SendMovement(u16 peer_id)
1466 DSTACK(__FUNCTION_NAME);
1467 std::ostringstream os(std::ios_base::binary);
1469 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1471 *pkt << g_settings->getFloat("movement_acceleration_default");
1472 *pkt << g_settings->getFloat("movement_acceleration_air");
1473 *pkt << g_settings->getFloat("movement_acceleration_fast");
1474 *pkt << g_settings->getFloat("movement_speed_walk");
1475 *pkt << g_settings->getFloat("movement_speed_crouch");
1476 *pkt << g_settings->getFloat("movement_speed_fast");
1477 *pkt << g_settings->getFloat("movement_speed_climb");
1478 *pkt << g_settings->getFloat("movement_speed_jump");
1479 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1480 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1481 *pkt << g_settings->getFloat("movement_liquid_sink");
1482 *pkt << g_settings->getFloat("movement_gravity");
1487 void Server::SendHP(u16 peer_id, u8 hp)
1489 DSTACK(__FUNCTION_NAME);
1491 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1496 void Server::SendBreath(u16 peer_id, u16 breath)
1498 DSTACK(__FUNCTION_NAME);
1500 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1501 *pkt << (u16) breath;
1505 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1507 DSTACK(__FUNCTION_NAME);
1509 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1514 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1515 v3f camera_point_target)
1517 DSTACK(__FUNCTION_NAME);
1519 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1520 *pkt << set_camera_point_target << camera_point_target;
1524 void Server::SendItemDef(u16 peer_id,
1525 IItemDefManager *itemdef, u16 protocol_version)
1527 DSTACK(__FUNCTION_NAME);
1529 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1533 u32 length of the next item
1534 zlib-compressed serialized ItemDefManager
1536 std::ostringstream tmp_os(std::ios::binary);
1537 itemdef->serialize(tmp_os, protocol_version);
1538 std::ostringstream tmp_os2(std::ios::binary);
1539 compressZlib(tmp_os.str(), tmp_os2);
1540 pkt->putLongString(tmp_os2.str());
1543 verbosestream << "Server: Sending item definitions to id(" << peer_id
1544 << "): size=" << pkt->getSize() << std::endl;
1549 void Server::SendNodeDef(u16 peer_id,
1550 INodeDefManager *nodedef, u16 protocol_version)
1552 DSTACK(__FUNCTION_NAME);
1554 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1558 u32 length of the next item
1559 zlib-compressed serialized NodeDefManager
1561 std::ostringstream tmp_os(std::ios::binary);
1562 nodedef->serialize(tmp_os, protocol_version);
1563 std::ostringstream tmp_os2(std::ios::binary);
1564 compressZlib(tmp_os.str(), tmp_os2);
1566 pkt->putLongString(tmp_os2.str());
1569 verbosestream << "Server: Sending node definitions to id(" << peer_id
1570 << "): size=" << pkt->getSize() << std::endl;
1576 Non-static send methods
1579 void Server::SendInventory(PlayerSAO* playerSAO)
1581 DSTACK(__FUNCTION_NAME);
1583 UpdateCrafting(playerSAO->getPlayer());
1589 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1590 playerSAO->getPeerID());
1592 std::ostringstream os;
1593 playerSAO->getInventory()->serialize(os);
1595 std::string s = os.str();
1597 pkt->putRawString(s.c_str(), s.size());
1601 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1603 DSTACK(__FUNCTION_NAME);
1605 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1608 if (peer_id != PEER_ID_INEXISTENT) {
1612 m_clients.sendToAll(0,pkt,true);
1616 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1617 const std::string &formname)
1619 DSTACK(__FUNCTION_NAME);
1621 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1623 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1629 // Spawns a particle on peer with peer_id
1630 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1631 float expirationtime, float size, bool collisiondetection,
1632 bool vertical, std::string texture)
1634 DSTACK(__FUNCTION_NAME);
1636 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1638 *pkt << pos << velocity << acceleration << expirationtime
1639 << size << collisiondetection;
1640 pkt->putLongString(texture);
1643 if (peer_id != PEER_ID_INEXISTENT) {
1647 m_clients.sendToAll(0,pkt,true);
1651 // Adds a ParticleSpawner on peer with peer_id
1652 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1653 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1654 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1656 DSTACK(__FUNCTION_NAME);
1658 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1660 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1661 << minacc << maxacc << minexptime << maxexptime << minsize
1662 << maxsize << collisiondetection;
1664 pkt->putLongString(texture);
1666 *pkt << id << vertical;
1668 if (peer_id != PEER_ID_INEXISTENT) {
1672 m_clients.sendToAll(0, pkt, true);
1676 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1678 DSTACK(__FUNCTION_NAME);
1680 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1682 // Ugly error in this packet
1685 if (peer_id != PEER_ID_INEXISTENT) {
1689 m_clients.sendToAll(0, pkt, true);
1694 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1696 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1698 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1699 << form->text << form->number << form->item << form->dir
1700 << form->align << form->offset << form->world_pos << form->size;
1705 void Server::SendHUDRemove(u16 peer_id, u32 id)
1707 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1712 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1714 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1715 *pkt << id << (u8) stat;
1719 case HUD_STAT_SCALE:
1720 case HUD_STAT_ALIGN:
1721 case HUD_STAT_OFFSET:
1722 *pkt << *(v2f *) value;
1726 *pkt << *(std::string *) value;
1728 case HUD_STAT_WORLD_POS:
1729 *pkt << *(v3f *) value;
1732 *pkt << *(v2s32 *) value;
1734 case HUD_STAT_NUMBER:
1738 *pkt << *(u32 *) value;
1745 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1747 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1749 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1751 *pkt << flags << mask;
1756 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1758 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1759 *pkt << param << value;
1763 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1764 const std::string &type, const std::vector<std::string> ¶ms)
1766 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1767 *pkt << bgcolor << type << (u16) params.size();
1769 for(size_t i=0; i<params.size(); i++)
1775 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1778 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1781 *pkt << do_override << (u16) (ratio * 65535);
1786 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1788 DSTACK(__FUNCTION_NAME);
1790 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1791 *pkt << time << time_speed;
1793 if (peer_id == PEER_ID_INEXISTENT) {
1794 m_clients.sendToAll(0, pkt, true);
1801 void Server::SendPlayerHP(u16 peer_id)
1803 DSTACK(__FUNCTION_NAME);
1804 PlayerSAO *playersao = getPlayerSAO(peer_id);
1806 SendHP(peer_id, playersao->getHP());
1807 m_script->player_event(playersao,"health_changed");
1809 // Send to other clients
1810 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1811 ActiveObjectMessage aom(playersao->getId(), true, str);
1812 playersao->m_messages_out.push(aom);
1815 void Server::SendPlayerBreath(u16 peer_id)
1817 DSTACK(__FUNCTION_NAME);
1818 PlayerSAO *playersao = getPlayerSAO(peer_id);
1821 m_script->player_event(playersao, "breath_changed");
1822 SendBreath(peer_id, playersao->getBreath());
1825 void Server::SendMovePlayer(u16 peer_id)
1827 DSTACK(__FUNCTION_NAME);
1828 Player *player = m_env->getPlayer(peer_id);
1831 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1832 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1835 v3f pos = player->getPosition();
1836 f32 pitch = player->getPitch();
1837 f32 yaw = player->getYaw();
1838 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1839 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1848 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1850 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1853 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1854 << animation_frames[3] << animation_speed;
1859 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1861 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1862 *pkt << first << third;
1865 void Server::SendPlayerPrivileges(u16 peer_id)
1867 Player *player = m_env->getPlayer(peer_id);
1869 if(player->peer_id == PEER_ID_INEXISTENT)
1872 std::set<std::string> privs;
1873 m_script->getAuth(player->getName(), NULL, &privs);
1875 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1876 *pkt << (u16) privs.size();
1878 for(std::set<std::string>::const_iterator i = privs.begin();
1879 i != privs.end(); i++) {
1886 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1888 Player *player = m_env->getPlayer(peer_id);
1890 if(player->peer_id == PEER_ID_INEXISTENT)
1893 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1894 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1898 s32 Server::playSound(const SimpleSoundSpec &spec,
1899 const ServerSoundParams ¶ms)
1901 // Find out initial position of sound
1902 bool pos_exists = false;
1903 v3f pos = params.getPos(m_env, &pos_exists);
1904 // If position is not found while it should be, cancel sound
1905 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1908 // Filter destination clients
1909 std::vector<u16> dst_clients;
1910 if(params.to_player != "")
1912 Player *player = m_env->getPlayer(params.to_player.c_str());
1914 infostream<<"Server::playSound: Player \""<<params.to_player
1915 <<"\" not found"<<std::endl;
1918 if(player->peer_id == PEER_ID_INEXISTENT){
1919 infostream<<"Server::playSound: Player \""<<params.to_player
1920 <<"\" not connected"<<std::endl;
1923 dst_clients.push_back(player->peer_id);
1926 std::vector<u16> clients = m_clients.getClientIDs();
1928 for(std::vector<u16>::iterator
1929 i = clients.begin(); i != clients.end(); ++i) {
1930 Player *player = m_env->getPlayer(*i);
1935 if(player->getPosition().getDistanceFrom(pos) >
1936 params.max_hear_distance)
1939 dst_clients.push_back(*i);
1943 if(dst_clients.empty())
1947 s32 id = m_next_sound_id++;
1948 // The sound will exist as a reference in m_playing_sounds
1949 m_playing_sounds[id] = ServerPlayingSound();
1950 ServerPlayingSound &psound = m_playing_sounds[id];
1951 psound.params = params;
1953 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1954 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1955 << (u8) params.type << pos << params.object << params.loop;
1957 for(std::vector<u16>::iterator i = dst_clients.begin();
1958 i != dst_clients.end(); i++) {
1959 psound.clients.insert(*i);
1960 m_clients.send(*i, 0, pkt, true, false);
1965 void Server::stopSound(s32 handle)
1967 // Get sound reference
1968 std::map<s32, ServerPlayingSound>::iterator i =
1969 m_playing_sounds.find(handle);
1970 if(i == m_playing_sounds.end())
1972 ServerPlayingSound &psound = i->second;
1974 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
1977 for(std::set<u16>::iterator i = psound.clients.begin();
1978 i != psound.clients.end(); i++) {
1980 m_clients.send(*i, 0, pkt, true, false);
1983 // Remove sound reference
1984 m_playing_sounds.erase(i);
1987 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1988 std::vector<u16> *far_players, float far_d_nodes)
1990 float maxd = far_d_nodes*BS;
1991 v3f p_f = intToFloat(p, BS);
1993 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
1996 std::vector<u16> clients = m_clients.getClientIDs();
1997 for(std::vector<u16>::iterator i = clients.begin();
1998 i != clients.end(); ++i) {
2001 if(Player *player = m_env->getPlayer(*i)) {
2002 // If player is far away, only set modified blocks not sent
2003 v3f player_pos = player->getPosition();
2004 if(player_pos.getDistanceFrom(p_f) > maxd) {
2005 far_players->push_back(*i);
2012 m_clients.send(*i, 0, pkt, true, false);
2014 // This loop needs the deletion of the packet here
2018 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2019 std::vector<u16> *far_players, float far_d_nodes,
2020 bool remove_metadata)
2022 float maxd = far_d_nodes*BS;
2023 v3f p_f = intToFloat(p, BS);
2025 std::vector<u16> clients = m_clients.getClientIDs();
2026 for(std::vector<u16>::iterator i = clients.begin();
2027 i != clients.end(); ++i) {
2031 if(Player *player = m_env->getPlayer(*i)) {
2032 // If player is far away, only set modified blocks not sent
2033 v3f player_pos = player->getPosition();
2034 if(player_pos.getDistanceFrom(p_f) > maxd) {
2035 far_players->push_back(*i);
2041 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2043 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2045 *pkt << p << n.param0 << n.param1 << n.param2
2046 << (u8) (remove_metadata ? 0 : 1);
2048 if (!remove_metadata) {
2049 if (client->net_proto_version <= 21) {
2050 // Old clients always clear metadata; fix it
2051 // by sending the full block again.
2052 client->SetBlockNotSent(p);
2059 if (pkt->getSize() > 0)
2060 m_clients.send(*i, 0, pkt, true);
2064 void Server::setBlockNotSent(v3s16 p)
2066 std::vector<u16> clients = m_clients.getClientIDs();
2068 for(std::vector<u16>::iterator i = clients.begin();
2069 i != clients.end(); ++i) {
2070 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2071 client->SetBlockNotSent(p);
2076 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2078 DSTACK(__FUNCTION_NAME);
2080 v3s16 p = block->getPos();
2083 Create a packet with the block in the right format
2086 std::ostringstream os(std::ios_base::binary);
2087 block->serialize(os, ver, false);
2088 block->serializeNetworkSpecific(os, net_proto_version);
2089 std::string s = os.str();
2091 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2092 2 + 2 + 2 + 2 + s.size(), peer_id);
2095 pkt->putRawString(s.c_str(), s.size());
2099 void Server::SendBlocks(float dtime)
2101 DSTACK(__FUNCTION_NAME);
2103 JMutexAutoLock envlock(m_env_mutex);
2104 //TODO check if one big lock could be faster then multiple small ones
2106 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2108 std::vector<PrioritySortedBlockTransfer> queue;
2110 s32 total_sending = 0;
2113 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2115 std::vector<u16> clients = m_clients.getClientIDs();
2118 for(std::vector<u16>::iterator i = clients.begin();
2119 i != clients.end(); ++i) {
2120 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2125 total_sending += client->SendingCount();
2126 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2132 // Lowest priority number comes first.
2133 // Lowest is most important.
2134 std::sort(queue.begin(), queue.end());
2137 for(u32 i=0; i<queue.size(); i++)
2139 //TODO: Calculate limit dynamically
2140 if(total_sending >= g_settings->getS32
2141 ("max_simultaneous_block_sends_server_total"))
2144 PrioritySortedBlockTransfer q = queue[i];
2146 MapBlock *block = NULL;
2149 block = m_env->getMap().getBlockNoCreate(q.pos);
2151 catch(InvalidPositionException &e)
2156 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2161 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2163 client->SentBlock(q.pos);
2169 void Server::fillMediaCache()
2171 DSTACK(__FUNCTION_NAME);
2173 infostream<<"Server: Calculating media file checksums"<<std::endl;
2175 // Collect all media file paths
2176 std::vector<std::string> paths;
2177 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2178 i != m_mods.end(); i++) {
2179 const ModSpec &mod = *i;
2180 paths.push_back(mod.path + DIR_DELIM + "textures");
2181 paths.push_back(mod.path + DIR_DELIM + "sounds");
2182 paths.push_back(mod.path + DIR_DELIM + "media");
2183 paths.push_back(mod.path + DIR_DELIM + "models");
2185 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2187 // Collect media file information from paths into cache
2188 for(std::vector<std::string>::iterator i = paths.begin();
2189 i != paths.end(); i++) {
2190 std::string mediapath = *i;
2191 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2192 for (u32 j = 0; j < dirlist.size(); j++) {
2193 if (dirlist[j].dir) // Ignode dirs
2195 std::string filename = dirlist[j].name;
2196 // If name contains illegal characters, ignore the file
2197 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2198 infostream<<"Server: ignoring illegal file name: \""
2199 << filename << "\"" << std::endl;
2202 // If name is not in a supported format, ignore it
2203 const char *supported_ext[] = {
2204 ".png", ".jpg", ".bmp", ".tga",
2205 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2207 ".x", ".b3d", ".md2", ".obj",
2210 if (removeStringEnd(filename, supported_ext) == ""){
2211 infostream << "Server: ignoring unsupported file extension: \""
2212 << filename << "\"" << std::endl;
2215 // Ok, attempt to load the file and add to cache
2216 std::string filepath = mediapath + DIR_DELIM + filename;
2218 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2220 errorstream << "Server::fillMediaCache(): Could not open \""
2221 << filename << "\" for reading" << std::endl;
2224 std::ostringstream tmp_os(std::ios_base::binary);
2228 fis.read(buf, 1024);
2229 std::streamsize len = fis.gcount();
2230 tmp_os.write(buf, len);
2239 errorstream<<"Server::fillMediaCache(): Failed to read \""
2240 << filename << "\"" << std::endl;
2243 if(tmp_os.str().length() == 0) {
2244 errorstream << "Server::fillMediaCache(): Empty file \""
2245 << filepath << "\"" << std::endl;
2250 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2252 unsigned char *digest = sha1.getDigest();
2253 std::string sha1_base64 = base64_encode(digest, 20);
2254 std::string sha1_hex = hex_encode((char*)digest, 20);
2258 m_media[filename] = MediaInfo(filepath, sha1_base64);
2259 verbosestream << "Server: " << sha1_hex << " is " << filename
2265 struct SendableMediaAnnouncement
2268 std::string sha1_digest;
2270 SendableMediaAnnouncement(const std::string &name_="",
2271 const std::string &sha1_digest_=""):
2273 sha1_digest(sha1_digest_)
2277 void Server::sendMediaAnnouncement(u16 peer_id)
2279 DSTACK(__FUNCTION_NAME);
2281 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2284 std::vector<SendableMediaAnnouncement> file_announcements;
2286 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2287 i != m_media.end(); i++){
2289 file_announcements.push_back(
2290 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2294 std::ostringstream os(std::ios_base::binary);
2301 u16 length of sha1_digest
2306 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2307 *pkt << (u16) file_announcements.size();
2309 for (std::vector<SendableMediaAnnouncement>::iterator
2310 j = file_announcements.begin();
2311 j != file_announcements.end(); ++j) {
2312 *pkt << j->name << j->sha1_digest;
2315 *pkt << g_settings->get("remote_media");
2319 struct SendableMedia
2325 SendableMedia(const std::string &name_="", const std::string &path_="",
2326 const std::string &data_=""):
2333 void Server::sendRequestedMedia(u16 peer_id,
2334 const std::vector<std::string> &tosend)
2336 DSTACK(__FUNCTION_NAME);
2338 verbosestream<<"Server::sendRequestedMedia(): "
2339 <<"Sending files to client"<<std::endl;
2343 // Put 5kB in one bunch (this is not accurate)
2344 u32 bytes_per_bunch = 5000;
2346 std::vector< std::vector<SendableMedia> > file_bunches;
2347 file_bunches.push_back(std::vector<SendableMedia>());
2349 u32 file_size_bunch_total = 0;
2351 for(std::vector<std::string>::const_iterator i = tosend.begin();
2352 i != tosend.end(); ++i) {
2353 const std::string &name = *i;
2355 if(m_media.find(name) == m_media.end()) {
2356 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2357 <<"unknown file \""<<(name)<<"\""<<std::endl;
2361 //TODO get path + name
2362 std::string tpath = m_media[name].path;
2365 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2366 if(fis.good() == false){
2367 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2368 <<tpath<<"\" for reading"<<std::endl;
2371 std::ostringstream tmp_os(std::ios_base::binary);
2375 fis.read(buf, 1024);
2376 std::streamsize len = fis.gcount();
2377 tmp_os.write(buf, len);
2378 file_size_bunch_total += len;
2387 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2388 <<name<<"\""<<std::endl;
2391 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2392 <<tname<<"\""<<std::endl;*/
2394 file_bunches[file_bunches.size()-1].push_back(
2395 SendableMedia(name, tpath, tmp_os.str()));
2397 // Start next bunch if got enough data
2398 if(file_size_bunch_total >= bytes_per_bunch) {
2399 file_bunches.push_back(std::vector<SendableMedia>());
2400 file_size_bunch_total = 0;
2405 /* Create and send packets */
2407 u16 num_bunches = file_bunches.size();
2408 for(u16 i = 0; i < num_bunches; i++) {
2411 u16 total number of texture bunches
2412 u16 index of this bunch
2413 u32 number of files in this bunch
2422 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2423 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2425 for(std::vector<SendableMedia>::iterator
2426 j = file_bunches[i].begin();
2427 j != file_bunches[i].end(); ++j) {
2429 pkt->putLongString(j->data);
2432 verbosestream << "Server::sendRequestedMedia(): bunch "
2433 << i << "/" << num_bunches
2434 << " files=" << file_bunches[i].size()
2435 << " size=" << pkt->getSize() << std::endl;
2440 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2442 if(m_detached_inventories.count(name) == 0) {
2443 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2446 Inventory *inv = m_detached_inventories[name];
2447 std::ostringstream os(std::ios_base::binary);
2449 os << serializeString(name);
2453 std::string s = os.str();
2455 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2456 pkt->putRawString(s.c_str(), s.size());
2458 if (peer_id != PEER_ID_INEXISTENT) {
2462 m_clients.sendToAll(0, pkt, true);
2466 void Server::sendDetachedInventories(u16 peer_id)
2468 DSTACK(__FUNCTION_NAME);
2470 for(std::map<std::string, Inventory*>::iterator
2471 i = m_detached_inventories.begin();
2472 i != m_detached_inventories.end(); i++) {
2473 const std::string &name = i->first;
2474 //Inventory *inv = i->second;
2475 sendDetachedInventory(name, peer_id);
2483 void Server::DiePlayer(u16 peer_id)
2485 DSTACK(__FUNCTION_NAME);
2487 PlayerSAO *playersao = getPlayerSAO(peer_id);
2490 infostream << "Server::DiePlayer(): Player "
2491 << playersao->getPlayer()->getName()
2492 << " dies" << std::endl;
2494 playersao->setHP(0);
2496 // Trigger scripted stuff
2497 m_script->on_dieplayer(playersao);
2499 SendPlayerHP(peer_id);
2500 SendDeathscreen(peer_id, false, v3f(0,0,0));
2503 void Server::RespawnPlayer(u16 peer_id)
2505 DSTACK(__FUNCTION_NAME);
2507 PlayerSAO *playersao = getPlayerSAO(peer_id);
2510 infostream << "Server::RespawnPlayer(): Player "
2511 << playersao->getPlayer()->getName()
2512 << " respawns" << std::endl;
2514 playersao->setHP(PLAYER_MAX_HP);
2515 playersao->setBreath(PLAYER_MAX_BREATH);
2517 SendPlayerHP(peer_id);
2518 SendPlayerBreath(peer_id);
2520 bool repositioned = m_script->on_respawnplayer(playersao);
2522 v3f pos = findSpawnPos(m_env->getServerMap());
2523 // setPos will send the new position to client
2524 playersao->setPos(pos);
2528 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2530 DSTACK(__FUNCTION_NAME);
2532 SendAccessDenied(peer_id, reason);
2533 m_clients.event(peer_id, CSE_SetDenied);
2534 m_con.DisconnectPeer(peer_id);
2537 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2539 DSTACK(__FUNCTION_NAME);
2540 std::wstring message;
2543 Clear references to playing sounds
2545 for(std::map<s32, ServerPlayingSound>::iterator
2546 i = m_playing_sounds.begin();
2547 i != m_playing_sounds.end();)
2549 ServerPlayingSound &psound = i->second;
2550 psound.clients.erase(peer_id);
2551 if(psound.clients.empty())
2552 m_playing_sounds.erase(i++);
2557 Player *player = m_env->getPlayer(peer_id);
2559 // Collect information about leaving in chat
2561 if(player != NULL && reason != CDR_DENY)
2563 std::wstring name = narrow_to_wide(player->getName());
2566 message += L" left the game.";
2567 if(reason == CDR_TIMEOUT)
2568 message += L" (timed out)";
2572 /* Run scripts and remove from environment */
2576 PlayerSAO *playersao = player->getPlayerSAO();
2579 m_script->on_leaveplayer(playersao);
2581 playersao->disconnected();
2589 if(player != NULL && reason != CDR_DENY) {
2590 std::ostringstream os(std::ios_base::binary);
2591 std::vector<u16> clients = m_clients.getClientIDs();
2593 for(std::vector<u16>::iterator i = clients.begin();
2594 i != clients.end(); ++i) {
2596 Player *player = m_env->getPlayer(*i);
2600 // Get name of player
2601 os << player->getName() << " ";
2604 actionstream << player->getName() << " "
2605 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2606 << " List of players: " << os.str() << std::endl;
2610 JMutexAutoLock env_lock(m_env_mutex);
2611 m_clients.DeleteClient(peer_id);
2615 // Send leave chat message to all remaining clients
2616 if(message.length() != 0)
2617 SendChatMessage(PEER_ID_INEXISTENT,message);
2620 void Server::UpdateCrafting(Player* player)
2622 DSTACK(__FUNCTION_NAME);
2624 // Get a preview for crafting
2626 InventoryLocation loc;
2627 loc.setPlayer(player->getName());
2628 getCraftingResult(&player->inventory, preview, false, this);
2629 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2631 // Put the new preview in
2632 InventoryList *plist = player->inventory.getList("craftpreview");
2633 sanity_check(plist);
2634 sanity_check(plist->getSize() >= 1);
2635 plist->changeItem(0, preview);
2638 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2640 RemoteClient *client = getClientNoEx(peer_id,state_min);
2642 throw ClientNotFoundException("Client not found");
2646 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2648 return m_clients.getClientNoEx(peer_id, state_min);
2651 std::string Server::getPlayerName(u16 peer_id)
2653 Player *player = m_env->getPlayer(peer_id);
2655 return "[id="+itos(peer_id)+"]";
2656 return player->getName();
2659 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2661 Player *player = m_env->getPlayer(peer_id);
2664 return player->getPlayerSAO();
2667 std::wstring Server::getStatusString()
2669 std::wostringstream os(std::ios_base::binary);
2672 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2674 os<<L", uptime="<<m_uptime.get();
2676 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2677 // Information about clients
2680 std::vector<u16> clients = m_clients.getClientIDs();
2681 for(std::vector<u16>::iterator i = clients.begin();
2682 i != clients.end(); ++i) {
2684 Player *player = m_env->getPlayer(*i);
2685 // Get name of player
2686 std::wstring name = L"unknown";
2688 name = narrow_to_wide(player->getName());
2689 // Add name to information string
2697 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2698 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2699 if(g_settings->get("motd") != "")
2700 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2704 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2706 std::set<std::string> privs;
2707 m_script->getAuth(name, NULL, &privs);
2711 bool Server::checkPriv(const std::string &name, const std::string &priv)
2713 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2714 return (privs.count(priv) != 0);
2717 void Server::reportPrivsModified(const std::string &name)
2720 std::vector<u16> clients = m_clients.getClientIDs();
2721 for(std::vector<u16>::iterator i = clients.begin();
2722 i != clients.end(); ++i) {
2723 Player *player = m_env->getPlayer(*i);
2724 reportPrivsModified(player->getName());
2727 Player *player = m_env->getPlayer(name.c_str());
2730 SendPlayerPrivileges(player->peer_id);
2731 PlayerSAO *sao = player->getPlayerSAO();
2734 sao->updatePrivileges(
2735 getPlayerEffectivePrivs(name),
2740 void Server::reportInventoryFormspecModified(const std::string &name)
2742 Player *player = m_env->getPlayer(name.c_str());
2745 SendPlayerInventoryFormspec(player->peer_id);
2748 void Server::setIpBanned(const std::string &ip, const std::string &name)
2750 m_banmanager->add(ip, name);
2753 void Server::unsetIpBanned(const std::string &ip_or_name)
2755 m_banmanager->remove(ip_or_name);
2758 std::string Server::getBanDescription(const std::string &ip_or_name)
2760 return m_banmanager->getBanDescription(ip_or_name);
2763 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2765 Player *player = m_env->getPlayer(name);
2769 if (player->peer_id == PEER_ID_INEXISTENT)
2772 SendChatMessage(player->peer_id, msg);
2775 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2777 Player *player = m_env->getPlayer(playername);
2781 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2785 SendShowFormspecMessage(player->peer_id, formspec, formname);
2789 u32 Server::hudAdd(Player *player, HudElement *form) {
2793 u32 id = player->addHud(form);
2795 SendHUDAdd(player->peer_id, id, form);
2800 bool Server::hudRemove(Player *player, u32 id) {
2804 HudElement* todel = player->removeHud(id);
2811 SendHUDRemove(player->peer_id, id);
2815 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2819 SendHUDChange(player->peer_id, id, stat, data);
2823 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2827 SendHUDSetFlags(player->peer_id, flags, mask);
2828 player->hud_flags = flags;
2830 PlayerSAO* playersao = player->getPlayerSAO();
2832 if (playersao == NULL)
2835 m_script->player_event(playersao, "hud_changed");
2839 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2842 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2845 std::ostringstream os(std::ios::binary);
2846 writeS32(os, hotbar_itemcount);
2847 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2851 void Server::hudSetHotbarImage(Player *player, std::string name) {
2855 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2858 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2862 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2865 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2870 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2874 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2879 SendEyeOffset(player->peer_id, first, third);
2883 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2884 const std::string &type, const std::vector<std::string> ¶ms)
2889 SendSetSky(player->peer_id, bgcolor, type, params);
2893 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2899 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2903 void Server::notifyPlayers(const std::wstring &msg)
2905 SendChatMessage(PEER_ID_INEXISTENT,msg);
2908 void Server::spawnParticle(const char *playername, v3f pos,
2909 v3f velocity, v3f acceleration,
2910 float expirationtime, float size, bool
2911 collisiondetection, bool vertical, std::string texture)
2913 Player *player = m_env->getPlayer(playername);
2916 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2917 expirationtime, size, collisiondetection, vertical, texture);
2920 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2921 float expirationtime, float size,
2922 bool collisiondetection, bool vertical, std::string texture)
2924 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2925 expirationtime, size, collisiondetection, vertical, texture);
2928 u32 Server::addParticleSpawner(const char *playername,
2929 u16 amount, float spawntime,
2930 v3f minpos, v3f maxpos,
2931 v3f minvel, v3f maxvel,
2932 v3f minacc, v3f maxacc,
2933 float minexptime, float maxexptime,
2934 float minsize, float maxsize,
2935 bool collisiondetection, bool vertical, std::string texture)
2937 Player *player = m_env->getPlayer(playername);
2942 for(;;) // look for unused particlespawner id
2945 if (std::find(m_particlespawner_ids.begin(),
2946 m_particlespawner_ids.end(), id)
2947 == m_particlespawner_ids.end())
2949 m_particlespawner_ids.push_back(id);
2954 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2955 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2956 minexptime, maxexptime, minsize, maxsize,
2957 collisiondetection, vertical, texture, id);
2962 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2963 v3f minpos, v3f maxpos,
2964 v3f minvel, v3f maxvel,
2965 v3f minacc, v3f maxacc,
2966 float minexptime, float maxexptime,
2967 float minsize, float maxsize,
2968 bool collisiondetection, bool vertical, std::string texture)
2971 for(;;) // look for unused particlespawner id
2974 if (std::find(m_particlespawner_ids.begin(),
2975 m_particlespawner_ids.end(), id)
2976 == m_particlespawner_ids.end())
2978 m_particlespawner_ids.push_back(id);
2983 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2984 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2985 minexptime, maxexptime, minsize, maxsize,
2986 collisiondetection, vertical, texture, id);
2991 void Server::deleteParticleSpawner(const char *playername, u32 id)
2993 Player *player = m_env->getPlayer(playername);
2997 m_particlespawner_ids.erase(
2998 std::remove(m_particlespawner_ids.begin(),
2999 m_particlespawner_ids.end(), id),
3000 m_particlespawner_ids.end());
3001 SendDeleteParticleSpawner(player->peer_id, id);
3004 void Server::deleteParticleSpawnerAll(u32 id)
3006 m_particlespawner_ids.erase(
3007 std::remove(m_particlespawner_ids.begin(),
3008 m_particlespawner_ids.end(), id),
3009 m_particlespawner_ids.end());
3010 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3013 Inventory* Server::createDetachedInventory(const std::string &name)
3015 if(m_detached_inventories.count(name) > 0){
3016 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3017 delete m_detached_inventories[name];
3019 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3021 Inventory *inv = new Inventory(m_itemdef);
3023 m_detached_inventories[name] = inv;
3024 //TODO find a better way to do this
3025 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3032 BoolScopeSet(bool *dst, bool val):
3035 m_orig_state = *m_dst;
3040 *m_dst = m_orig_state;
3047 // actions: time-reversed list
3048 // Return value: success/failure
3049 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3050 std::list<std::string> *log)
3052 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3053 ServerMap *map = (ServerMap*)(&m_env->getMap());
3055 // Fail if no actions to handle
3056 if(actions.empty()){
3057 log->push_back("Nothing to do.");
3064 for(std::list<RollbackAction>::const_iterator
3065 i = actions.begin();
3066 i != actions.end(); i++)
3068 const RollbackAction &action = *i;
3070 bool success = action.applyRevert(map, this, this);
3073 std::ostringstream os;
3074 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3075 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3077 log->push_back(os.str());
3079 std::ostringstream os;
3080 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3081 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3083 log->push_back(os.str());
3087 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3088 <<" failed"<<std::endl;
3090 // Call it done if less than half failed
3091 return num_failed <= num_tried/2;
3094 // IGameDef interface
3096 IItemDefManager* Server::getItemDefManager()
3100 INodeDefManager* Server::getNodeDefManager()
3104 ICraftDefManager* Server::getCraftDefManager()
3108 ITextureSource* Server::getTextureSource()
3112 IShaderSource* Server::getShaderSource()
3116 scene::ISceneManager* Server::getSceneManager()
3121 u16 Server::allocateUnknownNodeId(const std::string &name)
3123 return m_nodedef->allocateDummy(name);
3125 ISoundManager* Server::getSoundManager()
3127 return &dummySoundManager;
3129 MtEventManager* Server::getEventManager()
3134 IWritableItemDefManager* Server::getWritableItemDefManager()
3138 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3142 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3147 const ModSpec* Server::getModSpec(const std::string &modname)
3149 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3150 i != m_mods.end(); i++){
3151 const ModSpec &mod = *i;
3152 if(mod.name == modname)
3157 void Server::getModNames(std::vector<std::string> &modlist)
3159 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3160 modlist.push_back(i->name);
3163 std::string Server::getBuiltinLuaPath()
3165 return porting::path_share + DIR_DELIM + "builtin";
3168 v3f findSpawnPos(ServerMap &map)
3170 //return v3f(50,50,50)*BS;
3175 nodepos = v2s16(0,0);
3180 s16 water_level = map.getWaterLevel();
3182 // Try to find a good place a few times
3183 for(s32 i=0; i<1000; i++)
3186 // We're going to try to throw the player to this position
3187 v2s16 nodepos2d = v2s16(
3188 -range + (myrand() % (range * 2)),
3189 -range + (myrand() % (range * 2)));
3191 // Get ground height at point
3192 s16 groundheight = map.findGroundLevel(nodepos2d);
3193 if (groundheight <= water_level) // Don't go underwater
3195 if (groundheight > water_level + 6) // Don't go to high places
3198 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3199 bool is_good = false;
3201 for (s32 i = 0; i < 10; i++) {
3202 v3s16 blockpos = getNodeBlockPos(nodepos);
3203 map.emergeBlock(blockpos, true);
3204 content_t c = map.getNodeNoEx(nodepos).getContent();
3205 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3207 if (air_count >= 2){
3215 // Found a good place
3216 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3222 return intToFloat(nodepos, BS);
3225 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3227 bool newplayer = false;
3230 Try to get an existing player
3232 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3234 // If player is already connected, cancel
3235 if(player != NULL && player->peer_id != 0)
3237 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3242 If player with the wanted peer_id already exists, cancel.
3244 if(m_env->getPlayer(peer_id) != NULL)
3246 infostream<<"emergePlayer(): Player with wrong name but same"
3247 " peer_id already exists"<<std::endl;
3251 // Load player if it isn't already loaded
3253 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3256 // Create player if it doesn't exist
3259 player = new RemotePlayer(this, name);
3260 // Set player position
3261 infostream<<"Server: Finding spawn place for player \""
3262 <<name<<"\""<<std::endl;
3263 v3f pos = findSpawnPos(m_env->getServerMap());
3264 player->setPosition(pos);
3266 // Make sure the player is saved
3267 player->setModified(true);
3269 // Add player to environment
3270 m_env->addPlayer(player);
3273 // Create a new player active object
3274 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3275 getPlayerEffectivePrivs(player->getName()),
3278 /* Clean up old HUD elements from previous sessions */
3281 /* Add object to environment */
3282 m_env->addActiveObject(playersao);
3286 m_script->on_newplayer(playersao);
3292 void dedicated_server_loop(Server &server, bool &kill)
3294 DSTACK(__FUNCTION_NAME);
3296 verbosestream<<"dedicated_server_loop()"<<std::endl;
3298 IntervalLimiter m_profiler_interval;
3302 float steplen = g_settings->getFloat("dedicated_server_step");
3303 // This is kind of a hack but can be done like this
3304 // because server.step() is very light
3306 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3307 sleep_ms((int)(steplen*1000.0));
3309 server.step(steplen);
3311 if(server.getShutdownRequested() || kill)
3313 infostream<<"Dedicated server quitting"<<std::endl;
3315 if(g_settings->getBool("server_announce"))
3316 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3324 float profiler_print_interval =
3325 g_settings->getFloat("profiler_print_interval");
3326 if(profiler_print_interval != 0)
3328 if(m_profiler_interval.step(steplen, profiler_print_interval))
3330 infostream<<"Profiler:"<<std::endl;
3331 g_profiler->print(infostream);
3332 g_profiler->clear();