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::list<u16> clients = m_clients.getClientIDs();
1379 // Set the modified blocks unsent for all the clients
1380 for (std::list<u16>::iterator
1381 i = clients.begin();
1382 i != clients.end(); ++i) {
1383 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
1385 client->SetBlocksNotSent(block);
1390 void Server::peerAdded(con::Peer *peer)
1392 DSTACK(__FUNCTION_NAME);
1393 verbosestream<<"Server::peerAdded(): peer->id="
1394 <<peer->id<<std::endl;
1397 c.type = con::PEER_ADDED;
1398 c.peer_id = peer->id;
1400 m_peer_change_queue.push_back(c);
1403 void Server::deletingPeer(con::Peer *peer, bool timeout)
1405 DSTACK(__FUNCTION_NAME);
1406 verbosestream<<"Server::deletingPeer(): peer->id="
1407 <<peer->id<<", timeout="<<timeout<<std::endl;
1409 m_clients.event(peer->id, CSE_Disconnect);
1411 c.type = con::PEER_REMOVED;
1412 c.peer_id = peer->id;
1413 c.timeout = timeout;
1414 m_peer_change_queue.push_back(c);
1417 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1419 *retval = m_con.getPeerStat(peer_id,type);
1420 if (*retval == -1) return false;
1424 bool Server::getClientInfo(
1433 std::string* vers_string
1436 *state = m_clients.getClientState(peer_id);
1438 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1440 if (client == NULL) {
1445 *uptime = client->uptime();
1446 *ser_vers = client->serialization_version;
1447 *prot_vers = client->net_proto_version;
1449 *major = client->getMajor();
1450 *minor = client->getMinor();
1451 *patch = client->getPatch();
1452 *vers_string = client->getPatch();
1459 void Server::handlePeerChanges()
1461 while(m_peer_change_queue.size() > 0)
1463 con::PeerChange c = m_peer_change_queue.pop_front();
1465 verbosestream<<"Server: Handling peer change: "
1466 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1471 case con::PEER_ADDED:
1472 m_clients.CreateClient(c.peer_id);
1475 case con::PEER_REMOVED:
1476 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1480 assert("Invalid peer change event received!" == 0);
1486 void Server::Send(NetworkPacket* pkt)
1488 m_clients.send(pkt->getPeerId(),
1489 clientCommandFactoryTable[pkt->getCommand()].channel,
1491 clientCommandFactoryTable[pkt->getCommand()].reliable);
1494 void Server::SendMovement(u16 peer_id)
1496 DSTACK(__FUNCTION_NAME);
1497 std::ostringstream os(std::ios_base::binary);
1499 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1501 *pkt << g_settings->getFloat("movement_acceleration_default");
1502 *pkt << g_settings->getFloat("movement_acceleration_air");
1503 *pkt << g_settings->getFloat("movement_acceleration_fast");
1504 *pkt << g_settings->getFloat("movement_speed_walk");
1505 *pkt << g_settings->getFloat("movement_speed_crouch");
1506 *pkt << g_settings->getFloat("movement_speed_fast");
1507 *pkt << g_settings->getFloat("movement_speed_climb");
1508 *pkt << g_settings->getFloat("movement_speed_jump");
1509 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1510 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1511 *pkt << g_settings->getFloat("movement_liquid_sink");
1512 *pkt << g_settings->getFloat("movement_gravity");
1517 void Server::SendHP(u16 peer_id, u8 hp)
1519 DSTACK(__FUNCTION_NAME);
1521 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1526 void Server::SendBreath(u16 peer_id, u16 breath)
1528 DSTACK(__FUNCTION_NAME);
1530 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1531 *pkt << (u16) breath;
1535 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1537 DSTACK(__FUNCTION_NAME);
1539 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1544 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1545 v3f camera_point_target)
1547 DSTACK(__FUNCTION_NAME);
1549 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1550 *pkt << set_camera_point_target << camera_point_target;
1554 void Server::SendItemDef(u16 peer_id,
1555 IItemDefManager *itemdef, u16 protocol_version)
1557 DSTACK(__FUNCTION_NAME);
1559 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1563 u32 length of the next item
1564 zlib-compressed serialized ItemDefManager
1566 std::ostringstream tmp_os(std::ios::binary);
1567 itemdef->serialize(tmp_os, protocol_version);
1568 std::ostringstream tmp_os2(std::ios::binary);
1569 compressZlib(tmp_os.str(), tmp_os2);
1570 pkt->putLongString(tmp_os2.str());
1573 verbosestream << "Server: Sending item definitions to id(" << peer_id
1574 << "): size=" << pkt->getSize() << std::endl;
1579 void Server::SendNodeDef(u16 peer_id,
1580 INodeDefManager *nodedef, u16 protocol_version)
1582 DSTACK(__FUNCTION_NAME);
1584 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1588 u32 length of the next item
1589 zlib-compressed serialized NodeDefManager
1591 std::ostringstream tmp_os(std::ios::binary);
1592 nodedef->serialize(tmp_os, protocol_version);
1593 std::ostringstream tmp_os2(std::ios::binary);
1594 compressZlib(tmp_os.str(), tmp_os2);
1596 pkt->putLongString(tmp_os2.str());
1599 verbosestream << "Server: Sending node definitions to id(" << peer_id
1600 << "): size=" << pkt->getSize() << std::endl;
1606 Non-static send methods
1609 void Server::SendInventory(PlayerSAO* playerSAO)
1611 DSTACK(__FUNCTION_NAME);
1613 UpdateCrafting(playerSAO->getPlayer());
1619 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1620 playerSAO->getPeerID());
1622 std::ostringstream os;
1623 playerSAO->getInventory()->serialize(os);
1625 std::string s = os.str();
1627 pkt->putRawString(s.c_str(), s.size());
1631 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1633 DSTACK(__FUNCTION_NAME);
1635 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1638 if (peer_id != PEER_ID_INEXISTENT) {
1642 m_clients.sendToAll(0,pkt,true);
1646 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1647 const std::string &formname)
1649 DSTACK(__FUNCTION_NAME);
1651 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1653 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1659 // Spawns a particle on peer with peer_id
1660 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1661 float expirationtime, float size, bool collisiondetection,
1662 bool vertical, std::string texture)
1664 DSTACK(__FUNCTION_NAME);
1666 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1668 *pkt << pos << velocity << acceleration << expirationtime
1669 << size << collisiondetection;
1670 pkt->putLongString(texture);
1673 if (peer_id != PEER_ID_INEXISTENT) {
1677 m_clients.sendToAll(0,pkt,true);
1681 // Adds a ParticleSpawner on peer with peer_id
1682 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1683 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1684 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1686 DSTACK(__FUNCTION_NAME);
1688 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1690 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1691 << minacc << maxacc << minexptime << maxexptime << minsize
1692 << maxsize << collisiondetection;
1694 pkt->putLongString(texture);
1696 *pkt << id << vertical;
1698 if (peer_id != PEER_ID_INEXISTENT) {
1702 m_clients.sendToAll(0, pkt, true);
1706 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1708 DSTACK(__FUNCTION_NAME);
1710 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1712 // Ugly error in this packet
1715 if (peer_id != PEER_ID_INEXISTENT) {
1719 m_clients.sendToAll(0, pkt, true);
1724 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1726 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1728 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1729 << form->text << form->number << form->item << form->dir
1730 << form->align << form->offset << form->world_pos << form->size;
1735 void Server::SendHUDRemove(u16 peer_id, u32 id)
1737 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1742 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1744 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1745 *pkt << id << (u8) stat;
1749 case HUD_STAT_SCALE:
1750 case HUD_STAT_ALIGN:
1751 case HUD_STAT_OFFSET:
1752 *pkt << *(v2f *) value;
1756 *pkt << *(std::string *) value;
1758 case HUD_STAT_WORLD_POS:
1759 *pkt << *(v3f *) value;
1762 *pkt << *(v2s32 *) value;
1764 case HUD_STAT_NUMBER:
1768 *pkt << *(u32 *) value;
1775 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1777 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1779 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1781 *pkt << flags << mask;
1786 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1788 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1789 *pkt << param << value;
1793 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1794 const std::string &type, const std::vector<std::string> ¶ms)
1796 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1797 *pkt << bgcolor << type << (u16) params.size();
1799 for(size_t i=0; i<params.size(); i++)
1805 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1808 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1811 *pkt << do_override << (u16) (ratio * 65535);
1816 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1818 DSTACK(__FUNCTION_NAME);
1820 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1821 *pkt << time << time_speed;
1823 if (peer_id == PEER_ID_INEXISTENT) {
1824 m_clients.sendToAll(0, pkt, true);
1831 void Server::SendPlayerHP(u16 peer_id)
1833 DSTACK(__FUNCTION_NAME);
1834 PlayerSAO *playersao = getPlayerSAO(peer_id);
1836 SendHP(peer_id, playersao->getHP());
1837 m_script->player_event(playersao,"health_changed");
1839 // Send to other clients
1840 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1841 ActiveObjectMessage aom(playersao->getId(), true, str);
1842 playersao->m_messages_out.push_back(aom);
1845 void Server::SendPlayerBreath(u16 peer_id)
1847 DSTACK(__FUNCTION_NAME);
1848 PlayerSAO *playersao = getPlayerSAO(peer_id);
1851 m_script->player_event(playersao, "breath_changed");
1852 SendBreath(peer_id, playersao->getBreath());
1855 void Server::SendMovePlayer(u16 peer_id)
1857 DSTACK(__FUNCTION_NAME);
1858 Player *player = m_env->getPlayer(peer_id);
1861 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1862 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1865 v3f pos = player->getPosition();
1866 f32 pitch = player->getPitch();
1867 f32 yaw = player->getYaw();
1868 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1869 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1878 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1880 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1883 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1884 << animation_frames[3] << animation_speed;
1889 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1891 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1892 *pkt << first << third;
1895 void Server::SendPlayerPrivileges(u16 peer_id)
1897 Player *player = m_env->getPlayer(peer_id);
1899 if(player->peer_id == PEER_ID_INEXISTENT)
1902 std::set<std::string> privs;
1903 m_script->getAuth(player->getName(), NULL, &privs);
1905 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1906 *pkt << (u16) privs.size();
1908 for(std::set<std::string>::const_iterator i = privs.begin();
1909 i != privs.end(); i++) {
1916 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1918 Player *player = m_env->getPlayer(peer_id);
1920 if(player->peer_id == PEER_ID_INEXISTENT)
1923 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1924 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1928 s32 Server::playSound(const SimpleSoundSpec &spec,
1929 const ServerSoundParams ¶ms)
1931 // Find out initial position of sound
1932 bool pos_exists = false;
1933 v3f pos = params.getPos(m_env, &pos_exists);
1934 // If position is not found while it should be, cancel sound
1935 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1938 // Filter destination clients
1939 std::list<u16> dst_clients;
1940 if(params.to_player != "")
1942 Player *player = m_env->getPlayer(params.to_player.c_str());
1944 infostream<<"Server::playSound: Player \""<<params.to_player
1945 <<"\" not found"<<std::endl;
1948 if(player->peer_id == PEER_ID_INEXISTENT){
1949 infostream<<"Server::playSound: Player \""<<params.to_player
1950 <<"\" not connected"<<std::endl;
1953 dst_clients.push_back(player->peer_id);
1957 std::list<u16> clients = m_clients.getClientIDs();
1959 for(std::list<u16>::iterator
1960 i = clients.begin(); i != clients.end(); ++i)
1962 Player *player = m_env->getPlayer(*i);
1966 if(player->getPosition().getDistanceFrom(pos) >
1967 params.max_hear_distance)
1970 dst_clients.push_back(*i);
1973 if(dst_clients.empty())
1977 s32 id = m_next_sound_id++;
1978 // The sound will exist as a reference in m_playing_sounds
1979 m_playing_sounds[id] = ServerPlayingSound();
1980 ServerPlayingSound &psound = m_playing_sounds[id];
1981 psound.params = params;
1982 for(std::list<u16>::iterator i = dst_clients.begin();
1983 i != dst_clients.end(); i++)
1984 psound.clients.insert(*i);
1986 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1987 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1988 << (u8) params.type << pos << params.object << params.loop;
1989 for(std::list<u16>::iterator i = dst_clients.begin();
1990 i != dst_clients.end(); i++) {
1992 m_clients.send(*i, 0, pkt, true, false);
1997 void Server::stopSound(s32 handle)
1999 // Get sound reference
2000 std::map<s32, ServerPlayingSound>::iterator i =
2001 m_playing_sounds.find(handle);
2002 if(i == m_playing_sounds.end())
2004 ServerPlayingSound &psound = i->second;
2006 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2009 for(std::set<u16>::iterator i = psound.clients.begin();
2010 i != psound.clients.end(); i++) {
2012 m_clients.send(*i, 0, pkt, true, false);
2015 // Remove sound reference
2016 m_playing_sounds.erase(i);
2019 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2020 std::list<u16> *far_players, float far_d_nodes)
2022 float maxd = far_d_nodes*BS;
2023 v3f p_f = intToFloat(p, BS);
2025 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2028 std::list<u16> clients = m_clients.getClientIDs();
2029 for(std::list<u16>::iterator
2030 i = clients.begin();
2031 i != clients.end(); ++i) {
2034 if(Player *player = m_env->getPlayer(*i)) {
2035 // If player is far away, only set modified blocks not sent
2036 v3f player_pos = player->getPosition();
2037 if(player_pos.getDistanceFrom(p_f) > maxd) {
2038 far_players->push_back(*i);
2045 m_clients.send(*i, 0, pkt, true, false);
2047 // This loop needs the deletion of the packet here
2051 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2052 std::list<u16> *far_players, float far_d_nodes,
2053 bool remove_metadata)
2055 float maxd = far_d_nodes*BS;
2056 v3f p_f = intToFloat(p, BS);
2058 std::list<u16> clients = m_clients.getClientIDs();
2059 for(std::list<u16>::iterator
2060 i = clients.begin();
2061 i != clients.end(); ++i)
2067 Player *player = m_env->getPlayer(*i);
2070 // If player is far away, only set modified blocks not sent
2071 v3f player_pos = player->getPosition();
2072 if(player_pos.getDistanceFrom(p_f) > maxd)
2074 far_players->push_back(*i);
2080 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2082 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2084 *pkt << p << n.param0 << n.param1 << n.param2
2085 << (u8) (remove_metadata ? 0 : 1);
2087 if (!remove_metadata) {
2088 if (client->net_proto_version <= 21) {
2089 // Old clients always clear metadata; fix it
2090 // by sending the full block again.
2091 client->SetBlockNotSent(p);
2098 if (pkt->getSize() > 0)
2099 m_clients.send(*i, 0, pkt, true);
2103 void Server::setBlockNotSent(v3s16 p)
2105 std::list<u16> clients = m_clients.getClientIDs();
2107 for(std::list<u16>::iterator
2108 i = clients.begin();
2109 i != clients.end(); ++i)
2111 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2112 client->SetBlockNotSent(p);
2117 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2119 DSTACK(__FUNCTION_NAME);
2121 v3s16 p = block->getPos();
2124 Create a packet with the block in the right format
2127 std::ostringstream os(std::ios_base::binary);
2128 block->serialize(os, ver, false);
2129 block->serializeNetworkSpecific(os, net_proto_version);
2130 std::string s = os.str();
2132 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2133 2 + 2 + 2 + 2 + s.size(), peer_id);
2136 pkt->putRawString(s.c_str(), s.size());
2140 void Server::SendBlocks(float dtime)
2142 DSTACK(__FUNCTION_NAME);
2144 JMutexAutoLock envlock(m_env_mutex);
2145 //TODO check if one big lock could be faster then multiple small ones
2147 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2149 std::vector<PrioritySortedBlockTransfer> queue;
2151 s32 total_sending = 0;
2154 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2156 std::list<u16> clients = m_clients.getClientIDs();
2159 for(std::list<u16>::iterator
2160 i = clients.begin();
2161 i != clients.end(); ++i)
2163 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2168 total_sending += client->SendingCount();
2169 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2175 // Lowest priority number comes first.
2176 // Lowest is most important.
2177 std::sort(queue.begin(), queue.end());
2180 for(u32 i=0; i<queue.size(); i++)
2182 //TODO: Calculate limit dynamically
2183 if(total_sending >= g_settings->getS32
2184 ("max_simultaneous_block_sends_server_total"))
2187 PrioritySortedBlockTransfer q = queue[i];
2189 MapBlock *block = NULL;
2192 block = m_env->getMap().getBlockNoCreate(q.pos);
2194 catch(InvalidPositionException &e)
2199 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2204 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2206 client->SentBlock(q.pos);
2212 void Server::fillMediaCache()
2214 DSTACK(__FUNCTION_NAME);
2216 infostream<<"Server: Calculating media file checksums"<<std::endl;
2218 // Collect all media file paths
2219 std::list<std::string> paths;
2220 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2221 i != m_mods.end(); i++){
2222 const ModSpec &mod = *i;
2223 paths.push_back(mod.path + DIR_DELIM + "textures");
2224 paths.push_back(mod.path + DIR_DELIM + "sounds");
2225 paths.push_back(mod.path + DIR_DELIM + "media");
2226 paths.push_back(mod.path + DIR_DELIM + "models");
2228 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2230 // Collect media file information from paths into cache
2231 for(std::list<std::string>::iterator i = paths.begin();
2232 i != paths.end(); i++)
2234 std::string mediapath = *i;
2235 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2236 for(u32 j=0; j<dirlist.size(); j++){
2237 if(dirlist[j].dir) // Ignode dirs
2239 std::string filename = dirlist[j].name;
2240 // If name contains illegal characters, ignore the file
2241 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2242 infostream<<"Server: ignoring illegal file name: \""
2243 <<filename<<"\""<<std::endl;
2246 // If name is not in a supported format, ignore it
2247 const char *supported_ext[] = {
2248 ".png", ".jpg", ".bmp", ".tga",
2249 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2251 ".x", ".b3d", ".md2", ".obj",
2254 if(removeStringEnd(filename, supported_ext) == ""){
2255 infostream<<"Server: ignoring unsupported file extension: \""
2256 <<filename<<"\""<<std::endl;
2259 // Ok, attempt to load the file and add to cache
2260 std::string filepath = mediapath + DIR_DELIM + filename;
2262 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2263 if(fis.good() == false){
2264 errorstream<<"Server::fillMediaCache(): Could not open \""
2265 <<filename<<"\" for reading"<<std::endl;
2268 std::ostringstream tmp_os(std::ios_base::binary);
2272 fis.read(buf, 1024);
2273 std::streamsize len = fis.gcount();
2274 tmp_os.write(buf, len);
2283 errorstream<<"Server::fillMediaCache(): Failed to read \""
2284 <<filename<<"\""<<std::endl;
2287 if(tmp_os.str().length() == 0){
2288 errorstream<<"Server::fillMediaCache(): Empty file \""
2289 <<filepath<<"\""<<std::endl;
2294 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2296 unsigned char *digest = sha1.getDigest();
2297 std::string sha1_base64 = base64_encode(digest, 20);
2298 std::string sha1_hex = hex_encode((char*)digest, 20);
2302 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2303 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2308 struct SendableMediaAnnouncement
2311 std::string sha1_digest;
2313 SendableMediaAnnouncement(const std::string &name_="",
2314 const std::string &sha1_digest_=""):
2316 sha1_digest(sha1_digest_)
2320 void Server::sendMediaAnnouncement(u16 peer_id)
2322 DSTACK(__FUNCTION_NAME);
2324 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2327 std::list<SendableMediaAnnouncement> file_announcements;
2329 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2330 i != m_media.end(); i++){
2332 file_announcements.push_back(
2333 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2337 std::ostringstream os(std::ios_base::binary);
2344 u16 length of sha1_digest
2349 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2350 *pkt << (u16) file_announcements.size();
2352 for(std::list<SendableMediaAnnouncement>::iterator
2353 j = file_announcements.begin();
2354 j != file_announcements.end(); ++j) {
2355 *pkt << j->name << j->sha1_digest;
2358 *pkt << g_settings->get("remote_media");
2362 struct SendableMedia
2368 SendableMedia(const std::string &name_="", const std::string &path_="",
2369 const std::string &data_=""):
2376 void Server::sendRequestedMedia(u16 peer_id,
2377 const std::list<std::string> &tosend)
2379 DSTACK(__FUNCTION_NAME);
2381 verbosestream<<"Server::sendRequestedMedia(): "
2382 <<"Sending files to client"<<std::endl;
2386 // Put 5kB in one bunch (this is not accurate)
2387 u32 bytes_per_bunch = 5000;
2389 std::vector< std::list<SendableMedia> > file_bunches;
2390 file_bunches.push_back(std::list<SendableMedia>());
2392 u32 file_size_bunch_total = 0;
2394 for(std::list<std::string>::const_iterator i = tosend.begin();
2395 i != tosend.end(); ++i)
2397 const std::string &name = *i;
2399 if(m_media.find(name) == m_media.end()) {
2400 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2401 <<"unknown file \""<<(name)<<"\""<<std::endl;
2405 //TODO get path + name
2406 std::string tpath = m_media[name].path;
2409 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2410 if(fis.good() == false){
2411 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2412 <<tpath<<"\" for reading"<<std::endl;
2415 std::ostringstream tmp_os(std::ios_base::binary);
2419 fis.read(buf, 1024);
2420 std::streamsize len = fis.gcount();
2421 tmp_os.write(buf, len);
2422 file_size_bunch_total += len;
2431 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2432 <<name<<"\""<<std::endl;
2435 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2436 <<tname<<"\""<<std::endl;*/
2438 file_bunches[file_bunches.size()-1].push_back(
2439 SendableMedia(name, tpath, tmp_os.str()));
2441 // Start next bunch if got enough data
2442 if(file_size_bunch_total >= bytes_per_bunch) {
2443 file_bunches.push_back(std::list<SendableMedia>());
2444 file_size_bunch_total = 0;
2449 /* Create and send packets */
2451 u16 num_bunches = file_bunches.size();
2452 for(u16 i = 0; i < num_bunches; i++) {
2455 u16 total number of texture bunches
2456 u16 index of this bunch
2457 u32 number of files in this bunch
2466 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2467 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2469 for(std::list<SendableMedia>::iterator
2470 j = file_bunches[i].begin();
2471 j != file_bunches[i].end(); ++j) {
2473 pkt->putLongString(j->data);
2476 verbosestream << "Server::sendRequestedMedia(): bunch "
2477 << i << "/" << num_bunches
2478 << " files=" << file_bunches[i].size()
2479 << " size=" << pkt->getSize() << std::endl;
2484 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2486 if(m_detached_inventories.count(name) == 0) {
2487 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2490 Inventory *inv = m_detached_inventories[name];
2491 std::ostringstream os(std::ios_base::binary);
2493 os << serializeString(name);
2497 std::string s = os.str();
2499 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2500 pkt->putRawString(s.c_str(), s.size());
2502 if (peer_id != PEER_ID_INEXISTENT) {
2506 m_clients.sendToAll(0, pkt, true);
2510 void Server::sendDetachedInventories(u16 peer_id)
2512 DSTACK(__FUNCTION_NAME);
2514 for(std::map<std::string, Inventory*>::iterator
2515 i = m_detached_inventories.begin();
2516 i != m_detached_inventories.end(); i++) {
2517 const std::string &name = i->first;
2518 //Inventory *inv = i->second;
2519 sendDetachedInventory(name, peer_id);
2527 void Server::DiePlayer(u16 peer_id)
2529 DSTACK(__FUNCTION_NAME);
2531 PlayerSAO *playersao = getPlayerSAO(peer_id);
2534 infostream << "Server::DiePlayer(): Player "
2535 << playersao->getPlayer()->getName()
2536 << " dies" << std::endl;
2538 playersao->setHP(0);
2540 // Trigger scripted stuff
2541 m_script->on_dieplayer(playersao);
2543 SendPlayerHP(peer_id);
2544 SendDeathscreen(peer_id, false, v3f(0,0,0));
2547 void Server::RespawnPlayer(u16 peer_id)
2549 DSTACK(__FUNCTION_NAME);
2551 PlayerSAO *playersao = getPlayerSAO(peer_id);
2554 infostream << "Server::RespawnPlayer(): Player "
2555 << playersao->getPlayer()->getName()
2556 << " respawns" << std::endl;
2558 playersao->setHP(PLAYER_MAX_HP);
2559 playersao->setBreath(PLAYER_MAX_BREATH);
2561 SendPlayerHP(peer_id);
2562 SendPlayerBreath(peer_id);
2564 bool repositioned = m_script->on_respawnplayer(playersao);
2566 v3f pos = findSpawnPos(m_env->getServerMap());
2567 // setPos will send the new position to client
2568 playersao->setPos(pos);
2572 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2574 DSTACK(__FUNCTION_NAME);
2576 SendAccessDenied(peer_id, reason);
2577 m_clients.event(peer_id, CSE_SetDenied);
2578 m_con.DisconnectPeer(peer_id);
2581 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2583 DSTACK(__FUNCTION_NAME);
2584 std::wstring message;
2587 Clear references to playing sounds
2589 for(std::map<s32, ServerPlayingSound>::iterator
2590 i = m_playing_sounds.begin();
2591 i != m_playing_sounds.end();)
2593 ServerPlayingSound &psound = i->second;
2594 psound.clients.erase(peer_id);
2595 if(psound.clients.empty())
2596 m_playing_sounds.erase(i++);
2601 Player *player = m_env->getPlayer(peer_id);
2603 // Collect information about leaving in chat
2605 if(player != NULL && reason != CDR_DENY)
2607 std::wstring name = narrow_to_wide(player->getName());
2610 message += L" left the game.";
2611 if(reason == CDR_TIMEOUT)
2612 message += L" (timed out)";
2616 /* Run scripts and remove from environment */
2620 PlayerSAO *playersao = player->getPlayerSAO();
2623 m_script->on_leaveplayer(playersao);
2625 playersao->disconnected();
2633 if(player != NULL && reason != CDR_DENY)
2635 std::ostringstream os(std::ios_base::binary);
2636 std::list<u16> clients = m_clients.getClientIDs();
2638 for(std::list<u16>::iterator
2639 i = clients.begin();
2640 i != clients.end(); ++i)
2643 Player *player = m_env->getPlayer(*i);
2646 // Get name of player
2647 os<<player->getName()<<" ";
2650 actionstream<<player->getName()<<" "
2651 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2652 <<" List of players: "<<os.str()<<std::endl;
2656 JMutexAutoLock env_lock(m_env_mutex);
2657 m_clients.DeleteClient(peer_id);
2661 // Send leave chat message to all remaining clients
2662 if(message.length() != 0)
2663 SendChatMessage(PEER_ID_INEXISTENT,message);
2666 void Server::UpdateCrafting(Player* player)
2668 DSTACK(__FUNCTION_NAME);
2670 // Get a preview for crafting
2672 InventoryLocation loc;
2673 loc.setPlayer(player->getName());
2674 getCraftingResult(&player->inventory, preview, false, this);
2675 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2677 // Put the new preview in
2678 InventoryList *plist = player->inventory.getList("craftpreview");
2680 assert(plist->getSize() >= 1);
2681 plist->changeItem(0, preview);
2684 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2686 RemoteClient *client = getClientNoEx(peer_id,state_min);
2688 throw ClientNotFoundException("Client not found");
2692 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2694 return m_clients.getClientNoEx(peer_id, state_min);
2697 std::string Server::getPlayerName(u16 peer_id)
2699 Player *player = m_env->getPlayer(peer_id);
2701 return "[id="+itos(peer_id)+"]";
2702 return player->getName();
2705 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2707 Player *player = m_env->getPlayer(peer_id);
2710 return player->getPlayerSAO();
2713 std::wstring Server::getStatusString()
2715 std::wostringstream os(std::ios_base::binary);
2718 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2720 os<<L", uptime="<<m_uptime.get();
2722 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2723 // Information about clients
2726 std::list<u16> clients = m_clients.getClientIDs();
2727 for(std::list<u16>::iterator i = clients.begin();
2728 i != clients.end(); ++i)
2731 Player *player = m_env->getPlayer(*i);
2732 // Get name of player
2733 std::wstring name = L"unknown";
2735 name = narrow_to_wide(player->getName());
2736 // Add name to information string
2744 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2745 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2746 if(g_settings->get("motd") != "")
2747 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2751 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2753 std::set<std::string> privs;
2754 m_script->getAuth(name, NULL, &privs);
2758 bool Server::checkPriv(const std::string &name, const std::string &priv)
2760 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2761 return (privs.count(priv) != 0);
2764 void Server::reportPrivsModified(const std::string &name)
2767 std::list<u16> clients = m_clients.getClientIDs();
2768 for(std::list<u16>::iterator
2769 i = clients.begin();
2770 i != clients.end(); ++i){
2771 Player *player = m_env->getPlayer(*i);
2772 reportPrivsModified(player->getName());
2775 Player *player = m_env->getPlayer(name.c_str());
2778 SendPlayerPrivileges(player->peer_id);
2779 PlayerSAO *sao = player->getPlayerSAO();
2782 sao->updatePrivileges(
2783 getPlayerEffectivePrivs(name),
2788 void Server::reportInventoryFormspecModified(const std::string &name)
2790 Player *player = m_env->getPlayer(name.c_str());
2793 SendPlayerInventoryFormspec(player->peer_id);
2796 void Server::setIpBanned(const std::string &ip, const std::string &name)
2798 m_banmanager->add(ip, name);
2801 void Server::unsetIpBanned(const std::string &ip_or_name)
2803 m_banmanager->remove(ip_or_name);
2806 std::string Server::getBanDescription(const std::string &ip_or_name)
2808 return m_banmanager->getBanDescription(ip_or_name);
2811 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2813 Player *player = m_env->getPlayer(name);
2817 if (player->peer_id == PEER_ID_INEXISTENT)
2820 SendChatMessage(player->peer_id, msg);
2823 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2825 Player *player = m_env->getPlayer(playername);
2829 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2833 SendShowFormspecMessage(player->peer_id, formspec, formname);
2837 u32 Server::hudAdd(Player *player, HudElement *form) {
2841 u32 id = player->addHud(form);
2843 SendHUDAdd(player->peer_id, id, form);
2848 bool Server::hudRemove(Player *player, u32 id) {
2852 HudElement* todel = player->removeHud(id);
2859 SendHUDRemove(player->peer_id, id);
2863 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2867 SendHUDChange(player->peer_id, id, stat, data);
2871 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2875 SendHUDSetFlags(player->peer_id, flags, mask);
2876 player->hud_flags = flags;
2878 PlayerSAO* playersao = player->getPlayerSAO();
2880 if (playersao == NULL)
2883 m_script->player_event(playersao, "hud_changed");
2887 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2890 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2893 std::ostringstream os(std::ios::binary);
2894 writeS32(os, hotbar_itemcount);
2895 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2899 void Server::hudSetHotbarImage(Player *player, std::string name) {
2903 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2906 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2910 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2913 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2918 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2922 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2927 SendEyeOffset(player->peer_id, first, third);
2931 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2932 const std::string &type, const std::vector<std::string> ¶ms)
2937 SendSetSky(player->peer_id, bgcolor, type, params);
2941 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2947 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2951 void Server::notifyPlayers(const std::wstring &msg)
2953 SendChatMessage(PEER_ID_INEXISTENT,msg);
2956 void Server::spawnParticle(const char *playername, v3f pos,
2957 v3f velocity, v3f acceleration,
2958 float expirationtime, float size, bool
2959 collisiondetection, bool vertical, std::string texture)
2961 Player *player = m_env->getPlayer(playername);
2964 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2965 expirationtime, size, collisiondetection, vertical, texture);
2968 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2969 float expirationtime, float size,
2970 bool collisiondetection, bool vertical, std::string texture)
2972 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2973 expirationtime, size, collisiondetection, vertical, texture);
2976 u32 Server::addParticleSpawner(const char *playername,
2977 u16 amount, float spawntime,
2978 v3f minpos, v3f maxpos,
2979 v3f minvel, v3f maxvel,
2980 v3f minacc, v3f maxacc,
2981 float minexptime, float maxexptime,
2982 float minsize, float maxsize,
2983 bool collisiondetection, bool vertical, std::string texture)
2985 Player *player = m_env->getPlayer(playername);
2990 for(;;) // look for unused particlespawner id
2993 if (std::find(m_particlespawner_ids.begin(),
2994 m_particlespawner_ids.end(), id)
2995 == m_particlespawner_ids.end())
2997 m_particlespawner_ids.push_back(id);
3002 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3003 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3004 minexptime, maxexptime, minsize, maxsize,
3005 collisiondetection, vertical, texture, id);
3010 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3011 v3f minpos, v3f maxpos,
3012 v3f minvel, v3f maxvel,
3013 v3f minacc, v3f maxacc,
3014 float minexptime, float maxexptime,
3015 float minsize, float maxsize,
3016 bool collisiondetection, bool vertical, std::string texture)
3019 for(;;) // look for unused particlespawner id
3022 if (std::find(m_particlespawner_ids.begin(),
3023 m_particlespawner_ids.end(), id)
3024 == m_particlespawner_ids.end())
3026 m_particlespawner_ids.push_back(id);
3031 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3032 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3033 minexptime, maxexptime, minsize, maxsize,
3034 collisiondetection, vertical, texture, id);
3039 void Server::deleteParticleSpawner(const char *playername, u32 id)
3041 Player *player = m_env->getPlayer(playername);
3045 m_particlespawner_ids.erase(
3046 std::remove(m_particlespawner_ids.begin(),
3047 m_particlespawner_ids.end(), id),
3048 m_particlespawner_ids.end());
3049 SendDeleteParticleSpawner(player->peer_id, id);
3052 void Server::deleteParticleSpawnerAll(u32 id)
3054 m_particlespawner_ids.erase(
3055 std::remove(m_particlespawner_ids.begin(),
3056 m_particlespawner_ids.end(), id),
3057 m_particlespawner_ids.end());
3058 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3061 Inventory* Server::createDetachedInventory(const std::string &name)
3063 if(m_detached_inventories.count(name) > 0){
3064 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3065 delete m_detached_inventories[name];
3067 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3069 Inventory *inv = new Inventory(m_itemdef);
3071 m_detached_inventories[name] = inv;
3072 //TODO find a better way to do this
3073 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3080 BoolScopeSet(bool *dst, bool val):
3083 m_orig_state = *m_dst;
3088 *m_dst = m_orig_state;
3095 // actions: time-reversed list
3096 // Return value: success/failure
3097 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3098 std::list<std::string> *log)
3100 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3101 ServerMap *map = (ServerMap*)(&m_env->getMap());
3103 // Fail if no actions to handle
3104 if(actions.empty()){
3105 log->push_back("Nothing to do.");
3112 for(std::list<RollbackAction>::const_iterator
3113 i = actions.begin();
3114 i != actions.end(); i++)
3116 const RollbackAction &action = *i;
3118 bool success = action.applyRevert(map, this, this);
3121 std::ostringstream os;
3122 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3123 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3125 log->push_back(os.str());
3127 std::ostringstream os;
3128 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3129 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3131 log->push_back(os.str());
3135 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3136 <<" failed"<<std::endl;
3138 // Call it done if less than half failed
3139 return num_failed <= num_tried/2;
3142 // IGameDef interface
3144 IItemDefManager* Server::getItemDefManager()
3148 INodeDefManager* Server::getNodeDefManager()
3152 ICraftDefManager* Server::getCraftDefManager()
3156 ITextureSource* Server::getTextureSource()
3160 IShaderSource* Server::getShaderSource()
3164 scene::ISceneManager* Server::getSceneManager()
3169 u16 Server::allocateUnknownNodeId(const std::string &name)
3171 return m_nodedef->allocateDummy(name);
3173 ISoundManager* Server::getSoundManager()
3175 return &dummySoundManager;
3177 MtEventManager* Server::getEventManager()
3182 IWritableItemDefManager* Server::getWritableItemDefManager()
3186 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3190 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3195 const ModSpec* Server::getModSpec(const std::string &modname)
3197 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3198 i != m_mods.end(); i++){
3199 const ModSpec &mod = *i;
3200 if(mod.name == modname)
3205 void Server::getModNames(std::list<std::string> &modlist)
3207 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3209 modlist.push_back(i->name);
3212 std::string Server::getBuiltinLuaPath()
3214 return porting::path_share + DIR_DELIM + "builtin";
3217 v3f findSpawnPos(ServerMap &map)
3219 //return v3f(50,50,50)*BS;
3224 nodepos = v2s16(0,0);
3229 s16 water_level = map.getWaterLevel();
3231 // Try to find a good place a few times
3232 for(s32 i=0; i<1000; i++)
3235 // We're going to try to throw the player to this position
3236 v2s16 nodepos2d = v2s16(
3237 -range + (myrand() % (range * 2)),
3238 -range + (myrand() % (range * 2)));
3240 // Get ground height at point
3241 s16 groundheight = map.findGroundLevel(nodepos2d);
3242 if (groundheight <= water_level) // Don't go underwater
3244 if (groundheight > water_level + 6) // Don't go to high places
3247 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3248 bool is_good = false;
3250 for (s32 i = 0; i < 10; i++) {
3251 v3s16 blockpos = getNodeBlockPos(nodepos);
3252 map.emergeBlock(blockpos, true);
3253 content_t c = map.getNodeNoEx(nodepos).getContent();
3254 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3256 if (air_count >= 2){
3264 // Found a good place
3265 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3271 return intToFloat(nodepos, BS);
3274 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3276 bool newplayer = false;
3279 Try to get an existing player
3281 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3283 // If player is already connected, cancel
3284 if(player != NULL && player->peer_id != 0)
3286 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3291 If player with the wanted peer_id already exists, cancel.
3293 if(m_env->getPlayer(peer_id) != NULL)
3295 infostream<<"emergePlayer(): Player with wrong name but same"
3296 " peer_id already exists"<<std::endl;
3300 // Load player if it isn't already loaded
3302 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3305 // Create player if it doesn't exist
3308 player = new RemotePlayer(this, name);
3309 // Set player position
3310 infostream<<"Server: Finding spawn place for player \""
3311 <<name<<"\""<<std::endl;
3312 v3f pos = findSpawnPos(m_env->getServerMap());
3313 player->setPosition(pos);
3315 // Make sure the player is saved
3316 player->setModified(true);
3318 // Add player to environment
3319 m_env->addPlayer(player);
3322 // Create a new player active object
3323 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3324 getPlayerEffectivePrivs(player->getName()),
3327 /* Clean up old HUD elements from previous sessions */
3330 /* Add object to environment */
3331 m_env->addActiveObject(playersao);
3335 m_script->on_newplayer(playersao);
3341 void dedicated_server_loop(Server &server, bool &kill)
3343 DSTACK(__FUNCTION_NAME);
3345 verbosestream<<"dedicated_server_loop()"<<std::endl;
3347 IntervalLimiter m_profiler_interval;
3351 float steplen = g_settings->getFloat("dedicated_server_step");
3352 // This is kind of a hack but can be done like this
3353 // because server.step() is very light
3355 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3356 sleep_ms((int)(steplen*1000.0));
3358 server.step(steplen);
3360 if(server.getShutdownRequested() || kill)
3362 infostream<<"Dedicated server quitting"<<std::endl;
3364 if(g_settings->getBool("server_announce"))
3365 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3373 float profiler_print_interval =
3374 g_settings->getFloat("profiler_print_interval");
3375 if(profiler_print_interval != 0)
3377 if(m_profiler_interval.step(steplen, profiler_print_interval))
3379 infostream<<"Profiler:"<<std::endl;
3380 g_profiler->print(infostream);
3381 g_profiler->clear();