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(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(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
852 pkt.putRawString(reliable_data.c_str(), reliable_data.size());
856 if(unreliable_data.size() > 0) {
857 NetworkPacket pkt(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_Legacy(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_Legacy(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_Legacy(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 SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1105 SendPlayerBreath(peer_id);
1107 // Show death screen if necessary
1108 if(player->isDead())
1109 SendDeathscreen(peer_id, false, v3f(0,0,0));
1111 // Note things in chat if not in simple singleplayer mode
1112 if(!m_simple_singleplayer_mode) {
1113 // Send information about server to player in chat
1114 SendChatMessage(peer_id, getStatusString());
1116 // Send information about joining in chat
1118 std::wstring name = L"unknown";
1119 Player *player = m_env->getPlayer(peer_id);
1121 name = narrow_to_wide(player->getName());
1123 std::wstring message;
1126 message += L" joined the game.";
1127 SendChatMessage(PEER_ID_INEXISTENT,message);
1130 Address addr = getPeerAddress(player->peer_id);
1131 std::string ip_str = addr.serializeString();
1132 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1137 std::vector<std::string> names = m_clients.getPlayerNames();
1139 actionstream<<player->getName() <<" joins game. List of players: ";
1141 for (std::vector<std::string>::iterator i = names.begin();
1142 i != names.end(); i++) {
1143 actionstream << *i << " ";
1146 actionstream << player->getName() <<std::endl;
1151 inline void Server::handleCommand(NetworkPacket* pkt)
1153 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1154 (this->*opHandle.handler)(pkt);
1157 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1159 DSTACK(__FUNCTION_NAME);
1160 // Environment is locked first.
1161 JMutexAutoLock envlock(m_env_mutex);
1163 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1166 Address address = getPeerAddress(peer_id);
1167 std::string addr_s = address.serializeString();
1169 if(m_banmanager->isIpBanned(addr_s)) {
1170 std::string ban_name = m_banmanager->getBanName(addr_s);
1171 infostream << "Server: A banned client tried to connect from "
1172 << addr_s << "; banned name was "
1173 << ban_name << std::endl;
1174 // This actually doesn't seem to transfer to the client
1175 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1176 + narrow_to_wide(ban_name));
1180 catch(con::PeerNotFoundException &e) {
1182 * no peer for this packet found
1183 * most common reason is peer timeout, e.g. peer didn't
1184 * respond for some time, your server was overloaded or
1187 infostream << "Server::ProcessData(): Cancelling: peer "
1188 << peer_id << " not found" << std::endl;
1196 NetworkPacket pkt(data, datasize, peer_id);
1198 ToServerCommand command = (ToServerCommand) pkt.getCommand();
1200 // Command must be handled into ToServerCommandHandler
1201 if (command >= TOSERVER_NUM_MSG_TYPES) {
1202 infostream << "Server: Ignoring unknown command "
1203 << command << std::endl;
1206 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1207 handleCommand(&pkt);
1211 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1213 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1214 errorstream << "Server::ProcessData(): Cancelling: Peer"
1215 " serialization format invalid or not initialized."
1216 " Skipping incoming command=" << command << std::endl;
1220 /* Handle commands related to client startup */
1221 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1222 handleCommand(&pkt);
1226 if (m_clients.getClientState(peer_id) < CS_Active) {
1227 if (command == TOSERVER_PLAYERPOS) return;
1229 errorstream << "Got packet command: " << command << " for peer id "
1230 << peer_id << " but client isn't active yet. Dropping packet "
1235 handleCommand(&pkt);
1237 catch(SendFailedException &e) {
1238 errorstream << "Server::ProcessData(): SendFailedException: "
1239 << "what=" << e.what()
1244 void Server::setTimeOfDay(u32 time)
1246 m_env->setTimeOfDay(time);
1247 m_time_of_day_send_timer = 0;
1250 void Server::onMapEditEvent(MapEditEvent *event)
1252 if(m_ignore_map_edit_events)
1254 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1256 MapEditEvent *e = event->clone();
1257 m_unsent_map_edit_queue.push(e);
1260 Inventory* Server::getInventory(const InventoryLocation &loc)
1263 case InventoryLocation::UNDEFINED:
1264 case InventoryLocation::CURRENT_PLAYER:
1266 case InventoryLocation::PLAYER:
1268 Player *player = m_env->getPlayer(loc.name.c_str());
1271 PlayerSAO *playersao = player->getPlayerSAO();
1274 return playersao->getInventory();
1277 case InventoryLocation::NODEMETA:
1279 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1282 return meta->getInventory();
1285 case InventoryLocation::DETACHED:
1287 if(m_detached_inventories.count(loc.name) == 0)
1289 return m_detached_inventories[loc.name];
1293 sanity_check(false); // abort
1298 void Server::setInventoryModified(const InventoryLocation &loc)
1301 case InventoryLocation::UNDEFINED:
1303 case InventoryLocation::PLAYER:
1305 Player *player = m_env->getPlayer(loc.name.c_str());
1308 PlayerSAO *playersao = player->getPlayerSAO();
1312 SendInventory(playersao);
1315 case InventoryLocation::NODEMETA:
1317 v3s16 blockpos = getNodeBlockPos(loc.p);
1319 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1321 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1323 setBlockNotSent(blockpos);
1326 case InventoryLocation::DETACHED:
1328 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1332 sanity_check(false); // abort
1337 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1339 std::vector<u16> clients = m_clients.getClientIDs();
1341 // Set the modified blocks unsent for all the clients
1342 for (std::vector<u16>::iterator i = clients.begin();
1343 i != clients.end(); ++i) {
1344 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1345 client->SetBlocksNotSent(block);
1350 void Server::peerAdded(con::Peer *peer)
1352 DSTACK(__FUNCTION_NAME);
1353 verbosestream<<"Server::peerAdded(): peer->id="
1354 <<peer->id<<std::endl;
1357 c.type = con::PEER_ADDED;
1358 c.peer_id = peer->id;
1360 m_peer_change_queue.push(c);
1363 void Server::deletingPeer(con::Peer *peer, bool timeout)
1365 DSTACK(__FUNCTION_NAME);
1366 verbosestream<<"Server::deletingPeer(): peer->id="
1367 <<peer->id<<", timeout="<<timeout<<std::endl;
1369 m_clients.event(peer->id, CSE_Disconnect);
1371 c.type = con::PEER_REMOVED;
1372 c.peer_id = peer->id;
1373 c.timeout = timeout;
1374 m_peer_change_queue.push(c);
1377 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1379 *retval = m_con.getPeerStat(peer_id,type);
1380 if (*retval == -1) return false;
1384 bool Server::getClientInfo(
1393 std::string* vers_string
1396 *state = m_clients.getClientState(peer_id);
1398 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1400 if (client == NULL) {
1405 *uptime = client->uptime();
1406 *ser_vers = client->serialization_version;
1407 *prot_vers = client->net_proto_version;
1409 *major = client->getMajor();
1410 *minor = client->getMinor();
1411 *patch = client->getPatch();
1412 *vers_string = client->getPatch();
1419 void Server::handlePeerChanges()
1421 while(m_peer_change_queue.size() > 0)
1423 con::PeerChange c = m_peer_change_queue.front();
1424 m_peer_change_queue.pop();
1426 verbosestream<<"Server: Handling peer change: "
1427 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1432 case con::PEER_ADDED:
1433 m_clients.CreateClient(c.peer_id);
1436 case con::PEER_REMOVED:
1437 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1441 FATAL_ERROR("Invalid peer change event received!");
1447 void Server::Send(NetworkPacket* pkt)
1449 m_clients.send(pkt->getPeerId(),
1450 clientCommandFactoryTable[pkt->getCommand()].channel,
1452 clientCommandFactoryTable[pkt->getCommand()].reliable);
1455 void Server::SendMovement(u16 peer_id)
1457 DSTACK(__FUNCTION_NAME);
1458 std::ostringstream os(std::ios_base::binary);
1460 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1462 pkt << g_settings->getFloat("movement_acceleration_default");
1463 pkt << g_settings->getFloat("movement_acceleration_air");
1464 pkt << g_settings->getFloat("movement_acceleration_fast");
1465 pkt << g_settings->getFloat("movement_speed_walk");
1466 pkt << g_settings->getFloat("movement_speed_crouch");
1467 pkt << g_settings->getFloat("movement_speed_fast");
1468 pkt << g_settings->getFloat("movement_speed_climb");
1469 pkt << g_settings->getFloat("movement_speed_jump");
1470 pkt << g_settings->getFloat("movement_liquid_fluidity");
1471 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1472 pkt << g_settings->getFloat("movement_liquid_sink");
1473 pkt << g_settings->getFloat("movement_gravity");
1478 void Server::SendHP(u16 peer_id, u8 hp)
1480 DSTACK(__FUNCTION_NAME);
1482 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1487 void Server::SendBreath(u16 peer_id, u16 breath)
1489 DSTACK(__FUNCTION_NAME);
1491 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1492 pkt << (u16) breath;
1496 void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
1498 DSTACK(__FUNCTION_NAME);
1500 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1503 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1504 pkt << custom_reason;
1509 void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1511 DSTACK(__FUNCTION_NAME);
1513 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1518 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1519 v3f camera_point_target)
1521 DSTACK(__FUNCTION_NAME);
1523 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1524 pkt << set_camera_point_target << camera_point_target;
1528 void Server::SendItemDef(u16 peer_id,
1529 IItemDefManager *itemdef, u16 protocol_version)
1531 DSTACK(__FUNCTION_NAME);
1533 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1537 u32 length of the next item
1538 zlib-compressed serialized ItemDefManager
1540 std::ostringstream tmp_os(std::ios::binary);
1541 itemdef->serialize(tmp_os, protocol_version);
1542 std::ostringstream tmp_os2(std::ios::binary);
1543 compressZlib(tmp_os.str(), tmp_os2);
1544 pkt.putLongString(tmp_os2.str());
1547 verbosestream << "Server: Sending item definitions to id(" << peer_id
1548 << "): size=" << pkt.getSize() << std::endl;
1553 void Server::SendNodeDef(u16 peer_id,
1554 INodeDefManager *nodedef, u16 protocol_version)
1556 DSTACK(__FUNCTION_NAME);
1558 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1562 u32 length of the next item
1563 zlib-compressed serialized NodeDefManager
1565 std::ostringstream tmp_os(std::ios::binary);
1566 nodedef->serialize(tmp_os, protocol_version);
1567 std::ostringstream tmp_os2(std::ios::binary);
1568 compressZlib(tmp_os.str(), tmp_os2);
1570 pkt.putLongString(tmp_os2.str());
1573 verbosestream << "Server: Sending node definitions to id(" << peer_id
1574 << "): size=" << pkt.getSize() << std::endl;
1580 Non-static send methods
1583 void Server::SendInventory(PlayerSAO* playerSAO)
1585 DSTACK(__FUNCTION_NAME);
1587 UpdateCrafting(playerSAO->getPlayer());
1593 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1595 std::ostringstream os;
1596 playerSAO->getInventory()->serialize(os);
1598 std::string s = os.str();
1600 pkt.putRawString(s.c_str(), s.size());
1604 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1606 DSTACK(__FUNCTION_NAME);
1608 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1611 if (peer_id != PEER_ID_INEXISTENT) {
1615 m_clients.sendToAll(0, &pkt, true);
1619 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1620 const std::string &formname)
1622 DSTACK(__FUNCTION_NAME);
1624 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1626 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1632 // Spawns a particle on peer with peer_id
1633 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1634 float expirationtime, float size, bool collisiondetection,
1635 bool vertical, std::string texture)
1637 DSTACK(__FUNCTION_NAME);
1639 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1641 pkt << pos << velocity << acceleration << expirationtime
1642 << size << collisiondetection;
1643 pkt.putLongString(texture);
1646 if (peer_id != PEER_ID_INEXISTENT) {
1650 m_clients.sendToAll(0, &pkt, true);
1654 // Adds a ParticleSpawner on peer with peer_id
1655 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1656 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1657 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1659 DSTACK(__FUNCTION_NAME);
1661 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1663 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1664 << minacc << maxacc << minexptime << maxexptime << minsize
1665 << maxsize << collisiondetection;
1667 pkt.putLongString(texture);
1669 pkt << id << vertical;
1671 if (peer_id != PEER_ID_INEXISTENT) {
1675 m_clients.sendToAll(0, &pkt, true);
1679 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1681 DSTACK(__FUNCTION_NAME);
1683 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1685 // Ugly error in this packet
1688 if (peer_id != PEER_ID_INEXISTENT) {
1692 m_clients.sendToAll(0, &pkt, true);
1697 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1699 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1701 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1702 << form->text << form->number << form->item << form->dir
1703 << form->align << form->offset << form->world_pos << form->size;
1708 void Server::SendHUDRemove(u16 peer_id, u32 id)
1710 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1715 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1717 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1718 pkt << id << (u8) stat;
1722 case HUD_STAT_SCALE:
1723 case HUD_STAT_ALIGN:
1724 case HUD_STAT_OFFSET:
1725 pkt << *(v2f *) value;
1729 pkt << *(std::string *) value;
1731 case HUD_STAT_WORLD_POS:
1732 pkt << *(v3f *) value;
1735 pkt << *(v2s32 *) value;
1737 case HUD_STAT_NUMBER:
1741 pkt << *(u32 *) value;
1748 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1750 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1752 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1754 pkt << flags << mask;
1759 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1761 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1762 pkt << param << value;
1766 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1767 const std::string &type, const std::vector<std::string> ¶ms)
1769 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1770 pkt << bgcolor << type << (u16) params.size();
1772 for(size_t i=0; i<params.size(); i++)
1778 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1781 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1784 pkt << do_override << (u16) (ratio * 65535);
1789 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1791 DSTACK(__FUNCTION_NAME);
1793 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1794 pkt << time << time_speed;
1796 if (peer_id == PEER_ID_INEXISTENT) {
1797 m_clients.sendToAll(0, &pkt, true);
1804 void Server::SendPlayerHP(u16 peer_id)
1806 DSTACK(__FUNCTION_NAME);
1807 PlayerSAO *playersao = getPlayerSAO(peer_id);
1809 SendHP(peer_id, playersao->getHP());
1810 m_script->player_event(playersao,"health_changed");
1812 // Send to other clients
1813 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1814 ActiveObjectMessage aom(playersao->getId(), true, str);
1815 playersao->m_messages_out.push(aom);
1818 void Server::SendPlayerBreath(u16 peer_id)
1820 DSTACK(__FUNCTION_NAME);
1821 PlayerSAO *playersao = getPlayerSAO(peer_id);
1824 m_script->player_event(playersao, "breath_changed");
1825 SendBreath(peer_id, playersao->getBreath());
1828 void Server::SendMovePlayer(u16 peer_id)
1830 DSTACK(__FUNCTION_NAME);
1831 Player *player = m_env->getPlayer(peer_id);
1834 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1835 pkt << player->getPosition() << player->getPitch() << player->getYaw();
1838 v3f pos = player->getPosition();
1839 f32 pitch = player->getPitch();
1840 f32 yaw = player->getYaw();
1841 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1842 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1843 << " pitch=" << pitch
1851 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1853 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1856 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1857 << animation_frames[3] << animation_speed;
1862 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1864 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1865 pkt << first << third;
1868 void Server::SendPlayerPrivileges(u16 peer_id)
1870 Player *player = m_env->getPlayer(peer_id);
1872 if(player->peer_id == PEER_ID_INEXISTENT)
1875 std::set<std::string> privs;
1876 m_script->getAuth(player->getName(), NULL, &privs);
1878 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1879 pkt << (u16) privs.size();
1881 for(std::set<std::string>::const_iterator i = privs.begin();
1882 i != privs.end(); i++) {
1889 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1891 Player *player = m_env->getPlayer(peer_id);
1893 if(player->peer_id == PEER_ID_INEXISTENT)
1896 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1897 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1901 s32 Server::playSound(const SimpleSoundSpec &spec,
1902 const ServerSoundParams ¶ms)
1904 // Find out initial position of sound
1905 bool pos_exists = false;
1906 v3f pos = params.getPos(m_env, &pos_exists);
1907 // If position is not found while it should be, cancel sound
1908 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1911 // Filter destination clients
1912 std::vector<u16> dst_clients;
1913 if(params.to_player != "")
1915 Player *player = m_env->getPlayer(params.to_player.c_str());
1917 infostream<<"Server::playSound: Player \""<<params.to_player
1918 <<"\" not found"<<std::endl;
1921 if(player->peer_id == PEER_ID_INEXISTENT){
1922 infostream<<"Server::playSound: Player \""<<params.to_player
1923 <<"\" not connected"<<std::endl;
1926 dst_clients.push_back(player->peer_id);
1929 std::vector<u16> clients = m_clients.getClientIDs();
1931 for(std::vector<u16>::iterator
1932 i = clients.begin(); i != clients.end(); ++i) {
1933 Player *player = m_env->getPlayer(*i);
1938 if(player->getPosition().getDistanceFrom(pos) >
1939 params.max_hear_distance)
1942 dst_clients.push_back(*i);
1946 if(dst_clients.empty())
1950 s32 id = m_next_sound_id++;
1951 // The sound will exist as a reference in m_playing_sounds
1952 m_playing_sounds[id] = ServerPlayingSound();
1953 ServerPlayingSound &psound = m_playing_sounds[id];
1954 psound.params = params;
1956 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1957 pkt << id << spec.name << (float) (spec.gain * params.gain)
1958 << (u8) params.type << pos << params.object << params.loop;
1960 for(std::vector<u16>::iterator i = dst_clients.begin();
1961 i != dst_clients.end(); i++) {
1962 psound.clients.insert(*i);
1963 m_clients.send(*i, 0, &pkt, true);
1967 void Server::stopSound(s32 handle)
1969 // Get sound reference
1970 std::map<s32, ServerPlayingSound>::iterator i =
1971 m_playing_sounds.find(handle);
1972 if(i == m_playing_sounds.end())
1974 ServerPlayingSound &psound = i->second;
1976 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
1979 for(std::set<u16>::iterator i = psound.clients.begin();
1980 i != psound.clients.end(); i++) {
1982 m_clients.send(*i, 0, &pkt, true);
1984 // Remove sound reference
1985 m_playing_sounds.erase(i);
1988 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1989 std::vector<u16> *far_players, float far_d_nodes)
1991 float maxd = far_d_nodes*BS;
1992 v3f p_f = intToFloat(p, BS);
1994 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
1997 std::vector<u16> clients = m_clients.getClientIDs();
1998 for(std::vector<u16>::iterator i = clients.begin();
1999 i != clients.end(); ++i) {
2002 if(Player *player = m_env->getPlayer(*i)) {
2003 // If player is far away, only set modified blocks not sent
2004 v3f player_pos = player->getPosition();
2005 if(player_pos.getDistanceFrom(p_f) > maxd) {
2006 far_players->push_back(*i);
2013 m_clients.send(*i, 0, &pkt, true);
2017 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2018 std::vector<u16> *far_players, float far_d_nodes,
2019 bool remove_metadata)
2021 float maxd = far_d_nodes*BS;
2022 v3f p_f = intToFloat(p, BS);
2024 std::vector<u16> clients = m_clients.getClientIDs();
2025 for(std::vector<u16>::iterator i = clients.begin();
2026 i != clients.end(); ++i) {
2030 if(Player *player = m_env->getPlayer(*i)) {
2031 // If player is far away, only set modified blocks not sent
2032 v3f player_pos = player->getPosition();
2033 if(player_pos.getDistanceFrom(p_f) > maxd) {
2034 far_players->push_back(*i);
2040 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2042 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2044 pkt << p << n.param0 << n.param1 << n.param2
2045 << (u8) (remove_metadata ? 0 : 1);
2047 if (!remove_metadata) {
2048 if (client->net_proto_version <= 21) {
2049 // Old clients always clear metadata; fix it
2050 // by sending the full block again.
2051 client->SetBlockNotSent(p);
2058 if (pkt.getSize() > 0)
2059 m_clients.send(*i, 0, &pkt, true);
2063 void Server::setBlockNotSent(v3s16 p)
2065 std::vector<u16> clients = m_clients.getClientIDs();
2067 for(std::vector<u16>::iterator i = clients.begin();
2068 i != clients.end(); ++i) {
2069 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2070 client->SetBlockNotSent(p);
2075 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2077 DSTACK(__FUNCTION_NAME);
2079 v3s16 p = block->getPos();
2082 Create a packet with the block in the right format
2085 std::ostringstream os(std::ios_base::binary);
2086 block->serialize(os, ver, false);
2087 block->serializeNetworkSpecific(os, net_proto_version);
2088 std::string s = os.str();
2090 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2093 pkt.putRawString(s.c_str(), s.size());
2097 void Server::SendBlocks(float dtime)
2099 DSTACK(__FUNCTION_NAME);
2101 JMutexAutoLock envlock(m_env_mutex);
2102 //TODO check if one big lock could be faster then multiple small ones
2104 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2106 std::vector<PrioritySortedBlockTransfer> queue;
2108 s32 total_sending = 0;
2111 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2113 std::vector<u16> clients = m_clients.getClientIDs();
2116 for(std::vector<u16>::iterator i = clients.begin();
2117 i != clients.end(); ++i) {
2118 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2123 total_sending += client->SendingCount();
2124 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2130 // Lowest priority number comes first.
2131 // Lowest is most important.
2132 std::sort(queue.begin(), queue.end());
2135 for(u32 i=0; i<queue.size(); i++)
2137 //TODO: Calculate limit dynamically
2138 if(total_sending >= g_settings->getS32
2139 ("max_simultaneous_block_sends_server_total"))
2142 PrioritySortedBlockTransfer q = queue[i];
2144 MapBlock *block = NULL;
2147 block = m_env->getMap().getBlockNoCreate(q.pos);
2149 catch(InvalidPositionException &e)
2154 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2159 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2161 client->SentBlock(q.pos);
2167 void Server::fillMediaCache()
2169 DSTACK(__FUNCTION_NAME);
2171 infostream<<"Server: Calculating media file checksums"<<std::endl;
2173 // Collect all media file paths
2174 std::vector<std::string> paths;
2175 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2176 i != m_mods.end(); i++) {
2177 const ModSpec &mod = *i;
2178 paths.push_back(mod.path + DIR_DELIM + "textures");
2179 paths.push_back(mod.path + DIR_DELIM + "sounds");
2180 paths.push_back(mod.path + DIR_DELIM + "media");
2181 paths.push_back(mod.path + DIR_DELIM + "models");
2183 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2185 // Collect media file information from paths into cache
2186 for(std::vector<std::string>::iterator i = paths.begin();
2187 i != paths.end(); i++) {
2188 std::string mediapath = *i;
2189 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2190 for (u32 j = 0; j < dirlist.size(); j++) {
2191 if (dirlist[j].dir) // Ignode dirs
2193 std::string filename = dirlist[j].name;
2194 // If name contains illegal characters, ignore the file
2195 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2196 infostream<<"Server: ignoring illegal file name: \""
2197 << filename << "\"" << std::endl;
2200 // If name is not in a supported format, ignore it
2201 const char *supported_ext[] = {
2202 ".png", ".jpg", ".bmp", ".tga",
2203 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2205 ".x", ".b3d", ".md2", ".obj",
2208 if (removeStringEnd(filename, supported_ext) == ""){
2209 infostream << "Server: ignoring unsupported file extension: \""
2210 << filename << "\"" << std::endl;
2213 // Ok, attempt to load the file and add to cache
2214 std::string filepath = mediapath + DIR_DELIM + filename;
2216 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2218 errorstream << "Server::fillMediaCache(): Could not open \""
2219 << filename << "\" for reading" << std::endl;
2222 std::ostringstream tmp_os(std::ios_base::binary);
2226 fis.read(buf, 1024);
2227 std::streamsize len = fis.gcount();
2228 tmp_os.write(buf, len);
2237 errorstream<<"Server::fillMediaCache(): Failed to read \""
2238 << filename << "\"" << std::endl;
2241 if(tmp_os.str().length() == 0) {
2242 errorstream << "Server::fillMediaCache(): Empty file \""
2243 << filepath << "\"" << std::endl;
2248 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2250 unsigned char *digest = sha1.getDigest();
2251 std::string sha1_base64 = base64_encode(digest, 20);
2252 std::string sha1_hex = hex_encode((char*)digest, 20);
2256 m_media[filename] = MediaInfo(filepath, sha1_base64);
2257 verbosestream << "Server: " << sha1_hex << " is " << filename
2263 struct SendableMediaAnnouncement
2266 std::string sha1_digest;
2268 SendableMediaAnnouncement(const std::string &name_="",
2269 const std::string &sha1_digest_=""):
2271 sha1_digest(sha1_digest_)
2275 void Server::sendMediaAnnouncement(u16 peer_id)
2277 DSTACK(__FUNCTION_NAME);
2279 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2282 std::vector<SendableMediaAnnouncement> file_announcements;
2284 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2285 i != m_media.end(); i++){
2287 file_announcements.push_back(
2288 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2292 std::ostringstream os(std::ios_base::binary);
2294 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2295 pkt << (u16) file_announcements.size();
2297 for (std::vector<SendableMediaAnnouncement>::iterator
2298 j = file_announcements.begin();
2299 j != file_announcements.end(); ++j) {
2300 pkt << j->name << j->sha1_digest;
2303 pkt << g_settings->get("remote_media");
2307 struct SendableMedia
2313 SendableMedia(const std::string &name_="", const std::string &path_="",
2314 const std::string &data_=""):
2321 void Server::sendRequestedMedia(u16 peer_id,
2322 const std::vector<std::string> &tosend)
2324 DSTACK(__FUNCTION_NAME);
2326 verbosestream<<"Server::sendRequestedMedia(): "
2327 <<"Sending files to client"<<std::endl;
2331 // Put 5kB in one bunch (this is not accurate)
2332 u32 bytes_per_bunch = 5000;
2334 std::vector< std::vector<SendableMedia> > file_bunches;
2335 file_bunches.push_back(std::vector<SendableMedia>());
2337 u32 file_size_bunch_total = 0;
2339 for(std::vector<std::string>::const_iterator i = tosend.begin();
2340 i != tosend.end(); ++i) {
2341 const std::string &name = *i;
2343 if(m_media.find(name) == m_media.end()) {
2344 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2345 <<"unknown file \""<<(name)<<"\""<<std::endl;
2349 //TODO get path + name
2350 std::string tpath = m_media[name].path;
2353 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2354 if(fis.good() == false){
2355 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2356 <<tpath<<"\" for reading"<<std::endl;
2359 std::ostringstream tmp_os(std::ios_base::binary);
2363 fis.read(buf, 1024);
2364 std::streamsize len = fis.gcount();
2365 tmp_os.write(buf, len);
2366 file_size_bunch_total += len;
2375 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2376 <<name<<"\""<<std::endl;
2379 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2380 <<tname<<"\""<<std::endl;*/
2382 file_bunches[file_bunches.size()-1].push_back(
2383 SendableMedia(name, tpath, tmp_os.str()));
2385 // Start next bunch if got enough data
2386 if(file_size_bunch_total >= bytes_per_bunch) {
2387 file_bunches.push_back(std::vector<SendableMedia>());
2388 file_size_bunch_total = 0;
2393 /* Create and send packets */
2395 u16 num_bunches = file_bunches.size();
2396 for(u16 i = 0; i < num_bunches; i++) {
2399 u16 total number of texture bunches
2400 u16 index of this bunch
2401 u32 number of files in this bunch
2410 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2411 pkt << num_bunches << i << (u32) file_bunches[i].size();
2413 for(std::vector<SendableMedia>::iterator
2414 j = file_bunches[i].begin();
2415 j != file_bunches[i].end(); ++j) {
2417 pkt.putLongString(j->data);
2420 verbosestream << "Server::sendRequestedMedia(): bunch "
2421 << i << "/" << num_bunches
2422 << " files=" << file_bunches[i].size()
2423 << " size=" << pkt.getSize() << std::endl;
2428 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2430 if(m_detached_inventories.count(name) == 0) {
2431 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2434 Inventory *inv = m_detached_inventories[name];
2435 std::ostringstream os(std::ios_base::binary);
2437 os << serializeString(name);
2441 std::string s = os.str();
2443 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2444 pkt.putRawString(s.c_str(), s.size());
2446 if (peer_id != PEER_ID_INEXISTENT) {
2450 m_clients.sendToAll(0, &pkt, true);
2454 void Server::sendDetachedInventories(u16 peer_id)
2456 DSTACK(__FUNCTION_NAME);
2458 for(std::map<std::string, Inventory*>::iterator
2459 i = m_detached_inventories.begin();
2460 i != m_detached_inventories.end(); i++) {
2461 const std::string &name = i->first;
2462 //Inventory *inv = i->second;
2463 sendDetachedInventory(name, peer_id);
2471 void Server::DiePlayer(u16 peer_id)
2473 DSTACK(__FUNCTION_NAME);
2475 PlayerSAO *playersao = getPlayerSAO(peer_id);
2478 infostream << "Server::DiePlayer(): Player "
2479 << playersao->getPlayer()->getName()
2480 << " dies" << std::endl;
2482 playersao->setHP(0);
2484 // Trigger scripted stuff
2485 m_script->on_dieplayer(playersao);
2487 SendPlayerHP(peer_id);
2488 SendDeathscreen(peer_id, false, v3f(0,0,0));
2491 void Server::RespawnPlayer(u16 peer_id)
2493 DSTACK(__FUNCTION_NAME);
2495 PlayerSAO *playersao = getPlayerSAO(peer_id);
2498 infostream << "Server::RespawnPlayer(): Player "
2499 << playersao->getPlayer()->getName()
2500 << " respawns" << std::endl;
2502 playersao->setHP(PLAYER_MAX_HP);
2503 playersao->setBreath(PLAYER_MAX_BREATH);
2505 SendPlayerHP(peer_id);
2506 SendPlayerBreath(peer_id);
2508 bool repositioned = m_script->on_respawnplayer(playersao);
2510 v3f pos = findSpawnPos(m_env->getServerMap());
2511 // setPos will send the new position to client
2512 playersao->setPos(pos);
2516 void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
2518 DSTACK(__FUNCTION_NAME);
2520 SendAccessDenied(peer_id, reason, custom_reason);
2521 m_clients.event(peer_id, CSE_SetDenied);
2522 m_con.DisconnectPeer(peer_id);
2525 // 13/03/15: remove this function when protocol version 25 will become
2526 // the minimum version for MT users, maybe in 1 year
2527 void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2529 DSTACK(__FUNCTION_NAME);
2531 SendAccessDenied_Legacy(peer_id, reason);
2532 m_clients.event(peer_id, CSE_SetDenied);
2533 m_con.DisconnectPeer(peer_id);
2536 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2538 DSTACK(__FUNCTION_NAME);
2539 std::wstring message;
2542 Clear references to playing sounds
2544 for(std::map<s32, ServerPlayingSound>::iterator
2545 i = m_playing_sounds.begin();
2546 i != m_playing_sounds.end();)
2548 ServerPlayingSound &psound = i->second;
2549 psound.clients.erase(peer_id);
2550 if(psound.clients.empty())
2551 m_playing_sounds.erase(i++);
2556 Player *player = m_env->getPlayer(peer_id);
2558 // Collect information about leaving in chat
2560 if(player != NULL && reason != CDR_DENY)
2562 std::wstring name = narrow_to_wide(player->getName());
2565 message += L" left the game.";
2566 if(reason == CDR_TIMEOUT)
2567 message += L" (timed out)";
2571 /* Run scripts and remove from environment */
2575 PlayerSAO *playersao = player->getPlayerSAO();
2578 m_script->on_leaveplayer(playersao);
2580 playersao->disconnected();
2588 if(player != NULL && reason != CDR_DENY) {
2589 std::ostringstream os(std::ios_base::binary);
2590 std::vector<u16> clients = m_clients.getClientIDs();
2592 for(std::vector<u16>::iterator i = clients.begin();
2593 i != clients.end(); ++i) {
2595 Player *player = m_env->getPlayer(*i);
2599 // Get name of player
2600 os << player->getName() << " ";
2603 actionstream << player->getName() << " "
2604 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2605 << " List of players: " << os.str() << std::endl;
2609 JMutexAutoLock env_lock(m_env_mutex);
2610 m_clients.DeleteClient(peer_id);
2614 // Send leave chat message to all remaining clients
2615 if(message.length() != 0)
2616 SendChatMessage(PEER_ID_INEXISTENT,message);
2619 void Server::UpdateCrafting(Player* player)
2621 DSTACK(__FUNCTION_NAME);
2623 // Get a preview for crafting
2625 InventoryLocation loc;
2626 loc.setPlayer(player->getName());
2627 getCraftingResult(&player->inventory, preview, false, this);
2628 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2630 // Put the new preview in
2631 InventoryList *plist = player->inventory.getList("craftpreview");
2632 sanity_check(plist);
2633 sanity_check(plist->getSize() >= 1);
2634 plist->changeItem(0, preview);
2637 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2639 RemoteClient *client = getClientNoEx(peer_id,state_min);
2641 throw ClientNotFoundException("Client not found");
2645 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2647 return m_clients.getClientNoEx(peer_id, state_min);
2650 std::string Server::getPlayerName(u16 peer_id)
2652 Player *player = m_env->getPlayer(peer_id);
2654 return "[id="+itos(peer_id)+"]";
2655 return player->getName();
2658 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2660 Player *player = m_env->getPlayer(peer_id);
2663 return player->getPlayerSAO();
2666 std::wstring Server::getStatusString()
2668 std::wostringstream os(std::ios_base::binary);
2671 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2673 os<<L", uptime="<<m_uptime.get();
2675 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2676 // Information about clients
2679 std::vector<u16> clients = m_clients.getClientIDs();
2680 for(std::vector<u16>::iterator i = clients.begin();
2681 i != clients.end(); ++i) {
2683 Player *player = m_env->getPlayer(*i);
2684 // Get name of player
2685 std::wstring name = L"unknown";
2687 name = narrow_to_wide(player->getName());
2688 // Add name to information string
2696 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2697 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2698 if(g_settings->get("motd") != "")
2699 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2703 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2705 std::set<std::string> privs;
2706 m_script->getAuth(name, NULL, &privs);
2710 bool Server::checkPriv(const std::string &name, const std::string &priv)
2712 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2713 return (privs.count(priv) != 0);
2716 void Server::reportPrivsModified(const std::string &name)
2719 std::vector<u16> clients = m_clients.getClientIDs();
2720 for(std::vector<u16>::iterator i = clients.begin();
2721 i != clients.end(); ++i) {
2722 Player *player = m_env->getPlayer(*i);
2723 reportPrivsModified(player->getName());
2726 Player *player = m_env->getPlayer(name.c_str());
2729 SendPlayerPrivileges(player->peer_id);
2730 PlayerSAO *sao = player->getPlayerSAO();
2733 sao->updatePrivileges(
2734 getPlayerEffectivePrivs(name),
2739 void Server::reportInventoryFormspecModified(const std::string &name)
2741 Player *player = m_env->getPlayer(name.c_str());
2744 SendPlayerInventoryFormspec(player->peer_id);
2747 void Server::setIpBanned(const std::string &ip, const std::string &name)
2749 m_banmanager->add(ip, name);
2752 void Server::unsetIpBanned(const std::string &ip_or_name)
2754 m_banmanager->remove(ip_or_name);
2757 std::string Server::getBanDescription(const std::string &ip_or_name)
2759 return m_banmanager->getBanDescription(ip_or_name);
2762 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2764 Player *player = m_env->getPlayer(name);
2768 if (player->peer_id == PEER_ID_INEXISTENT)
2771 SendChatMessage(player->peer_id, msg);
2774 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2776 Player *player = m_env->getPlayer(playername);
2780 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2784 SendShowFormspecMessage(player->peer_id, formspec, formname);
2788 u32 Server::hudAdd(Player *player, HudElement *form) {
2792 u32 id = player->addHud(form);
2794 SendHUDAdd(player->peer_id, id, form);
2799 bool Server::hudRemove(Player *player, u32 id) {
2803 HudElement* todel = player->removeHud(id);
2810 SendHUDRemove(player->peer_id, id);
2814 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2818 SendHUDChange(player->peer_id, id, stat, data);
2822 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2826 SendHUDSetFlags(player->peer_id, flags, mask);
2827 player->hud_flags = flags;
2829 PlayerSAO* playersao = player->getPlayerSAO();
2831 if (playersao == NULL)
2834 m_script->player_event(playersao, "hud_changed");
2838 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2841 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2844 std::ostringstream os(std::ios::binary);
2845 writeS32(os, hotbar_itemcount);
2846 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2850 void Server::hudSetHotbarImage(Player *player, std::string name) {
2854 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2857 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2861 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2864 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2869 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2873 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2878 SendEyeOffset(player->peer_id, first, third);
2882 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2883 const std::string &type, const std::vector<std::string> ¶ms)
2888 SendSetSky(player->peer_id, bgcolor, type, params);
2892 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2898 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2902 void Server::notifyPlayers(const std::wstring &msg)
2904 SendChatMessage(PEER_ID_INEXISTENT,msg);
2907 void Server::spawnParticle(const char *playername, v3f pos,
2908 v3f velocity, v3f acceleration,
2909 float expirationtime, float size, bool
2910 collisiondetection, bool vertical, std::string texture)
2912 Player *player = m_env->getPlayer(playername);
2915 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2916 expirationtime, size, collisiondetection, vertical, texture);
2919 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2920 float expirationtime, float size,
2921 bool collisiondetection, bool vertical, std::string texture)
2923 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2924 expirationtime, size, collisiondetection, vertical, texture);
2927 u32 Server::addParticleSpawner(const char *playername,
2928 u16 amount, float spawntime,
2929 v3f minpos, v3f maxpos,
2930 v3f minvel, v3f maxvel,
2931 v3f minacc, v3f maxacc,
2932 float minexptime, float maxexptime,
2933 float minsize, float maxsize,
2934 bool collisiondetection, bool vertical, std::string texture)
2936 Player *player = m_env->getPlayer(playername);
2941 for(;;) // look for unused particlespawner id
2944 if (std::find(m_particlespawner_ids.begin(),
2945 m_particlespawner_ids.end(), id)
2946 == m_particlespawner_ids.end())
2948 m_particlespawner_ids.push_back(id);
2953 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2954 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2955 minexptime, maxexptime, minsize, maxsize,
2956 collisiondetection, vertical, texture, id);
2961 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2962 v3f minpos, v3f maxpos,
2963 v3f minvel, v3f maxvel,
2964 v3f minacc, v3f maxacc,
2965 float minexptime, float maxexptime,
2966 float minsize, float maxsize,
2967 bool collisiondetection, bool vertical, std::string texture)
2970 for(;;) // look for unused particlespawner id
2973 if (std::find(m_particlespawner_ids.begin(),
2974 m_particlespawner_ids.end(), id)
2975 == m_particlespawner_ids.end())
2977 m_particlespawner_ids.push_back(id);
2982 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2983 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2984 minexptime, maxexptime, minsize, maxsize,
2985 collisiondetection, vertical, texture, id);
2990 void Server::deleteParticleSpawner(const char *playername, u32 id)
2992 Player *player = m_env->getPlayer(playername);
2996 m_particlespawner_ids.erase(
2997 std::remove(m_particlespawner_ids.begin(),
2998 m_particlespawner_ids.end(), id),
2999 m_particlespawner_ids.end());
3000 SendDeleteParticleSpawner(player->peer_id, id);
3003 void Server::deleteParticleSpawnerAll(u32 id)
3005 m_particlespawner_ids.erase(
3006 std::remove(m_particlespawner_ids.begin(),
3007 m_particlespawner_ids.end(), id),
3008 m_particlespawner_ids.end());
3009 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3012 Inventory* Server::createDetachedInventory(const std::string &name)
3014 if(m_detached_inventories.count(name) > 0){
3015 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3016 delete m_detached_inventories[name];
3018 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3020 Inventory *inv = new Inventory(m_itemdef);
3022 m_detached_inventories[name] = inv;
3023 //TODO find a better way to do this
3024 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3031 BoolScopeSet(bool *dst, bool val):
3034 m_orig_state = *m_dst;
3039 *m_dst = m_orig_state;
3046 // actions: time-reversed list
3047 // Return value: success/failure
3048 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3049 std::list<std::string> *log)
3051 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3052 ServerMap *map = (ServerMap*)(&m_env->getMap());
3054 // Fail if no actions to handle
3055 if(actions.empty()){
3056 log->push_back("Nothing to do.");
3063 for(std::list<RollbackAction>::const_iterator
3064 i = actions.begin();
3065 i != actions.end(); i++)
3067 const RollbackAction &action = *i;
3069 bool success = action.applyRevert(map, this, this);
3072 std::ostringstream os;
3073 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3074 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3076 log->push_back(os.str());
3078 std::ostringstream os;
3079 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3080 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3082 log->push_back(os.str());
3086 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3087 <<" failed"<<std::endl;
3089 // Call it done if less than half failed
3090 return num_failed <= num_tried/2;
3093 // IGameDef interface
3095 IItemDefManager* Server::getItemDefManager()
3099 INodeDefManager* Server::getNodeDefManager()
3103 ICraftDefManager* Server::getCraftDefManager()
3107 ITextureSource* Server::getTextureSource()
3111 IShaderSource* Server::getShaderSource()
3115 scene::ISceneManager* Server::getSceneManager()
3120 u16 Server::allocateUnknownNodeId(const std::string &name)
3122 return m_nodedef->allocateDummy(name);
3124 ISoundManager* Server::getSoundManager()
3126 return &dummySoundManager;
3128 MtEventManager* Server::getEventManager()
3133 IWritableItemDefManager* Server::getWritableItemDefManager()
3137 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3141 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3146 const ModSpec* Server::getModSpec(const std::string &modname)
3148 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3149 i != m_mods.end(); i++){
3150 const ModSpec &mod = *i;
3151 if(mod.name == modname)
3156 void Server::getModNames(std::vector<std::string> &modlist)
3158 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3159 modlist.push_back(i->name);
3162 std::string Server::getBuiltinLuaPath()
3164 return porting::path_share + DIR_DELIM + "builtin";
3167 v3f findSpawnPos(ServerMap &map)
3169 //return v3f(50,50,50)*BS;
3174 nodepos = v2s16(0,0);
3179 s16 water_level = map.getWaterLevel();
3181 // Try to find a good place a few times
3182 for(s32 i=0; i<1000; i++)
3185 // We're going to try to throw the player to this position
3186 v2s16 nodepos2d = v2s16(
3187 -range + (myrand() % (range * 2)),
3188 -range + (myrand() % (range * 2)));
3190 // Get ground height at point
3191 s16 groundheight = map.findGroundLevel(nodepos2d);
3192 if (groundheight <= water_level) // Don't go underwater
3194 if (groundheight > water_level + 6) // Don't go to high places
3197 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3198 bool is_good = false;
3200 for (s32 i = 0; i < 10; i++) {
3201 v3s16 blockpos = getNodeBlockPos(nodepos);
3202 map.emergeBlock(blockpos, true);
3203 content_t c = map.getNodeNoEx(nodepos).getContent();
3204 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3206 if (air_count >= 2){
3214 // Found a good place
3215 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3221 return intToFloat(nodepos, BS);
3224 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3226 bool newplayer = false;
3229 Try to get an existing player
3231 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3233 // If player is already connected, cancel
3234 if(player != NULL && player->peer_id != 0)
3236 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3241 If player with the wanted peer_id already exists, cancel.
3243 if(m_env->getPlayer(peer_id) != NULL)
3245 infostream<<"emergePlayer(): Player with wrong name but same"
3246 " peer_id already exists"<<std::endl;
3250 // Load player if it isn't already loaded
3252 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3255 // Create player if it doesn't exist
3258 player = new RemotePlayer(this, name);
3259 // Set player position
3260 infostream<<"Server: Finding spawn place for player \""
3261 <<name<<"\""<<std::endl;
3262 v3f pos = findSpawnPos(m_env->getServerMap());
3263 player->setPosition(pos);
3265 // Make sure the player is saved
3266 player->setModified(true);
3268 // Add player to environment
3269 m_env->addPlayer(player);
3272 // Create a new player active object
3273 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3274 getPlayerEffectivePrivs(player->getName()),
3277 /* Clean up old HUD elements from previous sessions */
3280 /* Add object to environment */
3281 m_env->addActiveObject(playersao);
3285 m_script->on_newplayer(playersao);
3291 void dedicated_server_loop(Server &server, bool &kill)
3293 DSTACK(__FUNCTION_NAME);
3295 verbosestream<<"dedicated_server_loop()"<<std::endl;
3297 IntervalLimiter m_profiler_interval;
3301 float steplen = g_settings->getFloat("dedicated_server_step");
3302 // This is kind of a hack but can be done like this
3303 // because server.step() is very light
3305 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3306 sleep_ms((int)(steplen*1000.0));
3308 server.step(steplen);
3310 if(server.getShutdownRequested() || kill)
3312 infostream<<"Dedicated server quitting"<<std::endl;
3314 if(g_settings->getBool("server_announce"))
3315 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3323 float profiler_print_interval =
3324 g_settings->getFloat("profiler_print_interval");
3325 if(profiler_print_interval != 0)
3327 if(m_profiler_interval.step(steplen, profiler_print_interval))
3329 infostream<<"Profiler:"<<std::endl;
3330 g_profiler->print(infostream);
3331 g_profiler->clear();