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.front();
910 m_unsent_map_edit_queue.pop();
912 // Players far away from the change are stored here.
913 // Instead of sending the changes, MapBlocks are set not sent
915 std::list<u16> far_players;
917 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
919 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
920 prof.add("MEET_ADDNODE", 1);
921 if(disable_single_change_sending)
922 sendAddNode(event->p, event->n, event->already_known_by_peer,
923 &far_players, 5, event->type == MEET_ADDNODE);
925 sendAddNode(event->p, event->n, event->already_known_by_peer,
926 &far_players, 30, event->type == MEET_ADDNODE);
928 else if(event->type == MEET_REMOVENODE)
930 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
931 prof.add("MEET_REMOVENODE", 1);
932 if(disable_single_change_sending)
933 sendRemoveNode(event->p, event->already_known_by_peer,
936 sendRemoveNode(event->p, event->already_known_by_peer,
939 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
941 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
942 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
943 setBlockNotSent(event->p);
945 else if(event->type == MEET_OTHER)
947 infostream<<"Server: MEET_OTHER"<<std::endl;
948 prof.add("MEET_OTHER", 1);
949 for(std::set<v3s16>::iterator
950 i = event->modified_blocks.begin();
951 i != event->modified_blocks.end(); ++i)
958 prof.add("unknown", 1);
959 infostream<<"WARNING: Server: Unknown MapEditEvent "
960 <<((u32)event->type)<<std::endl;
964 Set blocks not sent to far players
966 if(!far_players.empty())
968 // Convert list format to that wanted by SetBlocksNotSent
969 std::map<v3s16, MapBlock*> modified_blocks2;
970 for(std::set<v3s16>::iterator
971 i = event->modified_blocks.begin();
972 i != event->modified_blocks.end(); ++i)
974 modified_blocks2[*i] =
975 m_env->getMap().getBlockNoCreateNoEx(*i);
977 // Set blocks not sent
978 for(std::list<u16>::iterator
979 i = far_players.begin();
980 i != far_players.end(); ++i)
983 RemoteClient *client = getClient(peer_id);
986 client->SetBlocksNotSent(modified_blocks2);
992 /*// Don't send too many at a time
994 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
998 if(event_count >= 5){
999 infostream<<"Server: MapEditEvents:"<<std::endl;
1000 prof.print(infostream);
1001 } else if(event_count != 0){
1002 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1003 prof.print(verbosestream);
1009 Trigger emergethread (it somehow gets to a non-triggered but
1010 bysy state sometimes)
1013 float &counter = m_emergethread_trigger_timer;
1019 m_emerge->startThreads();
1023 // Save map, players and auth stuff
1025 float &counter = m_savemap_timer;
1027 if(counter >= g_settings->getFloat("server_map_save_interval"))
1030 JMutexAutoLock lock(m_env_mutex);
1032 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1035 if (m_banmanager->isModified()) {
1036 m_banmanager->save();
1039 // Save changed parts of map
1040 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1043 m_env->saveLoadedPlayers();
1045 // Save environment metadata
1051 void Server::Receive()
1053 DSTACK(__FUNCTION_NAME);
1054 SharedBuffer<u8> data;
1058 datasize = m_con.Receive(peer_id,data);
1059 ProcessData(*data, datasize, peer_id);
1061 catch(con::InvalidIncomingDataException &e) {
1062 infostream<<"Server::Receive(): "
1063 "InvalidIncomingDataException: what()="
1064 <<e.what()<<std::endl;
1066 catch(SerializationError &e) {
1067 infostream<<"Server::Receive(): "
1068 "SerializationError: what()="
1069 <<e.what()<<std::endl;
1071 catch(ClientStateError &e) {
1072 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1073 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1074 L"Try reconnecting or updating your client");
1076 catch(con::PeerNotFoundException &e) {
1081 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1083 std::string playername = "";
1084 PlayerSAO *playersao = NULL;
1087 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1088 if (client != NULL) {
1089 playername = client->getName();
1090 playersao = emergePlayer(playername.c_str(), peer_id);
1092 } catch (std::exception &e) {
1098 RemotePlayer *player =
1099 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1101 // If failed, cancel
1102 if((playersao == NULL) || (player == NULL)) {
1103 if(player && player->peer_id != 0) {
1104 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1105 <<" (player allocated to an another client)"<<std::endl;
1106 DenyAccess(peer_id, L"Another client is connected with this "
1107 L"name. If your client closed unexpectedly, try again in "
1110 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1112 DenyAccess(peer_id, L"Could not allocate player.");
1118 Send complete position information
1120 SendMovePlayer(peer_id);
1123 SendPlayerPrivileges(peer_id);
1125 // Send inventory formspec
1126 SendPlayerInventoryFormspec(peer_id);
1129 SendInventory(playersao);
1132 if(g_settings->getBool("enable_damage"))
1133 SendPlayerHP(peer_id);
1136 SendPlayerBreath(peer_id);
1138 // Show death screen if necessary
1140 SendDeathscreen(peer_id, false, v3f(0,0,0));
1142 // Note things in chat if not in simple singleplayer mode
1143 if(!m_simple_singleplayer_mode) {
1144 // Send information about server to player in chat
1145 SendChatMessage(peer_id, getStatusString());
1147 // Send information about joining in chat
1149 std::wstring name = L"unknown";
1150 Player *player = m_env->getPlayer(peer_id);
1152 name = narrow_to_wide(player->getName());
1154 std::wstring message;
1157 message += L" joined the game.";
1158 SendChatMessage(PEER_ID_INEXISTENT,message);
1161 Address addr = getPeerAddress(player->peer_id);
1162 std::string ip_str = addr.serializeString();
1163 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1168 std::vector<std::string> names = m_clients.getPlayerNames();
1170 actionstream<<player->getName() <<" joins game. List of players: ";
1172 for (std::vector<std::string>::iterator i = names.begin();
1173 i != names.end(); i++) {
1174 actionstream << *i << " ";
1177 actionstream << player->getName() <<std::endl;
1182 inline void Server::handleCommand(NetworkPacket* pkt)
1184 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1185 (this->*opHandle.handler)(pkt);
1188 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1190 DSTACK(__FUNCTION_NAME);
1191 // Environment is locked first.
1192 JMutexAutoLock envlock(m_env_mutex);
1194 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1197 Address address = getPeerAddress(peer_id);
1198 std::string addr_s = address.serializeString();
1200 if(m_banmanager->isIpBanned(addr_s)) {
1201 std::string ban_name = m_banmanager->getBanName(addr_s);
1202 infostream << "Server: A banned client tried to connect from "
1203 << addr_s << "; banned name was "
1204 << ban_name << std::endl;
1205 // This actually doesn't seem to transfer to the client
1206 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1207 + narrow_to_wide(ban_name));
1211 catch(con::PeerNotFoundException &e) {
1213 * no peer for this packet found
1214 * most common reason is peer timeout, e.g. peer didn't
1215 * respond for some time, your server was overloaded or
1218 infostream << "Server::ProcessData(): Cancelling: peer "
1219 << peer_id << " not found" << std::endl;
1227 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1229 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1231 // Command must be handled into ToServerCommandHandler
1232 if (command >= TOSERVER_NUM_MSG_TYPES) {
1233 infostream << "Server: Ignoring unknown command "
1234 << command << std::endl;
1237 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1243 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1245 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1246 errorstream << "Server::ProcessData(): Cancelling: Peer"
1247 " serialization format invalid or not initialized."
1248 " Skipping incoming command=" << command << std::endl;
1254 /* Handle commands related to client startup */
1255 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1261 if (m_clients.getClientState(peer_id) < CS_Active) {
1262 if (command == TOSERVER_PLAYERPOS) return;
1264 errorstream << "Got packet command: " << command << " for peer id "
1265 << peer_id << " but client isn't active yet. Dropping packet "
1276 catch(SendFailedException &e) {
1277 errorstream << "Server::ProcessData(): SendFailedException: "
1278 << "what=" << e.what()
1283 void Server::setTimeOfDay(u32 time)
1285 m_env->setTimeOfDay(time);
1286 m_time_of_day_send_timer = 0;
1289 void Server::onMapEditEvent(MapEditEvent *event)
1291 if(m_ignore_map_edit_events)
1293 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1295 MapEditEvent *e = event->clone();
1296 m_unsent_map_edit_queue.push(e);
1299 Inventory* Server::getInventory(const InventoryLocation &loc)
1302 case InventoryLocation::UNDEFINED:
1303 case InventoryLocation::CURRENT_PLAYER:
1305 case InventoryLocation::PLAYER:
1307 Player *player = m_env->getPlayer(loc.name.c_str());
1310 PlayerSAO *playersao = player->getPlayerSAO();
1313 return playersao->getInventory();
1316 case InventoryLocation::NODEMETA:
1318 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1321 return meta->getInventory();
1324 case InventoryLocation::DETACHED:
1326 if(m_detached_inventories.count(loc.name) == 0)
1328 return m_detached_inventories[loc.name];
1337 void Server::setInventoryModified(const InventoryLocation &loc)
1340 case InventoryLocation::UNDEFINED:
1342 case InventoryLocation::PLAYER:
1344 Player *player = m_env->getPlayer(loc.name.c_str());
1347 PlayerSAO *playersao = player->getPlayerSAO();
1351 SendInventory(playersao);
1354 case InventoryLocation::NODEMETA:
1356 v3s16 blockpos = getNodeBlockPos(loc.p);
1358 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1360 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1362 setBlockNotSent(blockpos);
1365 case InventoryLocation::DETACHED:
1367 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1376 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1378 std::vector<u16> clients = m_clients.getClientIDs();
1380 // Set the modified blocks unsent for all the clients
1381 for (std::vector<u16>::iterator i = clients.begin();
1382 i != clients.end(); ++i) {
1383 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1384 client->SetBlocksNotSent(block);
1389 void Server::peerAdded(con::Peer *peer)
1391 DSTACK(__FUNCTION_NAME);
1392 verbosestream<<"Server::peerAdded(): peer->id="
1393 <<peer->id<<std::endl;
1396 c.type = con::PEER_ADDED;
1397 c.peer_id = peer->id;
1399 m_peer_change_queue.push(c);
1402 void Server::deletingPeer(con::Peer *peer, bool timeout)
1404 DSTACK(__FUNCTION_NAME);
1405 verbosestream<<"Server::deletingPeer(): peer->id="
1406 <<peer->id<<", timeout="<<timeout<<std::endl;
1408 m_clients.event(peer->id, CSE_Disconnect);
1410 c.type = con::PEER_REMOVED;
1411 c.peer_id = peer->id;
1412 c.timeout = timeout;
1413 m_peer_change_queue.push(c);
1416 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1418 *retval = m_con.getPeerStat(peer_id,type);
1419 if (*retval == -1) return false;
1423 bool Server::getClientInfo(
1432 std::string* vers_string
1435 *state = m_clients.getClientState(peer_id);
1437 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1439 if (client == NULL) {
1444 *uptime = client->uptime();
1445 *ser_vers = client->serialization_version;
1446 *prot_vers = client->net_proto_version;
1448 *major = client->getMajor();
1449 *minor = client->getMinor();
1450 *patch = client->getPatch();
1451 *vers_string = client->getPatch();
1458 void Server::handlePeerChanges()
1460 while(m_peer_change_queue.size() > 0)
1462 con::PeerChange c = m_peer_change_queue.front();
1463 m_peer_change_queue.pop();
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(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::vector<u16> clients = m_clients.getClientIDs();
1959 for(std::vector<u16>::iterator
1960 i = clients.begin(); i != clients.end(); ++i) {
1961 Player *player = m_env->getPlayer(*i);
1966 if(player->getPosition().getDistanceFrom(pos) >
1967 params.max_hear_distance)
1970 dst_clients.push_back(*i);
1974 if(dst_clients.empty())
1978 s32 id = m_next_sound_id++;
1979 // The sound will exist as a reference in m_playing_sounds
1980 m_playing_sounds[id] = ServerPlayingSound();
1981 ServerPlayingSound &psound = m_playing_sounds[id];
1982 psound.params = params;
1983 for(std::list<u16>::iterator i = dst_clients.begin();
1984 i != dst_clients.end(); i++)
1985 psound.clients.insert(*i);
1987 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1988 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1989 << (u8) params.type << pos << params.object << params.loop;
1990 for(std::list<u16>::iterator i = dst_clients.begin();
1991 i != dst_clients.end(); i++) {
1993 m_clients.send(*i, 0, pkt, true, false);
1998 void Server::stopSound(s32 handle)
2000 // Get sound reference
2001 std::map<s32, ServerPlayingSound>::iterator i =
2002 m_playing_sounds.find(handle);
2003 if(i == m_playing_sounds.end())
2005 ServerPlayingSound &psound = i->second;
2007 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2010 for(std::set<u16>::iterator i = psound.clients.begin();
2011 i != psound.clients.end(); i++) {
2013 m_clients.send(*i, 0, pkt, true, false);
2016 // Remove sound reference
2017 m_playing_sounds.erase(i);
2020 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2021 std::list<u16> *far_players, float far_d_nodes)
2023 float maxd = far_d_nodes*BS;
2024 v3f p_f = intToFloat(p, BS);
2026 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2029 std::vector<u16> clients = m_clients.getClientIDs();
2030 for(std::vector<u16>::iterator 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::vector<u16> clients = m_clients.getClientIDs();
2059 for(std::vector<u16>::iterator i = clients.begin();
2060 i != clients.end(); ++i) {
2064 if(Player *player = m_env->getPlayer(*i)) {
2065 // If player is far away, only set modified blocks not sent
2066 v3f player_pos = player->getPosition();
2067 if(player_pos.getDistanceFrom(p_f) > maxd) {
2068 far_players->push_back(*i);
2074 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2076 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2078 *pkt << p << n.param0 << n.param1 << n.param2
2079 << (u8) (remove_metadata ? 0 : 1);
2081 if (!remove_metadata) {
2082 if (client->net_proto_version <= 21) {
2083 // Old clients always clear metadata; fix it
2084 // by sending the full block again.
2085 client->SetBlockNotSent(p);
2092 if (pkt->getSize() > 0)
2093 m_clients.send(*i, 0, pkt, true);
2097 void Server::setBlockNotSent(v3s16 p)
2099 std::vector<u16> clients = m_clients.getClientIDs();
2101 for(std::vector<u16>::iterator i = clients.begin();
2102 i != clients.end(); ++i) {
2103 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2104 client->SetBlockNotSent(p);
2109 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2111 DSTACK(__FUNCTION_NAME);
2113 v3s16 p = block->getPos();
2116 Create a packet with the block in the right format
2119 std::ostringstream os(std::ios_base::binary);
2120 block->serialize(os, ver, false);
2121 block->serializeNetworkSpecific(os, net_proto_version);
2122 std::string s = os.str();
2124 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2125 2 + 2 + 2 + 2 + s.size(), peer_id);
2128 pkt->putRawString(s.c_str(), s.size());
2132 void Server::SendBlocks(float dtime)
2134 DSTACK(__FUNCTION_NAME);
2136 JMutexAutoLock envlock(m_env_mutex);
2137 //TODO check if one big lock could be faster then multiple small ones
2139 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2141 std::vector<PrioritySortedBlockTransfer> queue;
2143 s32 total_sending = 0;
2146 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2148 std::vector<u16> clients = m_clients.getClientIDs();
2151 for(std::vector<u16>::iterator i = clients.begin();
2152 i != clients.end(); ++i) {
2153 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2158 total_sending += client->SendingCount();
2159 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2165 // Lowest priority number comes first.
2166 // Lowest is most important.
2167 std::sort(queue.begin(), queue.end());
2170 for(u32 i=0; i<queue.size(); i++)
2172 //TODO: Calculate limit dynamically
2173 if(total_sending >= g_settings->getS32
2174 ("max_simultaneous_block_sends_server_total"))
2177 PrioritySortedBlockTransfer q = queue[i];
2179 MapBlock *block = NULL;
2182 block = m_env->getMap().getBlockNoCreate(q.pos);
2184 catch(InvalidPositionException &e)
2189 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2194 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2196 client->SentBlock(q.pos);
2202 void Server::fillMediaCache()
2204 DSTACK(__FUNCTION_NAME);
2206 infostream<<"Server: Calculating media file checksums"<<std::endl;
2208 // Collect all media file paths
2209 std::list<std::string> paths;
2210 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2211 i != m_mods.end(); i++){
2212 const ModSpec &mod = *i;
2213 paths.push_back(mod.path + DIR_DELIM + "textures");
2214 paths.push_back(mod.path + DIR_DELIM + "sounds");
2215 paths.push_back(mod.path + DIR_DELIM + "media");
2216 paths.push_back(mod.path + DIR_DELIM + "models");
2218 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2220 // Collect media file information from paths into cache
2221 for(std::list<std::string>::iterator i = paths.begin();
2222 i != paths.end(); i++)
2224 std::string mediapath = *i;
2225 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2226 for(u32 j=0; j<dirlist.size(); j++){
2227 if(dirlist[j].dir) // Ignode dirs
2229 std::string filename = dirlist[j].name;
2230 // If name contains illegal characters, ignore the file
2231 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2232 infostream<<"Server: ignoring illegal file name: \""
2233 <<filename<<"\""<<std::endl;
2236 // If name is not in a supported format, ignore it
2237 const char *supported_ext[] = {
2238 ".png", ".jpg", ".bmp", ".tga",
2239 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2241 ".x", ".b3d", ".md2", ".obj",
2244 if(removeStringEnd(filename, supported_ext) == ""){
2245 infostream<<"Server: ignoring unsupported file extension: \""
2246 <<filename<<"\""<<std::endl;
2249 // Ok, attempt to load the file and add to cache
2250 std::string filepath = mediapath + DIR_DELIM + filename;
2252 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2253 if(fis.good() == false){
2254 errorstream<<"Server::fillMediaCache(): Could not open \""
2255 <<filename<<"\" for reading"<<std::endl;
2258 std::ostringstream tmp_os(std::ios_base::binary);
2262 fis.read(buf, 1024);
2263 std::streamsize len = fis.gcount();
2264 tmp_os.write(buf, len);
2273 errorstream<<"Server::fillMediaCache(): Failed to read \""
2274 <<filename<<"\""<<std::endl;
2277 if(tmp_os.str().length() == 0){
2278 errorstream<<"Server::fillMediaCache(): Empty file \""
2279 <<filepath<<"\""<<std::endl;
2284 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2286 unsigned char *digest = sha1.getDigest();
2287 std::string sha1_base64 = base64_encode(digest, 20);
2288 std::string sha1_hex = hex_encode((char*)digest, 20);
2292 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2293 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2298 struct SendableMediaAnnouncement
2301 std::string sha1_digest;
2303 SendableMediaAnnouncement(const std::string &name_="",
2304 const std::string &sha1_digest_=""):
2306 sha1_digest(sha1_digest_)
2310 void Server::sendMediaAnnouncement(u16 peer_id)
2312 DSTACK(__FUNCTION_NAME);
2314 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2317 std::list<SendableMediaAnnouncement> file_announcements;
2319 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2320 i != m_media.end(); i++){
2322 file_announcements.push_back(
2323 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2327 std::ostringstream os(std::ios_base::binary);
2334 u16 length of sha1_digest
2339 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2340 *pkt << (u16) file_announcements.size();
2342 for(std::list<SendableMediaAnnouncement>::iterator
2343 j = file_announcements.begin();
2344 j != file_announcements.end(); ++j) {
2345 *pkt << j->name << j->sha1_digest;
2348 *pkt << g_settings->get("remote_media");
2352 struct SendableMedia
2358 SendableMedia(const std::string &name_="", const std::string &path_="",
2359 const std::string &data_=""):
2366 void Server::sendRequestedMedia(u16 peer_id,
2367 const std::list<std::string> &tosend)
2369 DSTACK(__FUNCTION_NAME);
2371 verbosestream<<"Server::sendRequestedMedia(): "
2372 <<"Sending files to client"<<std::endl;
2376 // Put 5kB in one bunch (this is not accurate)
2377 u32 bytes_per_bunch = 5000;
2379 std::vector< std::list<SendableMedia> > file_bunches;
2380 file_bunches.push_back(std::list<SendableMedia>());
2382 u32 file_size_bunch_total = 0;
2384 for(std::list<std::string>::const_iterator i = tosend.begin();
2385 i != tosend.end(); ++i)
2387 const std::string &name = *i;
2389 if(m_media.find(name) == m_media.end()) {
2390 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2391 <<"unknown file \""<<(name)<<"\""<<std::endl;
2395 //TODO get path + name
2396 std::string tpath = m_media[name].path;
2399 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2400 if(fis.good() == false){
2401 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2402 <<tpath<<"\" for reading"<<std::endl;
2405 std::ostringstream tmp_os(std::ios_base::binary);
2409 fis.read(buf, 1024);
2410 std::streamsize len = fis.gcount();
2411 tmp_os.write(buf, len);
2412 file_size_bunch_total += len;
2421 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2422 <<name<<"\""<<std::endl;
2425 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2426 <<tname<<"\""<<std::endl;*/
2428 file_bunches[file_bunches.size()-1].push_back(
2429 SendableMedia(name, tpath, tmp_os.str()));
2431 // Start next bunch if got enough data
2432 if(file_size_bunch_total >= bytes_per_bunch) {
2433 file_bunches.push_back(std::list<SendableMedia>());
2434 file_size_bunch_total = 0;
2439 /* Create and send packets */
2441 u16 num_bunches = file_bunches.size();
2442 for(u16 i = 0; i < num_bunches; i++) {
2445 u16 total number of texture bunches
2446 u16 index of this bunch
2447 u32 number of files in this bunch
2456 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2457 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2459 for(std::list<SendableMedia>::iterator
2460 j = file_bunches[i].begin();
2461 j != file_bunches[i].end(); ++j) {
2463 pkt->putLongString(j->data);
2466 verbosestream << "Server::sendRequestedMedia(): bunch "
2467 << i << "/" << num_bunches
2468 << " files=" << file_bunches[i].size()
2469 << " size=" << pkt->getSize() << std::endl;
2474 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2476 if(m_detached_inventories.count(name) == 0) {
2477 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2480 Inventory *inv = m_detached_inventories[name];
2481 std::ostringstream os(std::ios_base::binary);
2483 os << serializeString(name);
2487 std::string s = os.str();
2489 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2490 pkt->putRawString(s.c_str(), s.size());
2492 if (peer_id != PEER_ID_INEXISTENT) {
2496 m_clients.sendToAll(0, pkt, true);
2500 void Server::sendDetachedInventories(u16 peer_id)
2502 DSTACK(__FUNCTION_NAME);
2504 for(std::map<std::string, Inventory*>::iterator
2505 i = m_detached_inventories.begin();
2506 i != m_detached_inventories.end(); i++) {
2507 const std::string &name = i->first;
2508 //Inventory *inv = i->second;
2509 sendDetachedInventory(name, peer_id);
2517 void Server::DiePlayer(u16 peer_id)
2519 DSTACK(__FUNCTION_NAME);
2521 PlayerSAO *playersao = getPlayerSAO(peer_id);
2524 infostream << "Server::DiePlayer(): Player "
2525 << playersao->getPlayer()->getName()
2526 << " dies" << std::endl;
2528 playersao->setHP(0);
2530 // Trigger scripted stuff
2531 m_script->on_dieplayer(playersao);
2533 SendPlayerHP(peer_id);
2534 SendDeathscreen(peer_id, false, v3f(0,0,0));
2537 void Server::RespawnPlayer(u16 peer_id)
2539 DSTACK(__FUNCTION_NAME);
2541 PlayerSAO *playersao = getPlayerSAO(peer_id);
2544 infostream << "Server::RespawnPlayer(): Player "
2545 << playersao->getPlayer()->getName()
2546 << " respawns" << std::endl;
2548 playersao->setHP(PLAYER_MAX_HP);
2549 playersao->setBreath(PLAYER_MAX_BREATH);
2551 SendPlayerHP(peer_id);
2552 SendPlayerBreath(peer_id);
2554 bool repositioned = m_script->on_respawnplayer(playersao);
2556 v3f pos = findSpawnPos(m_env->getServerMap());
2557 // setPos will send the new position to client
2558 playersao->setPos(pos);
2562 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2564 DSTACK(__FUNCTION_NAME);
2566 SendAccessDenied(peer_id, reason);
2567 m_clients.event(peer_id, CSE_SetDenied);
2568 m_con.DisconnectPeer(peer_id);
2571 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2573 DSTACK(__FUNCTION_NAME);
2574 std::wstring message;
2577 Clear references to playing sounds
2579 for(std::map<s32, ServerPlayingSound>::iterator
2580 i = m_playing_sounds.begin();
2581 i != m_playing_sounds.end();)
2583 ServerPlayingSound &psound = i->second;
2584 psound.clients.erase(peer_id);
2585 if(psound.clients.empty())
2586 m_playing_sounds.erase(i++);
2591 Player *player = m_env->getPlayer(peer_id);
2593 // Collect information about leaving in chat
2595 if(player != NULL && reason != CDR_DENY)
2597 std::wstring name = narrow_to_wide(player->getName());
2600 message += L" left the game.";
2601 if(reason == CDR_TIMEOUT)
2602 message += L" (timed out)";
2606 /* Run scripts and remove from environment */
2610 PlayerSAO *playersao = player->getPlayerSAO();
2613 m_script->on_leaveplayer(playersao);
2615 playersao->disconnected();
2623 if(player != NULL && reason != CDR_DENY) {
2624 std::ostringstream os(std::ios_base::binary);
2625 std::vector<u16> clients = m_clients.getClientIDs();
2627 for(std::vector<u16>::iterator i = clients.begin();
2628 i != clients.end(); ++i) {
2630 Player *player = m_env->getPlayer(*i);
2634 // Get name of player
2635 os << player->getName() << " ";
2638 actionstream << player->getName() << " "
2639 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2640 << " List of players: " << os.str() << std::endl;
2644 JMutexAutoLock env_lock(m_env_mutex);
2645 m_clients.DeleteClient(peer_id);
2649 // Send leave chat message to all remaining clients
2650 if(message.length() != 0)
2651 SendChatMessage(PEER_ID_INEXISTENT,message);
2654 void Server::UpdateCrafting(Player* player)
2656 DSTACK(__FUNCTION_NAME);
2658 // Get a preview for crafting
2660 InventoryLocation loc;
2661 loc.setPlayer(player->getName());
2662 getCraftingResult(&player->inventory, preview, false, this);
2663 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2665 // Put the new preview in
2666 InventoryList *plist = player->inventory.getList("craftpreview");
2668 assert(plist->getSize() >= 1);
2669 plist->changeItem(0, preview);
2672 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2674 RemoteClient *client = getClientNoEx(peer_id,state_min);
2676 throw ClientNotFoundException("Client not found");
2680 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2682 return m_clients.getClientNoEx(peer_id, state_min);
2685 std::string Server::getPlayerName(u16 peer_id)
2687 Player *player = m_env->getPlayer(peer_id);
2689 return "[id="+itos(peer_id)+"]";
2690 return player->getName();
2693 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2695 Player *player = m_env->getPlayer(peer_id);
2698 return player->getPlayerSAO();
2701 std::wstring Server::getStatusString()
2703 std::wostringstream os(std::ios_base::binary);
2706 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2708 os<<L", uptime="<<m_uptime.get();
2710 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2711 // Information about clients
2714 std::vector<u16> clients = m_clients.getClientIDs();
2715 for(std::vector<u16>::iterator i = clients.begin();
2716 i != clients.end(); ++i) {
2718 Player *player = m_env->getPlayer(*i);
2719 // Get name of player
2720 std::wstring name = L"unknown";
2722 name = narrow_to_wide(player->getName());
2723 // Add name to information string
2731 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2732 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2733 if(g_settings->get("motd") != "")
2734 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2738 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2740 std::set<std::string> privs;
2741 m_script->getAuth(name, NULL, &privs);
2745 bool Server::checkPriv(const std::string &name, const std::string &priv)
2747 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2748 return (privs.count(priv) != 0);
2751 void Server::reportPrivsModified(const std::string &name)
2754 std::vector<u16> clients = m_clients.getClientIDs();
2755 for(std::vector<u16>::iterator i = clients.begin();
2756 i != clients.end(); ++i) {
2757 Player *player = m_env->getPlayer(*i);
2758 reportPrivsModified(player->getName());
2761 Player *player = m_env->getPlayer(name.c_str());
2764 SendPlayerPrivileges(player->peer_id);
2765 PlayerSAO *sao = player->getPlayerSAO();
2768 sao->updatePrivileges(
2769 getPlayerEffectivePrivs(name),
2774 void Server::reportInventoryFormspecModified(const std::string &name)
2776 Player *player = m_env->getPlayer(name.c_str());
2779 SendPlayerInventoryFormspec(player->peer_id);
2782 void Server::setIpBanned(const std::string &ip, const std::string &name)
2784 m_banmanager->add(ip, name);
2787 void Server::unsetIpBanned(const std::string &ip_or_name)
2789 m_banmanager->remove(ip_or_name);
2792 std::string Server::getBanDescription(const std::string &ip_or_name)
2794 return m_banmanager->getBanDescription(ip_or_name);
2797 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2799 Player *player = m_env->getPlayer(name);
2803 if (player->peer_id == PEER_ID_INEXISTENT)
2806 SendChatMessage(player->peer_id, msg);
2809 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2811 Player *player = m_env->getPlayer(playername);
2815 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2819 SendShowFormspecMessage(player->peer_id, formspec, formname);
2823 u32 Server::hudAdd(Player *player, HudElement *form) {
2827 u32 id = player->addHud(form);
2829 SendHUDAdd(player->peer_id, id, form);
2834 bool Server::hudRemove(Player *player, u32 id) {
2838 HudElement* todel = player->removeHud(id);
2845 SendHUDRemove(player->peer_id, id);
2849 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2853 SendHUDChange(player->peer_id, id, stat, data);
2857 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2861 SendHUDSetFlags(player->peer_id, flags, mask);
2862 player->hud_flags = flags;
2864 PlayerSAO* playersao = player->getPlayerSAO();
2866 if (playersao == NULL)
2869 m_script->player_event(playersao, "hud_changed");
2873 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2876 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2879 std::ostringstream os(std::ios::binary);
2880 writeS32(os, hotbar_itemcount);
2881 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2885 void Server::hudSetHotbarImage(Player *player, std::string name) {
2889 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2892 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2896 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2899 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2904 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2908 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2913 SendEyeOffset(player->peer_id, first, third);
2917 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2918 const std::string &type, const std::vector<std::string> ¶ms)
2923 SendSetSky(player->peer_id, bgcolor, type, params);
2927 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2933 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2937 void Server::notifyPlayers(const std::wstring &msg)
2939 SendChatMessage(PEER_ID_INEXISTENT,msg);
2942 void Server::spawnParticle(const char *playername, v3f pos,
2943 v3f velocity, v3f acceleration,
2944 float expirationtime, float size, bool
2945 collisiondetection, bool vertical, std::string texture)
2947 Player *player = m_env->getPlayer(playername);
2950 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2951 expirationtime, size, collisiondetection, vertical, texture);
2954 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2955 float expirationtime, float size,
2956 bool collisiondetection, bool vertical, std::string texture)
2958 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2959 expirationtime, size, collisiondetection, vertical, texture);
2962 u32 Server::addParticleSpawner(const char *playername,
2963 u16 amount, float spawntime,
2964 v3f minpos, v3f maxpos,
2965 v3f minvel, v3f maxvel,
2966 v3f minacc, v3f maxacc,
2967 float minexptime, float maxexptime,
2968 float minsize, float maxsize,
2969 bool collisiondetection, bool vertical, std::string texture)
2971 Player *player = m_env->getPlayer(playername);
2976 for(;;) // look for unused particlespawner id
2979 if (std::find(m_particlespawner_ids.begin(),
2980 m_particlespawner_ids.end(), id)
2981 == m_particlespawner_ids.end())
2983 m_particlespawner_ids.push_back(id);
2988 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2989 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2990 minexptime, maxexptime, minsize, maxsize,
2991 collisiondetection, vertical, texture, id);
2996 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2997 v3f minpos, v3f maxpos,
2998 v3f minvel, v3f maxvel,
2999 v3f minacc, v3f maxacc,
3000 float minexptime, float maxexptime,
3001 float minsize, float maxsize,
3002 bool collisiondetection, bool vertical, std::string texture)
3005 for(;;) // look for unused particlespawner id
3008 if (std::find(m_particlespawner_ids.begin(),
3009 m_particlespawner_ids.end(), id)
3010 == m_particlespawner_ids.end())
3012 m_particlespawner_ids.push_back(id);
3017 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3018 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3019 minexptime, maxexptime, minsize, maxsize,
3020 collisiondetection, vertical, texture, id);
3025 void Server::deleteParticleSpawner(const char *playername, u32 id)
3027 Player *player = m_env->getPlayer(playername);
3031 m_particlespawner_ids.erase(
3032 std::remove(m_particlespawner_ids.begin(),
3033 m_particlespawner_ids.end(), id),
3034 m_particlespawner_ids.end());
3035 SendDeleteParticleSpawner(player->peer_id, id);
3038 void Server::deleteParticleSpawnerAll(u32 id)
3040 m_particlespawner_ids.erase(
3041 std::remove(m_particlespawner_ids.begin(),
3042 m_particlespawner_ids.end(), id),
3043 m_particlespawner_ids.end());
3044 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3047 Inventory* Server::createDetachedInventory(const std::string &name)
3049 if(m_detached_inventories.count(name) > 0){
3050 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3051 delete m_detached_inventories[name];
3053 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3055 Inventory *inv = new Inventory(m_itemdef);
3057 m_detached_inventories[name] = inv;
3058 //TODO find a better way to do this
3059 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3066 BoolScopeSet(bool *dst, bool val):
3069 m_orig_state = *m_dst;
3074 *m_dst = m_orig_state;
3081 // actions: time-reversed list
3082 // Return value: success/failure
3083 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3084 std::list<std::string> *log)
3086 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3087 ServerMap *map = (ServerMap*)(&m_env->getMap());
3089 // Fail if no actions to handle
3090 if(actions.empty()){
3091 log->push_back("Nothing to do.");
3098 for(std::list<RollbackAction>::const_iterator
3099 i = actions.begin();
3100 i != actions.end(); i++)
3102 const RollbackAction &action = *i;
3104 bool success = action.applyRevert(map, this, this);
3107 std::ostringstream os;
3108 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3109 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3111 log->push_back(os.str());
3113 std::ostringstream os;
3114 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3115 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3117 log->push_back(os.str());
3121 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3122 <<" failed"<<std::endl;
3124 // Call it done if less than half failed
3125 return num_failed <= num_tried/2;
3128 // IGameDef interface
3130 IItemDefManager* Server::getItemDefManager()
3134 INodeDefManager* Server::getNodeDefManager()
3138 ICraftDefManager* Server::getCraftDefManager()
3142 ITextureSource* Server::getTextureSource()
3146 IShaderSource* Server::getShaderSource()
3150 scene::ISceneManager* Server::getSceneManager()
3155 u16 Server::allocateUnknownNodeId(const std::string &name)
3157 return m_nodedef->allocateDummy(name);
3159 ISoundManager* Server::getSoundManager()
3161 return &dummySoundManager;
3163 MtEventManager* Server::getEventManager()
3168 IWritableItemDefManager* Server::getWritableItemDefManager()
3172 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3176 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3181 const ModSpec* Server::getModSpec(const std::string &modname)
3183 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3184 i != m_mods.end(); i++){
3185 const ModSpec &mod = *i;
3186 if(mod.name == modname)
3191 void Server::getModNames(std::vector<std::string> &modlist)
3193 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3194 modlist.push_back(i->name);
3197 std::string Server::getBuiltinLuaPath()
3199 return porting::path_share + DIR_DELIM + "builtin";
3202 v3f findSpawnPos(ServerMap &map)
3204 //return v3f(50,50,50)*BS;
3209 nodepos = v2s16(0,0);
3214 s16 water_level = map.getWaterLevel();
3216 // Try to find a good place a few times
3217 for(s32 i=0; i<1000; i++)
3220 // We're going to try to throw the player to this position
3221 v2s16 nodepos2d = v2s16(
3222 -range + (myrand() % (range * 2)),
3223 -range + (myrand() % (range * 2)));
3225 // Get ground height at point
3226 s16 groundheight = map.findGroundLevel(nodepos2d);
3227 if (groundheight <= water_level) // Don't go underwater
3229 if (groundheight > water_level + 6) // Don't go to high places
3232 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3233 bool is_good = false;
3235 for (s32 i = 0; i < 10; i++) {
3236 v3s16 blockpos = getNodeBlockPos(nodepos);
3237 map.emergeBlock(blockpos, true);
3238 content_t c = map.getNodeNoEx(nodepos).getContent();
3239 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3241 if (air_count >= 2){
3249 // Found a good place
3250 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3256 return intToFloat(nodepos, BS);
3259 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3261 bool newplayer = false;
3264 Try to get an existing player
3266 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3268 // If player is already connected, cancel
3269 if(player != NULL && player->peer_id != 0)
3271 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3276 If player with the wanted peer_id already exists, cancel.
3278 if(m_env->getPlayer(peer_id) != NULL)
3280 infostream<<"emergePlayer(): Player with wrong name but same"
3281 " peer_id already exists"<<std::endl;
3285 // Load player if it isn't already loaded
3287 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3290 // Create player if it doesn't exist
3293 player = new RemotePlayer(this, name);
3294 // Set player position
3295 infostream<<"Server: Finding spawn place for player \""
3296 <<name<<"\""<<std::endl;
3297 v3f pos = findSpawnPos(m_env->getServerMap());
3298 player->setPosition(pos);
3300 // Make sure the player is saved
3301 player->setModified(true);
3303 // Add player to environment
3304 m_env->addPlayer(player);
3307 // Create a new player active object
3308 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3309 getPlayerEffectivePrivs(player->getName()),
3312 /* Clean up old HUD elements from previous sessions */
3315 /* Add object to environment */
3316 m_env->addActiveObject(playersao);
3320 m_script->on_newplayer(playersao);
3326 void dedicated_server_loop(Server &server, bool &kill)
3328 DSTACK(__FUNCTION_NAME);
3330 verbosestream<<"dedicated_server_loop()"<<std::endl;
3332 IntervalLimiter m_profiler_interval;
3336 float steplen = g_settings->getFloat("dedicated_server_step");
3337 // This is kind of a hack but can be done like this
3338 // because server.step() is very light
3340 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3341 sleep_ms((int)(steplen*1000.0));
3343 server.step(steplen);
3345 if(server.getShutdownRequested() || kill)
3347 infostream<<"Dedicated server quitting"<<std::endl;
3349 if(g_settings->getBool("server_announce"))
3350 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3358 float profiler_print_interval =
3359 g_settings->getFloat("profiler_print_interval");
3360 if(profiler_print_interval != 0)
3362 if(m_profiler_interval.step(steplen, profiler_print_interval))
3364 infostream<<"Profiler:"<<std::endl;
3365 g_profiler->print(infostream);
3366 g_profiler->clear();