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 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 ModConfiguration modconf(m_path_world);
247 m_mods = modconf.getMods();
248 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
249 // complain about mods with unsatisfied dependencies
250 if(!modconf.isConsistent())
252 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
253 it != unsatisfied_mods.end(); ++it)
256 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
257 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
258 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
259 errorstream << " \"" << *dep_it << "\"";
260 errorstream << std::endl;
264 Settings worldmt_settings;
265 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
266 worldmt_settings.readConfigFile(worldmt.c_str());
267 std::vector<std::string> names = worldmt_settings.getNames();
268 std::set<std::string> load_mod_names;
269 for(std::vector<std::string>::iterator it = names.begin();
270 it != names.end(); ++it)
272 std::string name = *it;
273 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
274 load_mod_names.insert(name.substr(9));
276 // complain about mods declared to be loaded, but not found
277 for(std::vector<ModSpec>::iterator it = m_mods.begin();
278 it != m_mods.end(); ++it)
279 load_mod_names.erase((*it).name);
280 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
281 it != unsatisfied_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 if(!load_mod_names.empty())
285 errorstream << "The following mods could not be found:";
286 for(std::set<std::string>::iterator it = load_mod_names.begin();
287 it != load_mod_names.end(); ++it)
288 errorstream << " \"" << (*it) << "\"";
289 errorstream << std::endl;
293 JMutexAutoLock envlock(m_env_mutex);
295 // Load mapgen params from Settings
296 m_emerge->loadMapgenParams();
298 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
299 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
301 // Initialize scripting
302 infostream<<"Server: Initializing Lua"<<std::endl;
304 m_script = new GameScripting(this);
306 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
308 if (!m_script->loadScript(scriptpath))
309 throw ModError("Failed to load and run " + scriptpath);
312 infostream<<"Server: Loading mods: ";
313 for(std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++){
315 const ModSpec &mod = *i;
316 infostream<<mod.name<<" ";
318 infostream<<std::endl;
319 // Load and run "mod" scripts
320 for(std::vector<ModSpec>::iterator i = m_mods.begin();
321 i != m_mods.end(); i++){
322 const ModSpec &mod = *i;
323 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
324 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
325 <<scriptpath<<"\"]"<<std::endl;
326 bool success = m_script->loadMod(scriptpath, mod.name);
328 errorstream<<"Server: Failed to load and run "
329 <<scriptpath<<std::endl;
330 throw ModError("Failed to load and run "+scriptpath);
334 // Read Textures and calculate sha1 sums
337 // Apply item aliases in the node definition manager
338 m_nodedef->updateAliases(m_itemdef);
340 m_nodedef->setNodeRegistrationStatus(true);
342 // Perform pending node name resolutions
343 m_nodedef->runNodeResolverCallbacks();
345 // Initialize Environment
346 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
348 m_clients.setEnv(m_env);
350 // Initialize mapgens
351 m_emerge->initMapgens();
353 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
354 if (m_enable_rollback_recording) {
355 // Create rollback manager
356 m_rollback = new RollbackManager(m_path_world, this);
359 // Give environment reference to scripting api
360 m_script->initializeEnvironment(m_env);
362 // Register us to receive map edit events
363 servermap->addEventReceiver(this);
365 // If file exists, load environment metadata
366 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
368 infostream<<"Server: Loading environment metadata"<<std::endl;
372 // Add some test ActiveBlockModifiers to environment
373 add_legacy_abms(m_env, m_nodedef);
375 m_liquid_transform_every = g_settings->getFloat("liquid_update");
380 infostream<<"Server destructing"<<std::endl;
382 // Send shutdown message
383 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
386 JMutexAutoLock envlock(m_env_mutex);
388 // Execute script shutdown hooks
389 m_script->on_shutdown();
391 infostream<<"Server: Saving players"<<std::endl;
392 m_env->saveLoadedPlayers();
394 infostream<<"Server: Saving environment metadata"<<std::endl;
402 // stop all emerge threads before deleting players that may have
403 // requested blocks to be emerged
404 m_emerge->stopThreads();
406 // Delete things in the reverse order of creation
409 // N.B. the EmergeManager should be deleted after the Environment since Map
410 // depends on EmergeManager to write its current params to the map meta
419 // Deinitialize scripting
420 infostream<<"Server: Deinitializing scripting"<<std::endl;
423 // Delete detached inventories
424 for (std::map<std::string, Inventory*>::iterator
425 i = m_detached_inventories.begin();
426 i != m_detached_inventories.end(); i++) {
431 void Server::start(Address bind_addr)
433 DSTACK(__FUNCTION_NAME);
435 m_bind_addr = bind_addr;
437 infostream<<"Starting server on "
438 << bind_addr.serializeString() <<"..."<<std::endl;
440 // Stop thread if already running
443 // Initialize connection
444 m_con.SetTimeoutMs(30);
445 m_con.Serve(bind_addr);
450 // ASCII art for the win!
452 <<" .__ __ __ "<<std::endl
453 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
454 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
455 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
456 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
457 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
458 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
459 actionstream<<"Server for gameid=\""<<m_gamespec.id
460 <<"\" listening on "<<bind_addr.serializeString()<<":"
461 <<bind_addr.getPort() << "."<<std::endl;
466 DSTACK(__FUNCTION_NAME);
468 infostream<<"Server: Stopping and waiting threads"<<std::endl;
470 // Stop threads (set run=false first so both start stopping)
472 //m_emergethread.setRun(false);
474 //m_emergethread.stop();
476 infostream<<"Server: Threads stopped"<<std::endl;
479 void Server::step(float dtime)
481 DSTACK(__FUNCTION_NAME);
486 JMutexAutoLock lock(m_step_dtime_mutex);
487 m_step_dtime += dtime;
489 // Throw if fatal error occurred in thread
490 std::string async_err = m_async_fatal_error.get();
492 throw ServerError(async_err);
496 void Server::AsyncRunStep(bool initial_step)
498 DSTACK(__FUNCTION_NAME);
500 g_profiler->add("Server::AsyncRunStep (num)", 1);
504 JMutexAutoLock lock1(m_step_dtime_mutex);
505 dtime = m_step_dtime;
509 // Send blocks to clients
513 if((dtime < 0.001) && (initial_step == false))
516 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
518 //infostream<<"Server steps "<<dtime<<std::endl;
519 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
522 JMutexAutoLock lock1(m_step_dtime_mutex);
523 m_step_dtime -= dtime;
530 m_uptime.set(m_uptime.get() + dtime);
536 Update time of day and overall game time
538 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
541 Send to clients at constant intervals
544 m_time_of_day_send_timer -= dtime;
545 if(m_time_of_day_send_timer < 0.0) {
546 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
547 u16 time = m_env->getTimeOfDay();
548 float time_speed = g_settings->getFloat("time_speed");
549 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
553 JMutexAutoLock lock(m_env_mutex);
554 // Figure out and report maximum lag to environment
555 float max_lag = m_env->getMaxLagEstimate();
556 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
558 if(dtime > 0.1 && dtime > max_lag * 2.0)
559 infostream<<"Server: Maximum lag peaked to "<<dtime
563 m_env->reportMaxLagEstimate(max_lag);
565 ScopeProfiler sp(g_profiler, "SEnv step");
566 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
570 static const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 JMutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"));
584 /* Transform liquids */
585 m_liquid_transform_timer += dtime;
586 if(m_liquid_transform_timer >= m_liquid_transform_every)
588 m_liquid_transform_timer -= m_liquid_transform_every;
590 JMutexAutoLock lock(m_env_mutex);
592 ScopeProfiler sp(g_profiler, "Server: liquid transform");
594 std::map<v3s16, MapBlock*> modified_blocks;
595 m_env->getMap().transformLiquids(modified_blocks);
600 core::map<v3s16, MapBlock*> lighting_modified_blocks;
601 ServerMap &map = ((ServerMap&)m_env->getMap());
602 map.updateLighting(modified_blocks, lighting_modified_blocks);
604 // Add blocks modified by lighting to modified_blocks
605 for(core::map<v3s16, MapBlock*>::Iterator
606 i = lighting_modified_blocks.getIterator();
607 i.atEnd() == false; i++)
609 MapBlock *block = i.getNode()->getValue();
610 modified_blocks.insert(block->getPos(), block);
614 Set the modified blocks unsent for all the clients
616 if(!modified_blocks.empty())
618 SetBlocksNotSent(modified_blocks);
621 m_clients.step(dtime);
623 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
625 // send masterserver announce
627 float &counter = m_masterserver_timer;
628 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
629 g_settings->getBool("server_announce"))
631 ServerList::sendAnnounce(counter ? "update" : "start",
632 m_bind_addr.getPort(),
633 m_clients.getPlayerNames(),
635 m_env->getGameTime(),
638 m_emerge->params.mg_name,
647 Check added and deleted active objects
650 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
651 JMutexAutoLock envlock(m_env_mutex);
654 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
655 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
657 // Radius inside which objects are active
658 s16 radius = g_settings->getS16("active_object_send_range_blocks");
659 s16 player_radius = g_settings->getS16("player_transfer_distance");
661 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
662 !g_settings->getBool("unlimited_player_transfer_distance"))
663 player_radius = radius;
665 radius *= MAP_BLOCKSIZE;
666 player_radius *= MAP_BLOCKSIZE;
668 for(std::map<u16, RemoteClient*>::iterator
670 i != clients.end(); ++i)
672 RemoteClient *client = i->second;
674 // If definitions and textures have not been sent, don't
675 // send objects either
676 if (client->getState() < CS_DefinitionsSent)
679 Player *player = m_env->getPlayer(client->peer_id);
682 // This can happen if the client timeouts somehow
683 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
685 <<" has no associated player"<<std::endl;*/
688 v3s16 pos = floatToInt(player->getPosition(), BS);
690 std::set<u16> removed_objects;
691 std::set<u16> added_objects;
692 m_env->getRemovedActiveObjects(pos, radius, player_radius,
693 client->m_known_objects, removed_objects);
694 m_env->getAddedActiveObjects(pos, radius, player_radius,
695 client->m_known_objects, added_objects);
697 // Ignore if nothing happened
698 if(removed_objects.empty() && added_objects.empty())
700 //infostream<<"active objects: none changed"<<std::endl;
704 std::string data_buffer;
708 // Handle removed objects
709 writeU16((u8*)buf, removed_objects.size());
710 data_buffer.append(buf, 2);
711 for(std::set<u16>::iterator
712 i = removed_objects.begin();
713 i != removed_objects.end(); ++i)
717 ServerActiveObject* obj = m_env->getActiveObject(id);
719 // Add to data buffer for sending
720 writeU16((u8*)buf, id);
721 data_buffer.append(buf, 2);
723 // Remove from known objects
724 client->m_known_objects.erase(id);
726 if(obj && obj->m_known_by_count > 0)
727 obj->m_known_by_count--;
730 // Handle added objects
731 writeU16((u8*)buf, added_objects.size());
732 data_buffer.append(buf, 2);
733 for(std::set<u16>::iterator
734 i = added_objects.begin();
735 i != added_objects.end(); ++i)
739 ServerActiveObject* obj = m_env->getActiveObject(id);
742 u8 type = ACTIVEOBJECT_TYPE_INVALID;
744 infostream<<"WARNING: "<<__FUNCTION_NAME
745 <<": NULL object"<<std::endl;
747 type = obj->getSendType();
749 // Add to data buffer for sending
750 writeU16((u8*)buf, id);
751 data_buffer.append(buf, 2);
752 writeU8((u8*)buf, type);
753 data_buffer.append(buf, 1);
756 data_buffer.append(serializeLongString(
757 obj->getClientInitializationData(client->net_proto_version)));
759 data_buffer.append(serializeLongString(""));
761 // Add to known objects
762 client->m_known_objects.insert(id);
765 obj->m_known_by_count++;
768 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
769 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
772 verbosestream << "Server: Sent object remove/add: "
773 << removed_objects.size() << " removed, "
774 << added_objects.size() << " added, "
775 << "packet size is " << pkt->getSize() << std::endl;
786 JMutexAutoLock envlock(m_env_mutex);
787 ScopeProfiler sp(g_profiler, "Server: sending object messages");
790 // Value = data sent by object
791 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
793 // Get active object messages from environment
796 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
800 std::list<ActiveObjectMessage>* message_list = NULL;
801 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
802 n = buffered_messages.find(aom.id);
803 if(n == buffered_messages.end())
805 message_list = new std::list<ActiveObjectMessage>;
806 buffered_messages[aom.id] = message_list;
810 message_list = n->second;
812 message_list->push_back(aom);
816 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
817 // Route data to every client
818 for(std::map<u16, RemoteClient*>::iterator
820 i != clients.end(); ++i)
822 RemoteClient *client = i->second;
823 std::string reliable_data;
824 std::string unreliable_data;
825 // Go through all objects in message buffer
826 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
827 j = buffered_messages.begin();
828 j != buffered_messages.end(); ++j)
830 // If object is not known by client, skip it
832 if(client->m_known_objects.find(id) == client->m_known_objects.end())
834 // Get message list of object
835 std::list<ActiveObjectMessage>* list = j->second;
836 // Go through every message
837 for(std::list<ActiveObjectMessage>::iterator
838 k = list->begin(); k != list->end(); ++k)
840 // Compose the full new data with header
841 ActiveObjectMessage aom = *k;
842 std::string new_data;
845 writeU16((u8*)&buf[0], aom.id);
846 new_data.append(buf, 2);
848 new_data += serializeString(aom.datastring);
849 // Add data to buffer
851 reliable_data += new_data;
853 unreliable_data += new_data;
857 reliable_data and unreliable_data are now ready.
860 if(reliable_data.size() > 0) {
861 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
864 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
868 if(unreliable_data.size() > 0) {
869 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
872 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
878 // Clear buffered_messages
879 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
880 i = buffered_messages.begin();
881 i != buffered_messages.end(); ++i)
888 Send queued-for-sending map edit events.
891 // We will be accessing the environment
892 JMutexAutoLock lock(m_env_mutex);
894 // Don't send too many at a time
897 // Single change sending is disabled if queue size is not small
898 bool disable_single_change_sending = false;
899 if(m_unsent_map_edit_queue.size() >= 4)
900 disable_single_change_sending = true;
902 int event_count = m_unsent_map_edit_queue.size();
904 // We'll log the amount of each
907 while(m_unsent_map_edit_queue.size() != 0)
909 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
911 // Players far away from the change are stored here.
912 // Instead of sending the changes, MapBlocks are set not sent
914 std::list<u16> far_players;
916 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
918 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
919 prof.add("MEET_ADDNODE", 1);
920 if(disable_single_change_sending)
921 sendAddNode(event->p, event->n, event->already_known_by_peer,
922 &far_players, 5, event->type == MEET_ADDNODE);
924 sendAddNode(event->p, event->n, event->already_known_by_peer,
925 &far_players, 30, event->type == MEET_ADDNODE);
927 else if(event->type == MEET_REMOVENODE)
929 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
930 prof.add("MEET_REMOVENODE", 1);
931 if(disable_single_change_sending)
932 sendRemoveNode(event->p, event->already_known_by_peer,
935 sendRemoveNode(event->p, event->already_known_by_peer,
938 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
940 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
941 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
942 setBlockNotSent(event->p);
944 else if(event->type == MEET_OTHER)
946 infostream<<"Server: MEET_OTHER"<<std::endl;
947 prof.add("MEET_OTHER", 1);
948 for(std::set<v3s16>::iterator
949 i = event->modified_blocks.begin();
950 i != event->modified_blocks.end(); ++i)
957 prof.add("unknown", 1);
958 infostream<<"WARNING: Server: Unknown MapEditEvent "
959 <<((u32)event->type)<<std::endl;
963 Set blocks not sent to far players
965 if(!far_players.empty())
967 // Convert list format to that wanted by SetBlocksNotSent
968 std::map<v3s16, MapBlock*> modified_blocks2;
969 for(std::set<v3s16>::iterator
970 i = event->modified_blocks.begin();
971 i != event->modified_blocks.end(); ++i)
973 modified_blocks2[*i] =
974 m_env->getMap().getBlockNoCreateNoEx(*i);
976 // Set blocks not sent
977 for(std::list<u16>::iterator
978 i = far_players.begin();
979 i != far_players.end(); ++i)
982 RemoteClient *client = getClient(peer_id);
985 client->SetBlocksNotSent(modified_blocks2);
991 /*// Don't send too many at a time
993 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
997 if(event_count >= 5){
998 infostream<<"Server: MapEditEvents:"<<std::endl;
999 prof.print(infostream);
1000 } else if(event_count != 0){
1001 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1002 prof.print(verbosestream);
1008 Trigger emergethread (it somehow gets to a non-triggered but
1009 bysy state sometimes)
1012 float &counter = m_emergethread_trigger_timer;
1018 m_emerge->startThreads();
1022 // Save map, players and auth stuff
1024 float &counter = m_savemap_timer;
1026 if(counter >= g_settings->getFloat("server_map_save_interval"))
1029 JMutexAutoLock lock(m_env_mutex);
1031 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1034 if (m_banmanager->isModified()) {
1035 m_banmanager->save();
1038 // Save changed parts of map
1039 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1042 m_env->saveLoadedPlayers();
1044 // Save environment metadata
1050 void Server::Receive()
1052 DSTACK(__FUNCTION_NAME);
1053 SharedBuffer<u8> data;
1057 datasize = m_con.Receive(peer_id,data);
1058 ProcessData(*data, datasize, peer_id);
1060 catch(con::InvalidIncomingDataException &e) {
1061 infostream<<"Server::Receive(): "
1062 "InvalidIncomingDataException: what()="
1063 <<e.what()<<std::endl;
1065 catch(SerializationError &e) {
1066 infostream<<"Server::Receive(): "
1067 "SerializationError: what()="
1068 <<e.what()<<std::endl;
1070 catch(ClientStateError &e) {
1071 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1072 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1073 L"Try reconnecting or updating your client");
1075 catch(con::PeerNotFoundException &e) {
1080 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1082 std::string playername = "";
1083 PlayerSAO *playersao = NULL;
1086 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1087 if (client != NULL) {
1088 playername = client->getName();
1089 playersao = emergePlayer(playername.c_str(), peer_id);
1091 } catch (std::exception &e) {
1097 RemotePlayer *player =
1098 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1100 // If failed, cancel
1101 if((playersao == NULL) || (player == NULL)) {
1102 if(player && player->peer_id != 0) {
1103 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1104 <<" (player allocated to an another client)"<<std::endl;
1105 DenyAccess(peer_id, L"Another client is connected with this "
1106 L"name. If your client closed unexpectedly, try again in "
1109 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1111 DenyAccess(peer_id, L"Could not allocate player.");
1117 Send complete position information
1119 SendMovePlayer(peer_id);
1122 SendPlayerPrivileges(peer_id);
1124 // Send inventory formspec
1125 SendPlayerInventoryFormspec(peer_id);
1128 SendInventory(playersao);
1131 if(g_settings->getBool("enable_damage"))
1132 SendPlayerHP(peer_id);
1135 SendPlayerBreath(peer_id);
1137 // Show death screen if necessary
1139 SendDeathscreen(peer_id, false, v3f(0,0,0));
1141 // Note things in chat if not in simple singleplayer mode
1142 if(!m_simple_singleplayer_mode) {
1143 // Send information about server to player in chat
1144 SendChatMessage(peer_id, getStatusString());
1146 // Send information about joining in chat
1148 std::wstring name = L"unknown";
1149 Player *player = m_env->getPlayer(peer_id);
1151 name = narrow_to_wide(player->getName());
1153 std::wstring message;
1156 message += L" joined the game.";
1157 SendChatMessage(PEER_ID_INEXISTENT,message);
1160 Address addr = getPeerAddress(player->peer_id);
1161 std::string ip_str = addr.serializeString();
1162 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1167 std::vector<std::string> names = m_clients.getPlayerNames();
1169 actionstream<<player->getName() <<" joins game. List of players: ";
1171 for (std::vector<std::string>::iterator i = names.begin();
1172 i != names.end(); i++) {
1173 actionstream << *i << " ";
1176 actionstream << player->getName() <<std::endl;
1181 inline void Server::handleCommand(NetworkPacket* pkt)
1183 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1184 (this->*opHandle.handler)(pkt);
1187 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1189 DSTACK(__FUNCTION_NAME);
1190 // Environment is locked first.
1191 JMutexAutoLock envlock(m_env_mutex);
1193 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1196 Address address = getPeerAddress(peer_id);
1197 std::string addr_s = address.serializeString();
1199 if(m_banmanager->isIpBanned(addr_s)) {
1200 std::string ban_name = m_banmanager->getBanName(addr_s);
1201 infostream << "Server: A banned client tried to connect from "
1202 << addr_s << "; banned name was "
1203 << ban_name << std::endl;
1204 // This actually doesn't seem to transfer to the client
1205 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1206 + narrow_to_wide(ban_name));
1210 catch(con::PeerNotFoundException &e) {
1212 * no peer for this packet found
1213 * most common reason is peer timeout, e.g. peer didn't
1214 * respond for some time, your server was overloaded or
1217 infostream << "Server::ProcessData(): Cancelling: peer "
1218 << peer_id << " not found" << std::endl;
1226 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1228 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1230 // Command must be handled into ToServerCommandHandler
1231 if (command >= TOSERVER_NUM_MSG_TYPES) {
1232 infostream << "Server: Ignoring unknown command "
1233 << command << std::endl;
1236 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1242 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1244 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1245 errorstream << "Server::ProcessData(): Cancelling: Peer"
1246 " serialization format invalid or not initialized."
1247 " Skipping incoming command=" << command << std::endl;
1253 /* Handle commands related to client startup */
1254 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1260 if (m_clients.getClientState(peer_id) < CS_Active) {
1261 if (command == TOSERVER_PLAYERPOS) return;
1263 errorstream << "Got packet command: " << command << " for peer id "
1264 << peer_id << " but client isn't active yet. Dropping packet "
1275 catch(SendFailedException &e) {
1276 errorstream << "Server::ProcessData(): SendFailedException: "
1277 << "what=" << e.what()
1282 void Server::setTimeOfDay(u32 time)
1284 m_env->setTimeOfDay(time);
1285 m_time_of_day_send_timer = 0;
1288 void Server::onMapEditEvent(MapEditEvent *event)
1290 if(m_ignore_map_edit_events)
1292 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1294 MapEditEvent *e = event->clone();
1295 m_unsent_map_edit_queue.push_back(e);
1298 Inventory* Server::getInventory(const InventoryLocation &loc)
1301 case InventoryLocation::UNDEFINED:
1302 case InventoryLocation::CURRENT_PLAYER:
1304 case InventoryLocation::PLAYER:
1306 Player *player = m_env->getPlayer(loc.name.c_str());
1309 PlayerSAO *playersao = player->getPlayerSAO();
1312 return playersao->getInventory();
1315 case InventoryLocation::NODEMETA:
1317 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1320 return meta->getInventory();
1323 case InventoryLocation::DETACHED:
1325 if(m_detached_inventories.count(loc.name) == 0)
1327 return m_detached_inventories[loc.name];
1336 void Server::setInventoryModified(const InventoryLocation &loc)
1339 case InventoryLocation::UNDEFINED:
1341 case InventoryLocation::PLAYER:
1343 Player *player = m_env->getPlayer(loc.name.c_str());
1346 PlayerSAO *playersao = player->getPlayerSAO();
1350 SendInventory(playersao);
1353 case InventoryLocation::NODEMETA:
1355 v3s16 blockpos = getNodeBlockPos(loc.p);
1357 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1359 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1361 setBlockNotSent(blockpos);
1364 case InventoryLocation::DETACHED:
1366 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1375 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1377 std::vector<u16> clients = m_clients.getClientIDs();
1379 // Set the modified blocks unsent for all the clients
1380 for (std::vector<u16>::iterator i = clients.begin();
1381 i != clients.end(); ++i) {
1382 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1383 client->SetBlocksNotSent(block);
1388 void Server::peerAdded(con::Peer *peer)
1390 DSTACK(__FUNCTION_NAME);
1391 verbosestream<<"Server::peerAdded(): peer->id="
1392 <<peer->id<<std::endl;
1395 c.type = con::PEER_ADDED;
1396 c.peer_id = peer->id;
1398 m_peer_change_queue.push_back(c);
1401 void Server::deletingPeer(con::Peer *peer, bool timeout)
1403 DSTACK(__FUNCTION_NAME);
1404 verbosestream<<"Server::deletingPeer(): peer->id="
1405 <<peer->id<<", timeout="<<timeout<<std::endl;
1407 m_clients.event(peer->id, CSE_Disconnect);
1409 c.type = con::PEER_REMOVED;
1410 c.peer_id = peer->id;
1411 c.timeout = timeout;
1412 m_peer_change_queue.push_back(c);
1415 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1417 *retval = m_con.getPeerStat(peer_id,type);
1418 if (*retval == -1) return false;
1422 bool Server::getClientInfo(
1431 std::string* vers_string
1434 *state = m_clients.getClientState(peer_id);
1436 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1438 if (client == NULL) {
1443 *uptime = client->uptime();
1444 *ser_vers = client->serialization_version;
1445 *prot_vers = client->net_proto_version;
1447 *major = client->getMajor();
1448 *minor = client->getMinor();
1449 *patch = client->getPatch();
1450 *vers_string = client->getPatch();
1457 void Server::handlePeerChanges()
1459 while(m_peer_change_queue.size() > 0)
1461 con::PeerChange c = m_peer_change_queue.pop_front();
1463 verbosestream<<"Server: Handling peer change: "
1464 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1469 case con::PEER_ADDED:
1470 m_clients.CreateClient(c.peer_id);
1473 case con::PEER_REMOVED:
1474 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1478 assert("Invalid peer change event received!" == 0);
1484 void Server::Send(NetworkPacket* pkt)
1486 m_clients.send(pkt->getPeerId(),
1487 clientCommandFactoryTable[pkt->getCommand()].channel,
1489 clientCommandFactoryTable[pkt->getCommand()].reliable);
1492 void Server::SendMovement(u16 peer_id)
1494 DSTACK(__FUNCTION_NAME);
1495 std::ostringstream os(std::ios_base::binary);
1497 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1499 *pkt << g_settings->getFloat("movement_acceleration_default");
1500 *pkt << g_settings->getFloat("movement_acceleration_air");
1501 *pkt << g_settings->getFloat("movement_acceleration_fast");
1502 *pkt << g_settings->getFloat("movement_speed_walk");
1503 *pkt << g_settings->getFloat("movement_speed_crouch");
1504 *pkt << g_settings->getFloat("movement_speed_fast");
1505 *pkt << g_settings->getFloat("movement_speed_climb");
1506 *pkt << g_settings->getFloat("movement_speed_jump");
1507 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1508 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1509 *pkt << g_settings->getFloat("movement_liquid_sink");
1510 *pkt << g_settings->getFloat("movement_gravity");
1515 void Server::SendHP(u16 peer_id, u8 hp)
1517 DSTACK(__FUNCTION_NAME);
1519 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1524 void Server::SendBreath(u16 peer_id, u16 breath)
1526 DSTACK(__FUNCTION_NAME);
1528 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1529 *pkt << (u16) breath;
1533 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1535 DSTACK(__FUNCTION_NAME);
1537 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1542 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1543 v3f camera_point_target)
1545 DSTACK(__FUNCTION_NAME);
1547 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1548 *pkt << set_camera_point_target << camera_point_target;
1552 void Server::SendItemDef(u16 peer_id,
1553 IItemDefManager *itemdef, u16 protocol_version)
1555 DSTACK(__FUNCTION_NAME);
1557 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1561 u32 length of the next item
1562 zlib-compressed serialized ItemDefManager
1564 std::ostringstream tmp_os(std::ios::binary);
1565 itemdef->serialize(tmp_os, protocol_version);
1566 std::ostringstream tmp_os2(std::ios::binary);
1567 compressZlib(tmp_os.str(), tmp_os2);
1568 pkt->putLongString(tmp_os2.str());
1571 verbosestream << "Server: Sending item definitions to id(" << peer_id
1572 << "): size=" << pkt->getSize() << std::endl;
1577 void Server::SendNodeDef(u16 peer_id,
1578 INodeDefManager *nodedef, u16 protocol_version)
1580 DSTACK(__FUNCTION_NAME);
1582 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1586 u32 length of the next item
1587 zlib-compressed serialized NodeDefManager
1589 std::ostringstream tmp_os(std::ios::binary);
1590 nodedef->serialize(tmp_os, protocol_version);
1591 std::ostringstream tmp_os2(std::ios::binary);
1592 compressZlib(tmp_os.str(), tmp_os2);
1594 pkt->putLongString(tmp_os2.str());
1597 verbosestream << "Server: Sending node definitions to id(" << peer_id
1598 << "): size=" << pkt->getSize() << std::endl;
1604 Non-static send methods
1607 void Server::SendInventory(PlayerSAO* playerSAO)
1609 DSTACK(__FUNCTION_NAME);
1611 UpdateCrafting(playerSAO->getPlayer());
1617 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1618 playerSAO->getPeerID());
1620 std::ostringstream os;
1621 playerSAO->getInventory()->serialize(os);
1623 std::string s = os.str();
1625 pkt->putRawString(s.c_str(), s.size());
1629 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1631 DSTACK(__FUNCTION_NAME);
1633 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1636 if (peer_id != PEER_ID_INEXISTENT) {
1640 m_clients.sendToAll(0,pkt,true);
1644 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1645 const std::string &formname)
1647 DSTACK(__FUNCTION_NAME);
1649 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1651 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1657 // Spawns a particle on peer with peer_id
1658 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1659 float expirationtime, float size, bool collisiondetection,
1660 bool vertical, std::string texture)
1662 DSTACK(__FUNCTION_NAME);
1664 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1666 *pkt << pos << velocity << acceleration << expirationtime
1667 << size << collisiondetection;
1668 pkt->putLongString(texture);
1671 if (peer_id != PEER_ID_INEXISTENT) {
1675 m_clients.sendToAll(0,pkt,true);
1679 // Adds a ParticleSpawner on peer with peer_id
1680 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1681 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1682 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1684 DSTACK(__FUNCTION_NAME);
1686 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1688 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1689 << minacc << maxacc << minexptime << maxexptime << minsize
1690 << maxsize << collisiondetection;
1692 pkt->putLongString(texture);
1694 *pkt << id << vertical;
1696 if (peer_id != PEER_ID_INEXISTENT) {
1700 m_clients.sendToAll(0, pkt, true);
1704 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1706 DSTACK(__FUNCTION_NAME);
1708 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1710 // Ugly error in this packet
1713 if (peer_id != PEER_ID_INEXISTENT) {
1717 m_clients.sendToAll(0, pkt, true);
1722 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1724 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1726 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1727 << form->text << form->number << form->item << form->dir
1728 << form->align << form->offset << form->world_pos << form->size;
1733 void Server::SendHUDRemove(u16 peer_id, u32 id)
1735 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1740 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1742 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1743 *pkt << id << (u8) stat;
1747 case HUD_STAT_SCALE:
1748 case HUD_STAT_ALIGN:
1749 case HUD_STAT_OFFSET:
1750 *pkt << *(v2f *) value;
1754 *pkt << *(std::string *) value;
1756 case HUD_STAT_WORLD_POS:
1757 *pkt << *(v3f *) value;
1760 *pkt << *(v2s32 *) value;
1762 case HUD_STAT_NUMBER:
1766 *pkt << *(u32 *) value;
1773 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1775 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1777 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1779 *pkt << flags << mask;
1784 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1786 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1787 *pkt << param << value;
1791 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1792 const std::string &type, const std::vector<std::string> ¶ms)
1794 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1795 *pkt << bgcolor << type << (u16) params.size();
1797 for(size_t i=0; i<params.size(); i++)
1803 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1806 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1809 *pkt << do_override << (u16) (ratio * 65535);
1814 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1816 DSTACK(__FUNCTION_NAME);
1818 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1819 *pkt << time << time_speed;
1821 if (peer_id == PEER_ID_INEXISTENT) {
1822 m_clients.sendToAll(0, pkt, true);
1829 void Server::SendPlayerHP(u16 peer_id)
1831 DSTACK(__FUNCTION_NAME);
1832 PlayerSAO *playersao = getPlayerSAO(peer_id);
1834 SendHP(peer_id, playersao->getHP());
1835 m_script->player_event(playersao,"health_changed");
1837 // Send to other clients
1838 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1839 ActiveObjectMessage aom(playersao->getId(), true, str);
1840 playersao->m_messages_out.push_back(aom);
1843 void Server::SendPlayerBreath(u16 peer_id)
1845 DSTACK(__FUNCTION_NAME);
1846 PlayerSAO *playersao = getPlayerSAO(peer_id);
1849 m_script->player_event(playersao, "breath_changed");
1850 SendBreath(peer_id, playersao->getBreath());
1853 void Server::SendMovePlayer(u16 peer_id)
1855 DSTACK(__FUNCTION_NAME);
1856 Player *player = m_env->getPlayer(peer_id);
1859 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1860 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1863 v3f pos = player->getPosition();
1864 f32 pitch = player->getPitch();
1865 f32 yaw = player->getYaw();
1866 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1867 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1876 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1878 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1881 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1882 << animation_frames[3] << animation_speed;
1887 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1889 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1890 *pkt << first << third;
1893 void Server::SendPlayerPrivileges(u16 peer_id)
1895 Player *player = m_env->getPlayer(peer_id);
1897 if(player->peer_id == PEER_ID_INEXISTENT)
1900 std::set<std::string> privs;
1901 m_script->getAuth(player->getName(), NULL, &privs);
1903 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1904 *pkt << (u16) privs.size();
1906 for(std::set<std::string>::const_iterator i = privs.begin();
1907 i != privs.end(); i++) {
1914 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1916 Player *player = m_env->getPlayer(peer_id);
1918 if(player->peer_id == PEER_ID_INEXISTENT)
1921 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1922 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1926 s32 Server::playSound(const SimpleSoundSpec &spec,
1927 const ServerSoundParams ¶ms)
1929 // Find out initial position of sound
1930 bool pos_exists = false;
1931 v3f pos = params.getPos(m_env, &pos_exists);
1932 // If position is not found while it should be, cancel sound
1933 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1936 // Filter destination clients
1937 std::list<u16> dst_clients;
1938 if(params.to_player != "")
1940 Player *player = m_env->getPlayer(params.to_player.c_str());
1942 infostream<<"Server::playSound: Player \""<<params.to_player
1943 <<"\" not found"<<std::endl;
1946 if(player->peer_id == PEER_ID_INEXISTENT){
1947 infostream<<"Server::playSound: Player \""<<params.to_player
1948 <<"\" not connected"<<std::endl;
1951 dst_clients.push_back(player->peer_id);
1955 std::vector<u16> clients = m_clients.getClientIDs();
1957 for(std::vector<u16>::iterator
1958 i = clients.begin(); i != clients.end(); ++i) {
1959 Player *player = m_env->getPlayer(*i);
1964 if(player->getPosition().getDistanceFrom(pos) >
1965 params.max_hear_distance)
1968 dst_clients.push_back(*i);
1972 if(dst_clients.empty())
1976 s32 id = m_next_sound_id++;
1977 // The sound will exist as a reference in m_playing_sounds
1978 m_playing_sounds[id] = ServerPlayingSound();
1979 ServerPlayingSound &psound = m_playing_sounds[id];
1980 psound.params = params;
1981 for(std::list<u16>::iterator i = dst_clients.begin();
1982 i != dst_clients.end(); i++)
1983 psound.clients.insert(*i);
1985 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1986 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1987 << (u8) params.type << pos << params.object << params.loop;
1988 for(std::list<u16>::iterator i = dst_clients.begin();
1989 i != dst_clients.end(); i++) {
1991 m_clients.send(*i, 0, pkt, true, false);
1996 void Server::stopSound(s32 handle)
1998 // Get sound reference
1999 std::map<s32, ServerPlayingSound>::iterator i =
2000 m_playing_sounds.find(handle);
2001 if(i == m_playing_sounds.end())
2003 ServerPlayingSound &psound = i->second;
2005 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2008 for(std::set<u16>::iterator i = psound.clients.begin();
2009 i != psound.clients.end(); i++) {
2011 m_clients.send(*i, 0, pkt, true, false);
2014 // Remove sound reference
2015 m_playing_sounds.erase(i);
2018 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2019 std::list<u16> *far_players, float far_d_nodes)
2021 float maxd = far_d_nodes*BS;
2022 v3f p_f = intToFloat(p, BS);
2024 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2027 std::vector<u16> clients = m_clients.getClientIDs();
2028 for(std::vector<u16>::iterator i = clients.begin();
2029 i != clients.end(); ++i) {
2032 if(Player *player = m_env->getPlayer(*i)) {
2033 // If player is far away, only set modified blocks not sent
2034 v3f player_pos = player->getPosition();
2035 if(player_pos.getDistanceFrom(p_f) > maxd) {
2036 far_players->push_back(*i);
2043 m_clients.send(*i, 0, pkt, true, false);
2045 // This loop needs the deletion of the packet here
2049 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2050 std::list<u16> *far_players, float far_d_nodes,
2051 bool remove_metadata)
2053 float maxd = far_d_nodes*BS;
2054 v3f p_f = intToFloat(p, BS);
2056 std::vector<u16> clients = m_clients.getClientIDs();
2057 for(std::vector<u16>::iterator i = clients.begin();
2058 i != clients.end(); ++i) {
2062 if(Player *player = m_env->getPlayer(*i)) {
2063 // If player is far away, only set modified blocks not sent
2064 v3f player_pos = player->getPosition();
2065 if(player_pos.getDistanceFrom(p_f) > maxd) {
2066 far_players->push_back(*i);
2072 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2074 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2076 *pkt << p << n.param0 << n.param1 << n.param2
2077 << (u8) (remove_metadata ? 0 : 1);
2079 if (!remove_metadata) {
2080 if (client->net_proto_version <= 21) {
2081 // Old clients always clear metadata; fix it
2082 // by sending the full block again.
2083 client->SetBlockNotSent(p);
2090 if (pkt->getSize() > 0)
2091 m_clients.send(*i, 0, pkt, true);
2095 void Server::setBlockNotSent(v3s16 p)
2097 std::vector<u16> clients = m_clients.getClientIDs();
2099 for(std::vector<u16>::iterator i = clients.begin();
2100 i != clients.end(); ++i) {
2101 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2102 client->SetBlockNotSent(p);
2107 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2109 DSTACK(__FUNCTION_NAME);
2111 v3s16 p = block->getPos();
2114 Create a packet with the block in the right format
2117 std::ostringstream os(std::ios_base::binary);
2118 block->serialize(os, ver, false);
2119 block->serializeNetworkSpecific(os, net_proto_version);
2120 std::string s = os.str();
2122 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2123 2 + 2 + 2 + 2 + s.size(), peer_id);
2126 pkt->putRawString(s.c_str(), s.size());
2130 void Server::SendBlocks(float dtime)
2132 DSTACK(__FUNCTION_NAME);
2134 JMutexAutoLock envlock(m_env_mutex);
2135 //TODO check if one big lock could be faster then multiple small ones
2137 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2139 std::vector<PrioritySortedBlockTransfer> queue;
2141 s32 total_sending = 0;
2144 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2146 std::vector<u16> clients = m_clients.getClientIDs();
2149 for(std::vector<u16>::iterator i = clients.begin();
2150 i != clients.end(); ++i) {
2151 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2156 total_sending += client->SendingCount();
2157 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2163 // Lowest priority number comes first.
2164 // Lowest is most important.
2165 std::sort(queue.begin(), queue.end());
2168 for(u32 i=0; i<queue.size(); i++)
2170 //TODO: Calculate limit dynamically
2171 if(total_sending >= g_settings->getS32
2172 ("max_simultaneous_block_sends_server_total"))
2175 PrioritySortedBlockTransfer q = queue[i];
2177 MapBlock *block = NULL;
2180 block = m_env->getMap().getBlockNoCreate(q.pos);
2182 catch(InvalidPositionException &e)
2187 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2192 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2194 client->SentBlock(q.pos);
2200 void Server::fillMediaCache()
2202 DSTACK(__FUNCTION_NAME);
2204 infostream<<"Server: Calculating media file checksums"<<std::endl;
2206 // Collect all media file paths
2207 std::list<std::string> paths;
2208 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2209 i != m_mods.end(); i++){
2210 const ModSpec &mod = *i;
2211 paths.push_back(mod.path + DIR_DELIM + "textures");
2212 paths.push_back(mod.path + DIR_DELIM + "sounds");
2213 paths.push_back(mod.path + DIR_DELIM + "media");
2214 paths.push_back(mod.path + DIR_DELIM + "models");
2216 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2218 // Collect media file information from paths into cache
2219 for(std::list<std::string>::iterator i = paths.begin();
2220 i != paths.end(); i++)
2222 std::string mediapath = *i;
2223 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2224 for(u32 j=0; j<dirlist.size(); j++){
2225 if(dirlist[j].dir) // Ignode dirs
2227 std::string filename = dirlist[j].name;
2228 // If name contains illegal characters, ignore the file
2229 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2230 infostream<<"Server: ignoring illegal file name: \""
2231 <<filename<<"\""<<std::endl;
2234 // If name is not in a supported format, ignore it
2235 const char *supported_ext[] = {
2236 ".png", ".jpg", ".bmp", ".tga",
2237 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2239 ".x", ".b3d", ".md2", ".obj",
2242 if(removeStringEnd(filename, supported_ext) == ""){
2243 infostream<<"Server: ignoring unsupported file extension: \""
2244 <<filename<<"\""<<std::endl;
2247 // Ok, attempt to load the file and add to cache
2248 std::string filepath = mediapath + DIR_DELIM + filename;
2250 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2251 if(fis.good() == false){
2252 errorstream<<"Server::fillMediaCache(): Could not open \""
2253 <<filename<<"\" for reading"<<std::endl;
2256 std::ostringstream tmp_os(std::ios_base::binary);
2260 fis.read(buf, 1024);
2261 std::streamsize len = fis.gcount();
2262 tmp_os.write(buf, len);
2271 errorstream<<"Server::fillMediaCache(): Failed to read \""
2272 <<filename<<"\""<<std::endl;
2275 if(tmp_os.str().length() == 0){
2276 errorstream<<"Server::fillMediaCache(): Empty file \""
2277 <<filepath<<"\""<<std::endl;
2282 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2284 unsigned char *digest = sha1.getDigest();
2285 std::string sha1_base64 = base64_encode(digest, 20);
2286 std::string sha1_hex = hex_encode((char*)digest, 20);
2290 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2291 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2296 struct SendableMediaAnnouncement
2299 std::string sha1_digest;
2301 SendableMediaAnnouncement(const std::string &name_="",
2302 const std::string &sha1_digest_=""):
2304 sha1_digest(sha1_digest_)
2308 void Server::sendMediaAnnouncement(u16 peer_id)
2310 DSTACK(__FUNCTION_NAME);
2312 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2315 std::list<SendableMediaAnnouncement> file_announcements;
2317 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2318 i != m_media.end(); i++){
2320 file_announcements.push_back(
2321 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2325 std::ostringstream os(std::ios_base::binary);
2332 u16 length of sha1_digest
2337 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2338 *pkt << (u16) file_announcements.size();
2340 for(std::list<SendableMediaAnnouncement>::iterator
2341 j = file_announcements.begin();
2342 j != file_announcements.end(); ++j) {
2343 *pkt << j->name << j->sha1_digest;
2346 *pkt << g_settings->get("remote_media");
2350 struct SendableMedia
2356 SendableMedia(const std::string &name_="", const std::string &path_="",
2357 const std::string &data_=""):
2364 void Server::sendRequestedMedia(u16 peer_id,
2365 const std::list<std::string> &tosend)
2367 DSTACK(__FUNCTION_NAME);
2369 verbosestream<<"Server::sendRequestedMedia(): "
2370 <<"Sending files to client"<<std::endl;
2374 // Put 5kB in one bunch (this is not accurate)
2375 u32 bytes_per_bunch = 5000;
2377 std::vector< std::list<SendableMedia> > file_bunches;
2378 file_bunches.push_back(std::list<SendableMedia>());
2380 u32 file_size_bunch_total = 0;
2382 for(std::list<std::string>::const_iterator i = tosend.begin();
2383 i != tosend.end(); ++i)
2385 const std::string &name = *i;
2387 if(m_media.find(name) == m_media.end()) {
2388 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2389 <<"unknown file \""<<(name)<<"\""<<std::endl;
2393 //TODO get path + name
2394 std::string tpath = m_media[name].path;
2397 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2398 if(fis.good() == false){
2399 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2400 <<tpath<<"\" for reading"<<std::endl;
2403 std::ostringstream tmp_os(std::ios_base::binary);
2407 fis.read(buf, 1024);
2408 std::streamsize len = fis.gcount();
2409 tmp_os.write(buf, len);
2410 file_size_bunch_total += len;
2419 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2420 <<name<<"\""<<std::endl;
2423 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2424 <<tname<<"\""<<std::endl;*/
2426 file_bunches[file_bunches.size()-1].push_back(
2427 SendableMedia(name, tpath, tmp_os.str()));
2429 // Start next bunch if got enough data
2430 if(file_size_bunch_total >= bytes_per_bunch) {
2431 file_bunches.push_back(std::list<SendableMedia>());
2432 file_size_bunch_total = 0;
2437 /* Create and send packets */
2439 u16 num_bunches = file_bunches.size();
2440 for(u16 i = 0; i < num_bunches; i++) {
2443 u16 total number of texture bunches
2444 u16 index of this bunch
2445 u32 number of files in this bunch
2454 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2455 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2457 for(std::list<SendableMedia>::iterator
2458 j = file_bunches[i].begin();
2459 j != file_bunches[i].end(); ++j) {
2461 pkt->putLongString(j->data);
2464 verbosestream << "Server::sendRequestedMedia(): bunch "
2465 << i << "/" << num_bunches
2466 << " files=" << file_bunches[i].size()
2467 << " size=" << pkt->getSize() << std::endl;
2472 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2474 if(m_detached_inventories.count(name) == 0) {
2475 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2478 Inventory *inv = m_detached_inventories[name];
2479 std::ostringstream os(std::ios_base::binary);
2481 os << serializeString(name);
2485 std::string s = os.str();
2487 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2488 pkt->putRawString(s.c_str(), s.size());
2490 if (peer_id != PEER_ID_INEXISTENT) {
2494 m_clients.sendToAll(0, pkt, true);
2498 void Server::sendDetachedInventories(u16 peer_id)
2500 DSTACK(__FUNCTION_NAME);
2502 for(std::map<std::string, Inventory*>::iterator
2503 i = m_detached_inventories.begin();
2504 i != m_detached_inventories.end(); i++) {
2505 const std::string &name = i->first;
2506 //Inventory *inv = i->second;
2507 sendDetachedInventory(name, peer_id);
2515 void Server::DiePlayer(u16 peer_id)
2517 DSTACK(__FUNCTION_NAME);
2519 PlayerSAO *playersao = getPlayerSAO(peer_id);
2522 infostream << "Server::DiePlayer(): Player "
2523 << playersao->getPlayer()->getName()
2524 << " dies" << std::endl;
2526 playersao->setHP(0);
2528 // Trigger scripted stuff
2529 m_script->on_dieplayer(playersao);
2531 SendPlayerHP(peer_id);
2532 SendDeathscreen(peer_id, false, v3f(0,0,0));
2535 void Server::RespawnPlayer(u16 peer_id)
2537 DSTACK(__FUNCTION_NAME);
2539 PlayerSAO *playersao = getPlayerSAO(peer_id);
2542 infostream << "Server::RespawnPlayer(): Player "
2543 << playersao->getPlayer()->getName()
2544 << " respawns" << std::endl;
2546 playersao->setHP(PLAYER_MAX_HP);
2547 playersao->setBreath(PLAYER_MAX_BREATH);
2549 SendPlayerHP(peer_id);
2550 SendPlayerBreath(peer_id);
2552 bool repositioned = m_script->on_respawnplayer(playersao);
2554 v3f pos = findSpawnPos(m_env->getServerMap());
2555 // setPos will send the new position to client
2556 playersao->setPos(pos);
2560 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2562 DSTACK(__FUNCTION_NAME);
2564 SendAccessDenied(peer_id, reason);
2565 m_clients.event(peer_id, CSE_SetDenied);
2566 m_con.DisconnectPeer(peer_id);
2569 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2571 DSTACK(__FUNCTION_NAME);
2572 std::wstring message;
2575 Clear references to playing sounds
2577 for(std::map<s32, ServerPlayingSound>::iterator
2578 i = m_playing_sounds.begin();
2579 i != m_playing_sounds.end();)
2581 ServerPlayingSound &psound = i->second;
2582 psound.clients.erase(peer_id);
2583 if(psound.clients.empty())
2584 m_playing_sounds.erase(i++);
2589 Player *player = m_env->getPlayer(peer_id);
2591 // Collect information about leaving in chat
2593 if(player != NULL && reason != CDR_DENY)
2595 std::wstring name = narrow_to_wide(player->getName());
2598 message += L" left the game.";
2599 if(reason == CDR_TIMEOUT)
2600 message += L" (timed out)";
2604 /* Run scripts and remove from environment */
2608 PlayerSAO *playersao = player->getPlayerSAO();
2611 m_script->on_leaveplayer(playersao);
2613 playersao->disconnected();
2621 if(player != NULL && reason != CDR_DENY) {
2622 std::ostringstream os(std::ios_base::binary);
2623 std::vector<u16> clients = m_clients.getClientIDs();
2625 for(std::vector<u16>::iterator i = clients.begin();
2626 i != clients.end(); ++i) {
2628 Player *player = m_env->getPlayer(*i);
2632 // Get name of player
2633 os << player->getName() << " ";
2636 actionstream << player->getName() << " "
2637 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2638 << " List of players: " << os.str() << std::endl;
2642 JMutexAutoLock env_lock(m_env_mutex);
2643 m_clients.DeleteClient(peer_id);
2647 // Send leave chat message to all remaining clients
2648 if(message.length() != 0)
2649 SendChatMessage(PEER_ID_INEXISTENT,message);
2652 void Server::UpdateCrafting(Player* player)
2654 DSTACK(__FUNCTION_NAME);
2656 // Get a preview for crafting
2658 InventoryLocation loc;
2659 loc.setPlayer(player->getName());
2660 getCraftingResult(&player->inventory, preview, false, this);
2661 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2663 // Put the new preview in
2664 InventoryList *plist = player->inventory.getList("craftpreview");
2666 assert(plist->getSize() >= 1);
2667 plist->changeItem(0, preview);
2670 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2672 RemoteClient *client = getClientNoEx(peer_id,state_min);
2674 throw ClientNotFoundException("Client not found");
2678 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2680 return m_clients.getClientNoEx(peer_id, state_min);
2683 std::string Server::getPlayerName(u16 peer_id)
2685 Player *player = m_env->getPlayer(peer_id);
2687 return "[id="+itos(peer_id)+"]";
2688 return player->getName();
2691 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2693 Player *player = m_env->getPlayer(peer_id);
2696 return player->getPlayerSAO();
2699 std::wstring Server::getStatusString()
2701 std::wostringstream os(std::ios_base::binary);
2704 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2706 os<<L", uptime="<<m_uptime.get();
2708 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2709 // Information about clients
2712 std::vector<u16> clients = m_clients.getClientIDs();
2713 for(std::vector<u16>::iterator i = clients.begin();
2714 i != clients.end(); ++i) {
2716 Player *player = m_env->getPlayer(*i);
2717 // Get name of player
2718 std::wstring name = L"unknown";
2720 name = narrow_to_wide(player->getName());
2721 // Add name to information string
2729 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2730 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2731 if(g_settings->get("motd") != "")
2732 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2736 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2738 std::set<std::string> privs;
2739 m_script->getAuth(name, NULL, &privs);
2743 bool Server::checkPriv(const std::string &name, const std::string &priv)
2745 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2746 return (privs.count(priv) != 0);
2749 void Server::reportPrivsModified(const std::string &name)
2752 std::vector<u16> clients = m_clients.getClientIDs();
2753 for(std::vector<u16>::iterator i = clients.begin();
2754 i != clients.end(); ++i) {
2755 Player *player = m_env->getPlayer(*i);
2756 reportPrivsModified(player->getName());
2759 Player *player = m_env->getPlayer(name.c_str());
2762 SendPlayerPrivileges(player->peer_id);
2763 PlayerSAO *sao = player->getPlayerSAO();
2766 sao->updatePrivileges(
2767 getPlayerEffectivePrivs(name),
2772 void Server::reportInventoryFormspecModified(const std::string &name)
2774 Player *player = m_env->getPlayer(name.c_str());
2777 SendPlayerInventoryFormspec(player->peer_id);
2780 void Server::setIpBanned(const std::string &ip, const std::string &name)
2782 m_banmanager->add(ip, name);
2785 void Server::unsetIpBanned(const std::string &ip_or_name)
2787 m_banmanager->remove(ip_or_name);
2790 std::string Server::getBanDescription(const std::string &ip_or_name)
2792 return m_banmanager->getBanDescription(ip_or_name);
2795 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2797 Player *player = m_env->getPlayer(name);
2801 if (player->peer_id == PEER_ID_INEXISTENT)
2804 SendChatMessage(player->peer_id, msg);
2807 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2809 Player *player = m_env->getPlayer(playername);
2813 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2817 SendShowFormspecMessage(player->peer_id, formspec, formname);
2821 u32 Server::hudAdd(Player *player, HudElement *form) {
2825 u32 id = player->addHud(form);
2827 SendHUDAdd(player->peer_id, id, form);
2832 bool Server::hudRemove(Player *player, u32 id) {
2836 HudElement* todel = player->removeHud(id);
2843 SendHUDRemove(player->peer_id, id);
2847 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2851 SendHUDChange(player->peer_id, id, stat, data);
2855 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2859 SendHUDSetFlags(player->peer_id, flags, mask);
2860 player->hud_flags = flags;
2862 PlayerSAO* playersao = player->getPlayerSAO();
2864 if (playersao == NULL)
2867 m_script->player_event(playersao, "hud_changed");
2871 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2874 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2877 std::ostringstream os(std::ios::binary);
2878 writeS32(os, hotbar_itemcount);
2879 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2883 void Server::hudSetHotbarImage(Player *player, std::string name) {
2887 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2890 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2894 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2897 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2902 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2906 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2911 SendEyeOffset(player->peer_id, first, third);
2915 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2916 const std::string &type, const std::vector<std::string> ¶ms)
2921 SendSetSky(player->peer_id, bgcolor, type, params);
2925 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2931 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2935 void Server::notifyPlayers(const std::wstring &msg)
2937 SendChatMessage(PEER_ID_INEXISTENT,msg);
2940 void Server::spawnParticle(const char *playername, v3f pos,
2941 v3f velocity, v3f acceleration,
2942 float expirationtime, float size, bool
2943 collisiondetection, bool vertical, std::string texture)
2945 Player *player = m_env->getPlayer(playername);
2948 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2949 expirationtime, size, collisiondetection, vertical, texture);
2952 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2953 float expirationtime, float size,
2954 bool collisiondetection, bool vertical, std::string texture)
2956 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2957 expirationtime, size, collisiondetection, vertical, texture);
2960 u32 Server::addParticleSpawner(const char *playername,
2961 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)
2969 Player *player = m_env->getPlayer(playername);
2974 for(;;) // look for unused particlespawner id
2977 if (std::find(m_particlespawner_ids.begin(),
2978 m_particlespawner_ids.end(), id)
2979 == m_particlespawner_ids.end())
2981 m_particlespawner_ids.push_back(id);
2986 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2987 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2988 minexptime, maxexptime, minsize, maxsize,
2989 collisiondetection, vertical, texture, id);
2994 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2995 v3f minpos, v3f maxpos,
2996 v3f minvel, v3f maxvel,
2997 v3f minacc, v3f maxacc,
2998 float minexptime, float maxexptime,
2999 float minsize, float maxsize,
3000 bool collisiondetection, bool vertical, std::string texture)
3003 for(;;) // look for unused particlespawner id
3006 if (std::find(m_particlespawner_ids.begin(),
3007 m_particlespawner_ids.end(), id)
3008 == m_particlespawner_ids.end())
3010 m_particlespawner_ids.push_back(id);
3015 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3016 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3017 minexptime, maxexptime, minsize, maxsize,
3018 collisiondetection, vertical, texture, id);
3023 void Server::deleteParticleSpawner(const char *playername, u32 id)
3025 Player *player = m_env->getPlayer(playername);
3029 m_particlespawner_ids.erase(
3030 std::remove(m_particlespawner_ids.begin(),
3031 m_particlespawner_ids.end(), id),
3032 m_particlespawner_ids.end());
3033 SendDeleteParticleSpawner(player->peer_id, id);
3036 void Server::deleteParticleSpawnerAll(u32 id)
3038 m_particlespawner_ids.erase(
3039 std::remove(m_particlespawner_ids.begin(),
3040 m_particlespawner_ids.end(), id),
3041 m_particlespawner_ids.end());
3042 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3045 Inventory* Server::createDetachedInventory(const std::string &name)
3047 if(m_detached_inventories.count(name) > 0){
3048 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3049 delete m_detached_inventories[name];
3051 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3053 Inventory *inv = new Inventory(m_itemdef);
3055 m_detached_inventories[name] = inv;
3056 //TODO find a better way to do this
3057 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3064 BoolScopeSet(bool *dst, bool val):
3067 m_orig_state = *m_dst;
3072 *m_dst = m_orig_state;
3079 // actions: time-reversed list
3080 // Return value: success/failure
3081 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3082 std::list<std::string> *log)
3084 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3085 ServerMap *map = (ServerMap*)(&m_env->getMap());
3087 // Fail if no actions to handle
3088 if(actions.empty()){
3089 log->push_back("Nothing to do.");
3096 for(std::list<RollbackAction>::const_iterator
3097 i = actions.begin();
3098 i != actions.end(); i++)
3100 const RollbackAction &action = *i;
3102 bool success = action.applyRevert(map, this, this);
3105 std::ostringstream os;
3106 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3107 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3109 log->push_back(os.str());
3111 std::ostringstream os;
3112 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3113 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3115 log->push_back(os.str());
3119 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3120 <<" failed"<<std::endl;
3122 // Call it done if less than half failed
3123 return num_failed <= num_tried/2;
3126 // IGameDef interface
3128 IItemDefManager* Server::getItemDefManager()
3132 INodeDefManager* Server::getNodeDefManager()
3136 ICraftDefManager* Server::getCraftDefManager()
3140 ITextureSource* Server::getTextureSource()
3144 IShaderSource* Server::getShaderSource()
3148 scene::ISceneManager* Server::getSceneManager()
3153 u16 Server::allocateUnknownNodeId(const std::string &name)
3155 return m_nodedef->allocateDummy(name);
3157 ISoundManager* Server::getSoundManager()
3159 return &dummySoundManager;
3161 MtEventManager* Server::getEventManager()
3166 IWritableItemDefManager* Server::getWritableItemDefManager()
3170 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3174 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3179 const ModSpec* Server::getModSpec(const std::string &modname)
3181 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3182 i != m_mods.end(); i++){
3183 const ModSpec &mod = *i;
3184 if(mod.name == modname)
3189 void Server::getModNames(std::list<std::string> &modlist)
3191 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3193 modlist.push_back(i->name);
3196 std::string Server::getBuiltinLuaPath()
3198 return porting::path_share + DIR_DELIM + "builtin";
3201 v3f findSpawnPos(ServerMap &map)
3203 //return v3f(50,50,50)*BS;
3208 nodepos = v2s16(0,0);
3213 s16 water_level = map.getWaterLevel();
3215 // Try to find a good place a few times
3216 for(s32 i=0; i<1000; i++)
3219 // We're going to try to throw the player to this position
3220 v2s16 nodepos2d = v2s16(
3221 -range + (myrand() % (range * 2)),
3222 -range + (myrand() % (range * 2)));
3224 // Get ground height at point
3225 s16 groundheight = map.findGroundLevel(nodepos2d);
3226 if (groundheight <= water_level) // Don't go underwater
3228 if (groundheight > water_level + 6) // Don't go to high places
3231 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3232 bool is_good = false;
3234 for (s32 i = 0; i < 10; i++) {
3235 v3s16 blockpos = getNodeBlockPos(nodepos);
3236 map.emergeBlock(blockpos, true);
3237 content_t c = map.getNodeNoEx(nodepos).getContent();
3238 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3240 if (air_count >= 2){
3248 // Found a good place
3249 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3255 return intToFloat(nodepos, BS);
3258 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3260 bool newplayer = false;
3263 Try to get an existing player
3265 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3267 // If player is already connected, cancel
3268 if(player != NULL && player->peer_id != 0)
3270 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3275 If player with the wanted peer_id already exists, cancel.
3277 if(m_env->getPlayer(peer_id) != NULL)
3279 infostream<<"emergePlayer(): Player with wrong name but same"
3280 " peer_id already exists"<<std::endl;
3284 // Load player if it isn't already loaded
3286 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3289 // Create player if it doesn't exist
3292 player = new RemotePlayer(this, name);
3293 // Set player position
3294 infostream<<"Server: Finding spawn place for player \""
3295 <<name<<"\""<<std::endl;
3296 v3f pos = findSpawnPos(m_env->getServerMap());
3297 player->setPosition(pos);
3299 // Make sure the player is saved
3300 player->setModified(true);
3302 // Add player to environment
3303 m_env->addPlayer(player);
3306 // Create a new player active object
3307 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3308 getPlayerEffectivePrivs(player->getName()),
3311 /* Clean up old HUD elements from previous sessions */
3314 /* Add object to environment */
3315 m_env->addActiveObject(playersao);
3319 m_script->on_newplayer(playersao);
3325 void dedicated_server_loop(Server &server, bool &kill)
3327 DSTACK(__FUNCTION_NAME);
3329 verbosestream<<"dedicated_server_loop()"<<std::endl;
3331 IntervalLimiter m_profiler_interval;
3335 float steplen = g_settings->getFloat("dedicated_server_step");
3336 // This is kind of a hack but can be done like this
3337 // because server.step() is very light
3339 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3340 sleep_ms((int)(steplen*1000.0));
3342 server.step(steplen);
3344 if(server.getShutdownRequested() || kill)
3346 infostream<<"Dedicated server quitting"<<std::endl;
3348 if(g_settings->getBool("server_announce"))
3349 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3357 float profiler_print_interval =
3358 g_settings->getFloat("profiler_print_interval");
3359 if(profiler_print_interval != 0)
3361 if(m_profiler_interval.step(steplen, profiler_print_interval))
3363 infostream<<"Profiler:"<<std::endl;
3364 g_profiler->print(infostream);
3365 g_profiler->clear();