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::vector<ActiveObjectMessage>* > buffered_messages;
793 // Get active object messages from environment
795 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
799 std::vector<ActiveObjectMessage>* message_list = NULL;
800 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
801 n = buffered_messages.find(aom.id);
802 if (n == buffered_messages.end()) {
803 message_list = new std::vector<ActiveObjectMessage>;
804 buffered_messages[aom.id] = message_list;
807 message_list = n->second;
809 message_list->push_back(aom);
813 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
814 // Route data to every client
815 for (std::map<u16, RemoteClient*>::iterator
817 i != clients.end(); ++i) {
818 RemoteClient *client = i->second;
819 std::string reliable_data;
820 std::string unreliable_data;
821 // Go through all objects in message buffer
822 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
823 j = buffered_messages.begin();
824 j != buffered_messages.end(); ++j) {
825 // If object is not known by client, skip it
827 if (client->m_known_objects.find(id) == client->m_known_objects.end())
830 // Get message list of object
831 std::vector<ActiveObjectMessage>* list = j->second;
832 // Go through every message
833 for (std::vector<ActiveObjectMessage>::iterator
834 k = list->begin(); k != list->end(); ++k) {
835 // Compose the full new data with header
836 ActiveObjectMessage aom = *k;
837 std::string new_data;
840 writeU16((u8*)&buf[0], aom.id);
841 new_data.append(buf, 2);
843 new_data += serializeString(aom.datastring);
844 // Add data to buffer
846 reliable_data += new_data;
848 unreliable_data += new_data;
852 reliable_data and unreliable_data are now ready.
855 if(reliable_data.size() > 0) {
856 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
859 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
863 if(unreliable_data.size() > 0) {
864 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
867 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
873 // Clear buffered_messages
874 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
875 i = buffered_messages.begin();
876 i != buffered_messages.end(); ++i) {
882 Send queued-for-sending map edit events.
885 // We will be accessing the environment
886 JMutexAutoLock lock(m_env_mutex);
888 // Don't send too many at a time
891 // Single change sending is disabled if queue size is not small
892 bool disable_single_change_sending = false;
893 if(m_unsent_map_edit_queue.size() >= 4)
894 disable_single_change_sending = true;
896 int event_count = m_unsent_map_edit_queue.size();
898 // We'll log the amount of each
901 while(m_unsent_map_edit_queue.size() != 0)
903 MapEditEvent* event = m_unsent_map_edit_queue.front();
904 m_unsent_map_edit_queue.pop();
906 // Players far away from the change are stored here.
907 // Instead of sending the changes, MapBlocks are set not sent
909 std::vector<u16> far_players;
911 switch (event->type) {
914 prof.add("MEET_ADDNODE", 1);
915 sendAddNode(event->p, event->n, event->already_known_by_peer,
916 &far_players, disable_single_change_sending ? 5 : 30,
917 event->type == MEET_ADDNODE);
919 case MEET_REMOVENODE:
920 prof.add("MEET_REMOVENODE", 1);
921 sendRemoveNode(event->p, event->already_known_by_peer,
922 &far_players, disable_single_change_sending ? 5 : 30);
924 case MEET_BLOCK_NODE_METADATA_CHANGED:
925 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
926 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
927 setBlockNotSent(event->p);
930 infostream << "Server: MEET_OTHER" << std::endl;
931 prof.add("MEET_OTHER", 1);
932 for(std::set<v3s16>::iterator
933 i = event->modified_blocks.begin();
934 i != event->modified_blocks.end(); ++i) {
939 prof.add("unknown", 1);
940 infostream << "WARNING: Server: Unknown MapEditEvent "
941 << ((u32)event->type) << std::endl;
946 Set blocks not sent to far players
948 if(!far_players.empty()) {
949 // Convert list format to that wanted by SetBlocksNotSent
950 std::map<v3s16, MapBlock*> modified_blocks2;
951 for(std::set<v3s16>::iterator
952 i = event->modified_blocks.begin();
953 i != event->modified_blocks.end(); ++i) {
954 modified_blocks2[*i] =
955 m_env->getMap().getBlockNoCreateNoEx(*i);
958 // Set blocks not sent
959 for(std::vector<u16>::iterator
960 i = far_players.begin();
961 i != far_players.end(); ++i) {
962 if(RemoteClient *client = getClient(*i))
963 client->SetBlocksNotSent(modified_blocks2);
969 /*// Don't send too many at a time
971 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
975 if(event_count >= 5){
976 infostream<<"Server: MapEditEvents:"<<std::endl;
977 prof.print(infostream);
978 } else if(event_count != 0){
979 verbosestream<<"Server: MapEditEvents:"<<std::endl;
980 prof.print(verbosestream);
986 Trigger emergethread (it somehow gets to a non-triggered but
987 bysy state sometimes)
990 float &counter = m_emergethread_trigger_timer;
996 m_emerge->startThreads();
1000 // Save map, players and auth stuff
1002 float &counter = m_savemap_timer;
1004 if(counter >= g_settings->getFloat("server_map_save_interval"))
1007 JMutexAutoLock lock(m_env_mutex);
1009 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1012 if (m_banmanager->isModified()) {
1013 m_banmanager->save();
1016 // Save changed parts of map
1017 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1020 m_env->saveLoadedPlayers();
1022 // Save environment metadata
1028 void Server::Receive()
1030 DSTACK(__FUNCTION_NAME);
1031 SharedBuffer<u8> data;
1035 datasize = m_con.Receive(peer_id,data);
1036 ProcessData(*data, datasize, peer_id);
1038 catch(con::InvalidIncomingDataException &e) {
1039 infostream<<"Server::Receive(): "
1040 "InvalidIncomingDataException: what()="
1041 <<e.what()<<std::endl;
1043 catch(SerializationError &e) {
1044 infostream<<"Server::Receive(): "
1045 "SerializationError: what()="
1046 <<e.what()<<std::endl;
1048 catch(ClientStateError &e) {
1049 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1050 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1051 L"Try reconnecting or updating your client");
1053 catch(con::PeerNotFoundException &e) {
1058 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1060 std::string playername = "";
1061 PlayerSAO *playersao = NULL;
1064 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1065 if (client != NULL) {
1066 playername = client->getName();
1067 playersao = emergePlayer(playername.c_str(), peer_id);
1069 } catch (std::exception &e) {
1075 RemotePlayer *player =
1076 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1078 // If failed, cancel
1079 if((playersao == NULL) || (player == NULL)) {
1080 if(player && player->peer_id != 0) {
1081 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1082 <<" (player allocated to an another client)"<<std::endl;
1083 DenyAccess(peer_id, L"Another client is connected with this "
1084 L"name. If your client closed unexpectedly, try again in "
1087 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1089 DenyAccess(peer_id, L"Could not allocate player.");
1095 Send complete position information
1097 SendMovePlayer(peer_id);
1100 SendPlayerPrivileges(peer_id);
1102 // Send inventory formspec
1103 SendPlayerInventoryFormspec(peer_id);
1106 SendInventory(playersao);
1109 if(g_settings->getBool("enable_damage"))
1110 SendPlayerHP(peer_id);
1113 SendPlayerBreath(peer_id);
1115 // Show death screen if necessary
1117 SendDeathscreen(peer_id, false, v3f(0,0,0));
1119 // Note things in chat if not in simple singleplayer mode
1120 if(!m_simple_singleplayer_mode) {
1121 // Send information about server to player in chat
1122 SendChatMessage(peer_id, getStatusString());
1124 // Send information about joining in chat
1126 std::wstring name = L"unknown";
1127 Player *player = m_env->getPlayer(peer_id);
1129 name = narrow_to_wide(player->getName());
1131 std::wstring message;
1134 message += L" joined the game.";
1135 SendChatMessage(PEER_ID_INEXISTENT,message);
1138 Address addr = getPeerAddress(player->peer_id);
1139 std::string ip_str = addr.serializeString();
1140 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1145 std::vector<std::string> names = m_clients.getPlayerNames();
1147 actionstream<<player->getName() <<" joins game. List of players: ";
1149 for (std::vector<std::string>::iterator i = names.begin();
1150 i != names.end(); i++) {
1151 actionstream << *i << " ";
1154 actionstream << player->getName() <<std::endl;
1159 inline void Server::handleCommand(NetworkPacket* pkt)
1161 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1162 (this->*opHandle.handler)(pkt);
1165 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1167 DSTACK(__FUNCTION_NAME);
1168 // Environment is locked first.
1169 JMutexAutoLock envlock(m_env_mutex);
1171 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1174 Address address = getPeerAddress(peer_id);
1175 std::string addr_s = address.serializeString();
1177 if(m_banmanager->isIpBanned(addr_s)) {
1178 std::string ban_name = m_banmanager->getBanName(addr_s);
1179 infostream << "Server: A banned client tried to connect from "
1180 << addr_s << "; banned name was "
1181 << ban_name << std::endl;
1182 // This actually doesn't seem to transfer to the client
1183 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1184 + narrow_to_wide(ban_name));
1188 catch(con::PeerNotFoundException &e) {
1190 * no peer for this packet found
1191 * most common reason is peer timeout, e.g. peer didn't
1192 * respond for some time, your server was overloaded or
1195 infostream << "Server::ProcessData(): Cancelling: peer "
1196 << peer_id << " not found" << std::endl;
1204 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1206 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1208 // Command must be handled into ToServerCommandHandler
1209 if (command >= TOSERVER_NUM_MSG_TYPES) {
1210 infostream << "Server: Ignoring unknown command "
1211 << command << std::endl;
1214 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1220 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1222 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1223 errorstream << "Server::ProcessData(): Cancelling: Peer"
1224 " serialization format invalid or not initialized."
1225 " Skipping incoming command=" << command << std::endl;
1231 /* Handle commands related to client startup */
1232 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1238 if (m_clients.getClientState(peer_id) < CS_Active) {
1239 if (command == TOSERVER_PLAYERPOS) return;
1241 errorstream << "Got packet command: " << command << " for peer id "
1242 << peer_id << " but client isn't active yet. Dropping packet "
1253 catch(SendFailedException &e) {
1254 errorstream << "Server::ProcessData(): SendFailedException: "
1255 << "what=" << e.what()
1260 void Server::setTimeOfDay(u32 time)
1262 m_env->setTimeOfDay(time);
1263 m_time_of_day_send_timer = 0;
1266 void Server::onMapEditEvent(MapEditEvent *event)
1268 if(m_ignore_map_edit_events)
1270 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1272 MapEditEvent *e = event->clone();
1273 m_unsent_map_edit_queue.push(e);
1276 Inventory* Server::getInventory(const InventoryLocation &loc)
1279 case InventoryLocation::UNDEFINED:
1280 case InventoryLocation::CURRENT_PLAYER:
1282 case InventoryLocation::PLAYER:
1284 Player *player = m_env->getPlayer(loc.name.c_str());
1287 PlayerSAO *playersao = player->getPlayerSAO();
1290 return playersao->getInventory();
1293 case InventoryLocation::NODEMETA:
1295 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1298 return meta->getInventory();
1301 case InventoryLocation::DETACHED:
1303 if(m_detached_inventories.count(loc.name) == 0)
1305 return m_detached_inventories[loc.name];
1314 void Server::setInventoryModified(const InventoryLocation &loc)
1317 case InventoryLocation::UNDEFINED:
1319 case InventoryLocation::PLAYER:
1321 Player *player = m_env->getPlayer(loc.name.c_str());
1324 PlayerSAO *playersao = player->getPlayerSAO();
1328 SendInventory(playersao);
1331 case InventoryLocation::NODEMETA:
1333 v3s16 blockpos = getNodeBlockPos(loc.p);
1335 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1337 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1339 setBlockNotSent(blockpos);
1342 case InventoryLocation::DETACHED:
1344 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1353 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1355 std::vector<u16> clients = m_clients.getClientIDs();
1357 // Set the modified blocks unsent for all the clients
1358 for (std::vector<u16>::iterator i = clients.begin();
1359 i != clients.end(); ++i) {
1360 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1361 client->SetBlocksNotSent(block);
1366 void Server::peerAdded(con::Peer *peer)
1368 DSTACK(__FUNCTION_NAME);
1369 verbosestream<<"Server::peerAdded(): peer->id="
1370 <<peer->id<<std::endl;
1373 c.type = con::PEER_ADDED;
1374 c.peer_id = peer->id;
1376 m_peer_change_queue.push(c);
1379 void Server::deletingPeer(con::Peer *peer, bool timeout)
1381 DSTACK(__FUNCTION_NAME);
1382 verbosestream<<"Server::deletingPeer(): peer->id="
1383 <<peer->id<<", timeout="<<timeout<<std::endl;
1385 m_clients.event(peer->id, CSE_Disconnect);
1387 c.type = con::PEER_REMOVED;
1388 c.peer_id = peer->id;
1389 c.timeout = timeout;
1390 m_peer_change_queue.push(c);
1393 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1395 *retval = m_con.getPeerStat(peer_id,type);
1396 if (*retval == -1) return false;
1400 bool Server::getClientInfo(
1409 std::string* vers_string
1412 *state = m_clients.getClientState(peer_id);
1414 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1416 if (client == NULL) {
1421 *uptime = client->uptime();
1422 *ser_vers = client->serialization_version;
1423 *prot_vers = client->net_proto_version;
1425 *major = client->getMajor();
1426 *minor = client->getMinor();
1427 *patch = client->getPatch();
1428 *vers_string = client->getPatch();
1435 void Server::handlePeerChanges()
1437 while(m_peer_change_queue.size() > 0)
1439 con::PeerChange c = m_peer_change_queue.front();
1440 m_peer_change_queue.pop();
1442 verbosestream<<"Server: Handling peer change: "
1443 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1448 case con::PEER_ADDED:
1449 m_clients.CreateClient(c.peer_id);
1452 case con::PEER_REMOVED:
1453 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1457 assert("Invalid peer change event received!" == 0);
1463 void Server::Send(NetworkPacket* pkt)
1465 m_clients.send(pkt->getPeerId(),
1466 clientCommandFactoryTable[pkt->getCommand()].channel,
1468 clientCommandFactoryTable[pkt->getCommand()].reliable);
1471 void Server::SendMovement(u16 peer_id)
1473 DSTACK(__FUNCTION_NAME);
1474 std::ostringstream os(std::ios_base::binary);
1476 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1478 *pkt << g_settings->getFloat("movement_acceleration_default");
1479 *pkt << g_settings->getFloat("movement_acceleration_air");
1480 *pkt << g_settings->getFloat("movement_acceleration_fast");
1481 *pkt << g_settings->getFloat("movement_speed_walk");
1482 *pkt << g_settings->getFloat("movement_speed_crouch");
1483 *pkt << g_settings->getFloat("movement_speed_fast");
1484 *pkt << g_settings->getFloat("movement_speed_climb");
1485 *pkt << g_settings->getFloat("movement_speed_jump");
1486 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1487 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1488 *pkt << g_settings->getFloat("movement_liquid_sink");
1489 *pkt << g_settings->getFloat("movement_gravity");
1494 void Server::SendHP(u16 peer_id, u8 hp)
1496 DSTACK(__FUNCTION_NAME);
1498 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1503 void Server::SendBreath(u16 peer_id, u16 breath)
1505 DSTACK(__FUNCTION_NAME);
1507 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1508 *pkt << (u16) breath;
1512 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1514 DSTACK(__FUNCTION_NAME);
1516 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1521 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1522 v3f camera_point_target)
1524 DSTACK(__FUNCTION_NAME);
1526 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1527 *pkt << set_camera_point_target << camera_point_target;
1531 void Server::SendItemDef(u16 peer_id,
1532 IItemDefManager *itemdef, u16 protocol_version)
1534 DSTACK(__FUNCTION_NAME);
1536 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1540 u32 length of the next item
1541 zlib-compressed serialized ItemDefManager
1543 std::ostringstream tmp_os(std::ios::binary);
1544 itemdef->serialize(tmp_os, protocol_version);
1545 std::ostringstream tmp_os2(std::ios::binary);
1546 compressZlib(tmp_os.str(), tmp_os2);
1547 pkt->putLongString(tmp_os2.str());
1550 verbosestream << "Server: Sending item definitions to id(" << peer_id
1551 << "): size=" << pkt->getSize() << std::endl;
1556 void Server::SendNodeDef(u16 peer_id,
1557 INodeDefManager *nodedef, u16 protocol_version)
1559 DSTACK(__FUNCTION_NAME);
1561 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1565 u32 length of the next item
1566 zlib-compressed serialized NodeDefManager
1568 std::ostringstream tmp_os(std::ios::binary);
1569 nodedef->serialize(tmp_os, protocol_version);
1570 std::ostringstream tmp_os2(std::ios::binary);
1571 compressZlib(tmp_os.str(), tmp_os2);
1573 pkt->putLongString(tmp_os2.str());
1576 verbosestream << "Server: Sending node definitions to id(" << peer_id
1577 << "): size=" << pkt->getSize() << std::endl;
1583 Non-static send methods
1586 void Server::SendInventory(PlayerSAO* playerSAO)
1588 DSTACK(__FUNCTION_NAME);
1590 UpdateCrafting(playerSAO->getPlayer());
1596 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1597 playerSAO->getPeerID());
1599 std::ostringstream os;
1600 playerSAO->getInventory()->serialize(os);
1602 std::string s = os.str();
1604 pkt->putRawString(s.c_str(), s.size());
1608 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1610 DSTACK(__FUNCTION_NAME);
1612 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1615 if (peer_id != PEER_ID_INEXISTENT) {
1619 m_clients.sendToAll(0,pkt,true);
1623 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1624 const std::string &formname)
1626 DSTACK(__FUNCTION_NAME);
1628 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1630 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1636 // Spawns a particle on peer with peer_id
1637 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1638 float expirationtime, float size, bool collisiondetection,
1639 bool vertical, std::string texture)
1641 DSTACK(__FUNCTION_NAME);
1643 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1645 *pkt << pos << velocity << acceleration << expirationtime
1646 << size << collisiondetection;
1647 pkt->putLongString(texture);
1650 if (peer_id != PEER_ID_INEXISTENT) {
1654 m_clients.sendToAll(0,pkt,true);
1658 // Adds a ParticleSpawner on peer with peer_id
1659 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1660 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1661 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1663 DSTACK(__FUNCTION_NAME);
1665 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1667 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1668 << minacc << maxacc << minexptime << maxexptime << minsize
1669 << maxsize << collisiondetection;
1671 pkt->putLongString(texture);
1673 *pkt << id << vertical;
1675 if (peer_id != PEER_ID_INEXISTENT) {
1679 m_clients.sendToAll(0, pkt, true);
1683 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1685 DSTACK(__FUNCTION_NAME);
1687 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1689 // Ugly error in this packet
1692 if (peer_id != PEER_ID_INEXISTENT) {
1696 m_clients.sendToAll(0, pkt, true);
1701 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1703 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1705 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1706 << form->text << form->number << form->item << form->dir
1707 << form->align << form->offset << form->world_pos << form->size;
1712 void Server::SendHUDRemove(u16 peer_id, u32 id)
1714 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1719 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1721 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1722 *pkt << id << (u8) stat;
1726 case HUD_STAT_SCALE:
1727 case HUD_STAT_ALIGN:
1728 case HUD_STAT_OFFSET:
1729 *pkt << *(v2f *) value;
1733 *pkt << *(std::string *) value;
1735 case HUD_STAT_WORLD_POS:
1736 *pkt << *(v3f *) value;
1739 *pkt << *(v2s32 *) value;
1741 case HUD_STAT_NUMBER:
1745 *pkt << *(u32 *) value;
1752 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1754 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1756 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1758 *pkt << flags << mask;
1763 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1765 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1766 *pkt << param << value;
1770 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1771 const std::string &type, const std::vector<std::string> ¶ms)
1773 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1774 *pkt << bgcolor << type << (u16) params.size();
1776 for(size_t i=0; i<params.size(); i++)
1782 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1785 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1788 *pkt << do_override << (u16) (ratio * 65535);
1793 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1795 DSTACK(__FUNCTION_NAME);
1797 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1798 *pkt << time << time_speed;
1800 if (peer_id == PEER_ID_INEXISTENT) {
1801 m_clients.sendToAll(0, pkt, true);
1808 void Server::SendPlayerHP(u16 peer_id)
1810 DSTACK(__FUNCTION_NAME);
1811 PlayerSAO *playersao = getPlayerSAO(peer_id);
1813 SendHP(peer_id, playersao->getHP());
1814 m_script->player_event(playersao,"health_changed");
1816 // Send to other clients
1817 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1818 ActiveObjectMessage aom(playersao->getId(), true, str);
1819 playersao->m_messages_out.push(aom);
1822 void Server::SendPlayerBreath(u16 peer_id)
1824 DSTACK(__FUNCTION_NAME);
1825 PlayerSAO *playersao = getPlayerSAO(peer_id);
1828 m_script->player_event(playersao, "breath_changed");
1829 SendBreath(peer_id, playersao->getBreath());
1832 void Server::SendMovePlayer(u16 peer_id)
1834 DSTACK(__FUNCTION_NAME);
1835 Player *player = m_env->getPlayer(peer_id);
1838 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1839 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1842 v3f pos = player->getPosition();
1843 f32 pitch = player->getPitch();
1844 f32 yaw = player->getYaw();
1845 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1846 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1855 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1857 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1860 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1861 << animation_frames[3] << animation_speed;
1866 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1868 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1869 *pkt << first << third;
1872 void Server::SendPlayerPrivileges(u16 peer_id)
1874 Player *player = m_env->getPlayer(peer_id);
1876 if(player->peer_id == PEER_ID_INEXISTENT)
1879 std::set<std::string> privs;
1880 m_script->getAuth(player->getName(), NULL, &privs);
1882 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1883 *pkt << (u16) privs.size();
1885 for(std::set<std::string>::const_iterator i = privs.begin();
1886 i != privs.end(); i++) {
1893 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1895 Player *player = m_env->getPlayer(peer_id);
1897 if(player->peer_id == PEER_ID_INEXISTENT)
1900 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1901 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1905 s32 Server::playSound(const SimpleSoundSpec &spec,
1906 const ServerSoundParams ¶ms)
1908 // Find out initial position of sound
1909 bool pos_exists = false;
1910 v3f pos = params.getPos(m_env, &pos_exists);
1911 // If position is not found while it should be, cancel sound
1912 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1915 // Filter destination clients
1916 std::list<u16> dst_clients;
1917 if(params.to_player != "")
1919 Player *player = m_env->getPlayer(params.to_player.c_str());
1921 infostream<<"Server::playSound: Player \""<<params.to_player
1922 <<"\" not found"<<std::endl;
1925 if(player->peer_id == PEER_ID_INEXISTENT){
1926 infostream<<"Server::playSound: Player \""<<params.to_player
1927 <<"\" not connected"<<std::endl;
1930 dst_clients.push_back(player->peer_id);
1934 std::vector<u16> clients = m_clients.getClientIDs();
1936 for(std::vector<u16>::iterator
1937 i = clients.begin(); i != clients.end(); ++i) {
1938 Player *player = m_env->getPlayer(*i);
1943 if(player->getPosition().getDistanceFrom(pos) >
1944 params.max_hear_distance)
1947 dst_clients.push_back(*i);
1951 if(dst_clients.empty())
1955 s32 id = m_next_sound_id++;
1956 // The sound will exist as a reference in m_playing_sounds
1957 m_playing_sounds[id] = ServerPlayingSound();
1958 ServerPlayingSound &psound = m_playing_sounds[id];
1959 psound.params = params;
1960 for(std::list<u16>::iterator i = dst_clients.begin();
1961 i != dst_clients.end(); i++)
1962 psound.clients.insert(*i);
1964 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1965 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1966 << (u8) params.type << pos << params.object << params.loop;
1967 for(std::list<u16>::iterator i = dst_clients.begin();
1968 i != dst_clients.end(); i++) {
1970 m_clients.send(*i, 0, pkt, true, false);
1975 void Server::stopSound(s32 handle)
1977 // Get sound reference
1978 std::map<s32, ServerPlayingSound>::iterator i =
1979 m_playing_sounds.find(handle);
1980 if(i == m_playing_sounds.end())
1982 ServerPlayingSound &psound = i->second;
1984 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
1987 for(std::set<u16>::iterator i = psound.clients.begin();
1988 i != psound.clients.end(); i++) {
1990 m_clients.send(*i, 0, pkt, true, false);
1993 // Remove sound reference
1994 m_playing_sounds.erase(i);
1997 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1998 std::vector<u16> *far_players, float far_d_nodes)
2000 float maxd = far_d_nodes*BS;
2001 v3f p_f = intToFloat(p, BS);
2003 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2006 std::vector<u16> clients = m_clients.getClientIDs();
2007 for(std::vector<u16>::iterator i = clients.begin();
2008 i != clients.end(); ++i) {
2011 if(Player *player = m_env->getPlayer(*i)) {
2012 // If player is far away, only set modified blocks not sent
2013 v3f player_pos = player->getPosition();
2014 if(player_pos.getDistanceFrom(p_f) > maxd) {
2015 far_players->push_back(*i);
2022 m_clients.send(*i, 0, pkt, true, false);
2024 // This loop needs the deletion of the packet here
2028 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2029 std::vector<u16> *far_players, float far_d_nodes,
2030 bool remove_metadata)
2032 float maxd = far_d_nodes*BS;
2033 v3f p_f = intToFloat(p, BS);
2035 std::vector<u16> clients = m_clients.getClientIDs();
2036 for(std::vector<u16>::iterator i = clients.begin();
2037 i != clients.end(); ++i) {
2041 if(Player *player = m_env->getPlayer(*i)) {
2042 // If player is far away, only set modified blocks not sent
2043 v3f player_pos = player->getPosition();
2044 if(player_pos.getDistanceFrom(p_f) > maxd) {
2045 far_players->push_back(*i);
2051 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2053 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2055 *pkt << p << n.param0 << n.param1 << n.param2
2056 << (u8) (remove_metadata ? 0 : 1);
2058 if (!remove_metadata) {
2059 if (client->net_proto_version <= 21) {
2060 // Old clients always clear metadata; fix it
2061 // by sending the full block again.
2062 client->SetBlockNotSent(p);
2069 if (pkt->getSize() > 0)
2070 m_clients.send(*i, 0, pkt, true);
2074 void Server::setBlockNotSent(v3s16 p)
2076 std::vector<u16> clients = m_clients.getClientIDs();
2078 for(std::vector<u16>::iterator i = clients.begin();
2079 i != clients.end(); ++i) {
2080 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2081 client->SetBlockNotSent(p);
2086 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2088 DSTACK(__FUNCTION_NAME);
2090 v3s16 p = block->getPos();
2093 Create a packet with the block in the right format
2096 std::ostringstream os(std::ios_base::binary);
2097 block->serialize(os, ver, false);
2098 block->serializeNetworkSpecific(os, net_proto_version);
2099 std::string s = os.str();
2101 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2102 2 + 2 + 2 + 2 + s.size(), peer_id);
2105 pkt->putRawString(s.c_str(), s.size());
2109 void Server::SendBlocks(float dtime)
2111 DSTACK(__FUNCTION_NAME);
2113 JMutexAutoLock envlock(m_env_mutex);
2114 //TODO check if one big lock could be faster then multiple small ones
2116 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2118 std::vector<PrioritySortedBlockTransfer> queue;
2120 s32 total_sending = 0;
2123 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2125 std::vector<u16> clients = m_clients.getClientIDs();
2128 for(std::vector<u16>::iterator i = clients.begin();
2129 i != clients.end(); ++i) {
2130 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2135 total_sending += client->SendingCount();
2136 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2142 // Lowest priority number comes first.
2143 // Lowest is most important.
2144 std::sort(queue.begin(), queue.end());
2147 for(u32 i=0; i<queue.size(); i++)
2149 //TODO: Calculate limit dynamically
2150 if(total_sending >= g_settings->getS32
2151 ("max_simultaneous_block_sends_server_total"))
2154 PrioritySortedBlockTransfer q = queue[i];
2156 MapBlock *block = NULL;
2159 block = m_env->getMap().getBlockNoCreate(q.pos);
2161 catch(InvalidPositionException &e)
2166 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2171 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2173 client->SentBlock(q.pos);
2179 void Server::fillMediaCache()
2181 DSTACK(__FUNCTION_NAME);
2183 infostream<<"Server: Calculating media file checksums"<<std::endl;
2185 // Collect all media file paths
2186 std::list<std::string> paths;
2187 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2188 i != m_mods.end(); i++){
2189 const ModSpec &mod = *i;
2190 paths.push_back(mod.path + DIR_DELIM + "textures");
2191 paths.push_back(mod.path + DIR_DELIM + "sounds");
2192 paths.push_back(mod.path + DIR_DELIM + "media");
2193 paths.push_back(mod.path + DIR_DELIM + "models");
2195 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2197 // Collect media file information from paths into cache
2198 for(std::list<std::string>::iterator i = paths.begin();
2199 i != paths.end(); i++)
2201 std::string mediapath = *i;
2202 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2203 for(u32 j=0; j<dirlist.size(); j++){
2204 if(dirlist[j].dir) // Ignode dirs
2206 std::string filename = dirlist[j].name;
2207 // If name contains illegal characters, ignore the file
2208 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2209 infostream<<"Server: ignoring illegal file name: \""
2210 <<filename<<"\""<<std::endl;
2213 // If name is not in a supported format, ignore it
2214 const char *supported_ext[] = {
2215 ".png", ".jpg", ".bmp", ".tga",
2216 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2218 ".x", ".b3d", ".md2", ".obj",
2221 if(removeStringEnd(filename, supported_ext) == ""){
2222 infostream<<"Server: ignoring unsupported file extension: \""
2223 <<filename<<"\""<<std::endl;
2226 // Ok, attempt to load the file and add to cache
2227 std::string filepath = mediapath + DIR_DELIM + filename;
2229 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2230 if(fis.good() == false){
2231 errorstream<<"Server::fillMediaCache(): Could not open \""
2232 <<filename<<"\" for reading"<<std::endl;
2235 std::ostringstream tmp_os(std::ios_base::binary);
2239 fis.read(buf, 1024);
2240 std::streamsize len = fis.gcount();
2241 tmp_os.write(buf, len);
2250 errorstream<<"Server::fillMediaCache(): Failed to read \""
2251 <<filename<<"\""<<std::endl;
2254 if(tmp_os.str().length() == 0){
2255 errorstream<<"Server::fillMediaCache(): Empty file \""
2256 <<filepath<<"\""<<std::endl;
2261 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2263 unsigned char *digest = sha1.getDigest();
2264 std::string sha1_base64 = base64_encode(digest, 20);
2265 std::string sha1_hex = hex_encode((char*)digest, 20);
2269 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2270 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2275 struct SendableMediaAnnouncement
2278 std::string sha1_digest;
2280 SendableMediaAnnouncement(const std::string &name_="",
2281 const std::string &sha1_digest_=""):
2283 sha1_digest(sha1_digest_)
2287 void Server::sendMediaAnnouncement(u16 peer_id)
2289 DSTACK(__FUNCTION_NAME);
2291 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2294 std::list<SendableMediaAnnouncement> file_announcements;
2296 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2297 i != m_media.end(); i++){
2299 file_announcements.push_back(
2300 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2304 std::ostringstream os(std::ios_base::binary);
2311 u16 length of sha1_digest
2316 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2317 *pkt << (u16) file_announcements.size();
2319 for(std::list<SendableMediaAnnouncement>::iterator
2320 j = file_announcements.begin();
2321 j != file_announcements.end(); ++j) {
2322 *pkt << j->name << j->sha1_digest;
2325 *pkt << g_settings->get("remote_media");
2329 struct SendableMedia
2335 SendableMedia(const std::string &name_="", const std::string &path_="",
2336 const std::string &data_=""):
2343 void Server::sendRequestedMedia(u16 peer_id,
2344 const std::list<std::string> &tosend)
2346 DSTACK(__FUNCTION_NAME);
2348 verbosestream<<"Server::sendRequestedMedia(): "
2349 <<"Sending files to client"<<std::endl;
2353 // Put 5kB in one bunch (this is not accurate)
2354 u32 bytes_per_bunch = 5000;
2356 std::vector< std::list<SendableMedia> > file_bunches;
2357 file_bunches.push_back(std::list<SendableMedia>());
2359 u32 file_size_bunch_total = 0;
2361 for(std::list<std::string>::const_iterator i = tosend.begin();
2362 i != tosend.end(); ++i)
2364 const std::string &name = *i;
2366 if(m_media.find(name) == m_media.end()) {
2367 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2368 <<"unknown file \""<<(name)<<"\""<<std::endl;
2372 //TODO get path + name
2373 std::string tpath = m_media[name].path;
2376 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2377 if(fis.good() == false){
2378 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2379 <<tpath<<"\" for reading"<<std::endl;
2382 std::ostringstream tmp_os(std::ios_base::binary);
2386 fis.read(buf, 1024);
2387 std::streamsize len = fis.gcount();
2388 tmp_os.write(buf, len);
2389 file_size_bunch_total += len;
2398 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2399 <<name<<"\""<<std::endl;
2402 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2403 <<tname<<"\""<<std::endl;*/
2405 file_bunches[file_bunches.size()-1].push_back(
2406 SendableMedia(name, tpath, tmp_os.str()));
2408 // Start next bunch if got enough data
2409 if(file_size_bunch_total >= bytes_per_bunch) {
2410 file_bunches.push_back(std::list<SendableMedia>());
2411 file_size_bunch_total = 0;
2416 /* Create and send packets */
2418 u16 num_bunches = file_bunches.size();
2419 for(u16 i = 0; i < num_bunches; i++) {
2422 u16 total number of texture bunches
2423 u16 index of this bunch
2424 u32 number of files in this bunch
2433 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2434 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2436 for(std::list<SendableMedia>::iterator
2437 j = file_bunches[i].begin();
2438 j != file_bunches[i].end(); ++j) {
2440 pkt->putLongString(j->data);
2443 verbosestream << "Server::sendRequestedMedia(): bunch "
2444 << i << "/" << num_bunches
2445 << " files=" << file_bunches[i].size()
2446 << " size=" << pkt->getSize() << std::endl;
2451 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2453 if(m_detached_inventories.count(name) == 0) {
2454 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2457 Inventory *inv = m_detached_inventories[name];
2458 std::ostringstream os(std::ios_base::binary);
2460 os << serializeString(name);
2464 std::string s = os.str();
2466 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2467 pkt->putRawString(s.c_str(), s.size());
2469 if (peer_id != PEER_ID_INEXISTENT) {
2473 m_clients.sendToAll(0, pkt, true);
2477 void Server::sendDetachedInventories(u16 peer_id)
2479 DSTACK(__FUNCTION_NAME);
2481 for(std::map<std::string, Inventory*>::iterator
2482 i = m_detached_inventories.begin();
2483 i != m_detached_inventories.end(); i++) {
2484 const std::string &name = i->first;
2485 //Inventory *inv = i->second;
2486 sendDetachedInventory(name, peer_id);
2494 void Server::DiePlayer(u16 peer_id)
2496 DSTACK(__FUNCTION_NAME);
2498 PlayerSAO *playersao = getPlayerSAO(peer_id);
2501 infostream << "Server::DiePlayer(): Player "
2502 << playersao->getPlayer()->getName()
2503 << " dies" << std::endl;
2505 playersao->setHP(0);
2507 // Trigger scripted stuff
2508 m_script->on_dieplayer(playersao);
2510 SendPlayerHP(peer_id);
2511 SendDeathscreen(peer_id, false, v3f(0,0,0));
2514 void Server::RespawnPlayer(u16 peer_id)
2516 DSTACK(__FUNCTION_NAME);
2518 PlayerSAO *playersao = getPlayerSAO(peer_id);
2521 infostream << "Server::RespawnPlayer(): Player "
2522 << playersao->getPlayer()->getName()
2523 << " respawns" << std::endl;
2525 playersao->setHP(PLAYER_MAX_HP);
2526 playersao->setBreath(PLAYER_MAX_BREATH);
2528 SendPlayerHP(peer_id);
2529 SendPlayerBreath(peer_id);
2531 bool repositioned = m_script->on_respawnplayer(playersao);
2533 v3f pos = findSpawnPos(m_env->getServerMap());
2534 // setPos will send the new position to client
2535 playersao->setPos(pos);
2539 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2541 DSTACK(__FUNCTION_NAME);
2543 SendAccessDenied(peer_id, reason);
2544 m_clients.event(peer_id, CSE_SetDenied);
2545 m_con.DisconnectPeer(peer_id);
2548 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2550 DSTACK(__FUNCTION_NAME);
2551 std::wstring message;
2554 Clear references to playing sounds
2556 for(std::map<s32, ServerPlayingSound>::iterator
2557 i = m_playing_sounds.begin();
2558 i != m_playing_sounds.end();)
2560 ServerPlayingSound &psound = i->second;
2561 psound.clients.erase(peer_id);
2562 if(psound.clients.empty())
2563 m_playing_sounds.erase(i++);
2568 Player *player = m_env->getPlayer(peer_id);
2570 // Collect information about leaving in chat
2572 if(player != NULL && reason != CDR_DENY)
2574 std::wstring name = narrow_to_wide(player->getName());
2577 message += L" left the game.";
2578 if(reason == CDR_TIMEOUT)
2579 message += L" (timed out)";
2583 /* Run scripts and remove from environment */
2587 PlayerSAO *playersao = player->getPlayerSAO();
2590 m_script->on_leaveplayer(playersao);
2592 playersao->disconnected();
2600 if(player != NULL && reason != CDR_DENY) {
2601 std::ostringstream os(std::ios_base::binary);
2602 std::vector<u16> clients = m_clients.getClientIDs();
2604 for(std::vector<u16>::iterator i = clients.begin();
2605 i != clients.end(); ++i) {
2607 Player *player = m_env->getPlayer(*i);
2611 // Get name of player
2612 os << player->getName() << " ";
2615 actionstream << player->getName() << " "
2616 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2617 << " List of players: " << os.str() << std::endl;
2621 JMutexAutoLock env_lock(m_env_mutex);
2622 m_clients.DeleteClient(peer_id);
2626 // Send leave chat message to all remaining clients
2627 if(message.length() != 0)
2628 SendChatMessage(PEER_ID_INEXISTENT,message);
2631 void Server::UpdateCrafting(Player* player)
2633 DSTACK(__FUNCTION_NAME);
2635 // Get a preview for crafting
2637 InventoryLocation loc;
2638 loc.setPlayer(player->getName());
2639 getCraftingResult(&player->inventory, preview, false, this);
2640 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2642 // Put the new preview in
2643 InventoryList *plist = player->inventory.getList("craftpreview");
2645 assert(plist->getSize() >= 1);
2646 plist->changeItem(0, preview);
2649 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2651 RemoteClient *client = getClientNoEx(peer_id,state_min);
2653 throw ClientNotFoundException("Client not found");
2657 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2659 return m_clients.getClientNoEx(peer_id, state_min);
2662 std::string Server::getPlayerName(u16 peer_id)
2664 Player *player = m_env->getPlayer(peer_id);
2666 return "[id="+itos(peer_id)+"]";
2667 return player->getName();
2670 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2672 Player *player = m_env->getPlayer(peer_id);
2675 return player->getPlayerSAO();
2678 std::wstring Server::getStatusString()
2680 std::wostringstream os(std::ios_base::binary);
2683 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2685 os<<L", uptime="<<m_uptime.get();
2687 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2688 // Information about clients
2691 std::vector<u16> clients = m_clients.getClientIDs();
2692 for(std::vector<u16>::iterator i = clients.begin();
2693 i != clients.end(); ++i) {
2695 Player *player = m_env->getPlayer(*i);
2696 // Get name of player
2697 std::wstring name = L"unknown";
2699 name = narrow_to_wide(player->getName());
2700 // Add name to information string
2708 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2709 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2710 if(g_settings->get("motd") != "")
2711 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2715 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2717 std::set<std::string> privs;
2718 m_script->getAuth(name, NULL, &privs);
2722 bool Server::checkPriv(const std::string &name, const std::string &priv)
2724 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2725 return (privs.count(priv) != 0);
2728 void Server::reportPrivsModified(const std::string &name)
2731 std::vector<u16> clients = m_clients.getClientIDs();
2732 for(std::vector<u16>::iterator i = clients.begin();
2733 i != clients.end(); ++i) {
2734 Player *player = m_env->getPlayer(*i);
2735 reportPrivsModified(player->getName());
2738 Player *player = m_env->getPlayer(name.c_str());
2741 SendPlayerPrivileges(player->peer_id);
2742 PlayerSAO *sao = player->getPlayerSAO();
2745 sao->updatePrivileges(
2746 getPlayerEffectivePrivs(name),
2751 void Server::reportInventoryFormspecModified(const std::string &name)
2753 Player *player = m_env->getPlayer(name.c_str());
2756 SendPlayerInventoryFormspec(player->peer_id);
2759 void Server::setIpBanned(const std::string &ip, const std::string &name)
2761 m_banmanager->add(ip, name);
2764 void Server::unsetIpBanned(const std::string &ip_or_name)
2766 m_banmanager->remove(ip_or_name);
2769 std::string Server::getBanDescription(const std::string &ip_or_name)
2771 return m_banmanager->getBanDescription(ip_or_name);
2774 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2776 Player *player = m_env->getPlayer(name);
2780 if (player->peer_id == PEER_ID_INEXISTENT)
2783 SendChatMessage(player->peer_id, msg);
2786 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2788 Player *player = m_env->getPlayer(playername);
2792 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2796 SendShowFormspecMessage(player->peer_id, formspec, formname);
2800 u32 Server::hudAdd(Player *player, HudElement *form) {
2804 u32 id = player->addHud(form);
2806 SendHUDAdd(player->peer_id, id, form);
2811 bool Server::hudRemove(Player *player, u32 id) {
2815 HudElement* todel = player->removeHud(id);
2822 SendHUDRemove(player->peer_id, id);
2826 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2830 SendHUDChange(player->peer_id, id, stat, data);
2834 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2838 SendHUDSetFlags(player->peer_id, flags, mask);
2839 player->hud_flags = flags;
2841 PlayerSAO* playersao = player->getPlayerSAO();
2843 if (playersao == NULL)
2846 m_script->player_event(playersao, "hud_changed");
2850 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2853 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2856 std::ostringstream os(std::ios::binary);
2857 writeS32(os, hotbar_itemcount);
2858 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2862 void Server::hudSetHotbarImage(Player *player, std::string name) {
2866 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2869 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2873 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2876 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2881 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2885 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2890 SendEyeOffset(player->peer_id, first, third);
2894 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2895 const std::string &type, const std::vector<std::string> ¶ms)
2900 SendSetSky(player->peer_id, bgcolor, type, params);
2904 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2910 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2914 void Server::notifyPlayers(const std::wstring &msg)
2916 SendChatMessage(PEER_ID_INEXISTENT,msg);
2919 void Server::spawnParticle(const char *playername, v3f pos,
2920 v3f velocity, v3f acceleration,
2921 float expirationtime, float size, bool
2922 collisiondetection, bool vertical, std::string texture)
2924 Player *player = m_env->getPlayer(playername);
2927 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2928 expirationtime, size, collisiondetection, vertical, texture);
2931 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2932 float expirationtime, float size,
2933 bool collisiondetection, bool vertical, std::string texture)
2935 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2936 expirationtime, size, collisiondetection, vertical, texture);
2939 u32 Server::addParticleSpawner(const char *playername,
2940 u16 amount, float spawntime,
2941 v3f minpos, v3f maxpos,
2942 v3f minvel, v3f maxvel,
2943 v3f minacc, v3f maxacc,
2944 float minexptime, float maxexptime,
2945 float minsize, float maxsize,
2946 bool collisiondetection, bool vertical, std::string texture)
2948 Player *player = m_env->getPlayer(playername);
2953 for(;;) // look for unused particlespawner id
2956 if (std::find(m_particlespawner_ids.begin(),
2957 m_particlespawner_ids.end(), id)
2958 == m_particlespawner_ids.end())
2960 m_particlespawner_ids.push_back(id);
2965 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2966 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2967 minexptime, maxexptime, minsize, maxsize,
2968 collisiondetection, vertical, texture, id);
2973 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2974 v3f minpos, v3f maxpos,
2975 v3f minvel, v3f maxvel,
2976 v3f minacc, v3f maxacc,
2977 float minexptime, float maxexptime,
2978 float minsize, float maxsize,
2979 bool collisiondetection, bool vertical, std::string texture)
2982 for(;;) // look for unused particlespawner id
2985 if (std::find(m_particlespawner_ids.begin(),
2986 m_particlespawner_ids.end(), id)
2987 == m_particlespawner_ids.end())
2989 m_particlespawner_ids.push_back(id);
2994 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2995 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2996 minexptime, maxexptime, minsize, maxsize,
2997 collisiondetection, vertical, texture, id);
3002 void Server::deleteParticleSpawner(const char *playername, u32 id)
3004 Player *player = m_env->getPlayer(playername);
3008 m_particlespawner_ids.erase(
3009 std::remove(m_particlespawner_ids.begin(),
3010 m_particlespawner_ids.end(), id),
3011 m_particlespawner_ids.end());
3012 SendDeleteParticleSpawner(player->peer_id, id);
3015 void Server::deleteParticleSpawnerAll(u32 id)
3017 m_particlespawner_ids.erase(
3018 std::remove(m_particlespawner_ids.begin(),
3019 m_particlespawner_ids.end(), id),
3020 m_particlespawner_ids.end());
3021 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3024 Inventory* Server::createDetachedInventory(const std::string &name)
3026 if(m_detached_inventories.count(name) > 0){
3027 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3028 delete m_detached_inventories[name];
3030 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3032 Inventory *inv = new Inventory(m_itemdef);
3034 m_detached_inventories[name] = inv;
3035 //TODO find a better way to do this
3036 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3043 BoolScopeSet(bool *dst, bool val):
3046 m_orig_state = *m_dst;
3051 *m_dst = m_orig_state;
3058 // actions: time-reversed list
3059 // Return value: success/failure
3060 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3061 std::list<std::string> *log)
3063 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3064 ServerMap *map = (ServerMap*)(&m_env->getMap());
3066 // Fail if no actions to handle
3067 if(actions.empty()){
3068 log->push_back("Nothing to do.");
3075 for(std::list<RollbackAction>::const_iterator
3076 i = actions.begin();
3077 i != actions.end(); i++)
3079 const RollbackAction &action = *i;
3081 bool success = action.applyRevert(map, this, this);
3084 std::ostringstream os;
3085 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3086 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3088 log->push_back(os.str());
3090 std::ostringstream os;
3091 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3092 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3094 log->push_back(os.str());
3098 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3099 <<" failed"<<std::endl;
3101 // Call it done if less than half failed
3102 return num_failed <= num_tried/2;
3105 // IGameDef interface
3107 IItemDefManager* Server::getItemDefManager()
3111 INodeDefManager* Server::getNodeDefManager()
3115 ICraftDefManager* Server::getCraftDefManager()
3119 ITextureSource* Server::getTextureSource()
3123 IShaderSource* Server::getShaderSource()
3127 scene::ISceneManager* Server::getSceneManager()
3132 u16 Server::allocateUnknownNodeId(const std::string &name)
3134 return m_nodedef->allocateDummy(name);
3136 ISoundManager* Server::getSoundManager()
3138 return &dummySoundManager;
3140 MtEventManager* Server::getEventManager()
3145 IWritableItemDefManager* Server::getWritableItemDefManager()
3149 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3153 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3158 const ModSpec* Server::getModSpec(const std::string &modname)
3160 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3161 i != m_mods.end(); i++){
3162 const ModSpec &mod = *i;
3163 if(mod.name == modname)
3168 void Server::getModNames(std::vector<std::string> &modlist)
3170 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3171 modlist.push_back(i->name);
3174 std::string Server::getBuiltinLuaPath()
3176 return porting::path_share + DIR_DELIM + "builtin";
3179 v3f findSpawnPos(ServerMap &map)
3181 //return v3f(50,50,50)*BS;
3186 nodepos = v2s16(0,0);
3191 s16 water_level = map.getWaterLevel();
3193 // Try to find a good place a few times
3194 for(s32 i=0; i<1000; i++)
3197 // We're going to try to throw the player to this position
3198 v2s16 nodepos2d = v2s16(
3199 -range + (myrand() % (range * 2)),
3200 -range + (myrand() % (range * 2)));
3202 // Get ground height at point
3203 s16 groundheight = map.findGroundLevel(nodepos2d);
3204 if (groundheight <= water_level) // Don't go underwater
3206 if (groundheight > water_level + 6) // Don't go to high places
3209 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3210 bool is_good = false;
3212 for (s32 i = 0; i < 10; i++) {
3213 v3s16 blockpos = getNodeBlockPos(nodepos);
3214 map.emergeBlock(blockpos, true);
3215 content_t c = map.getNodeNoEx(nodepos).getContent();
3216 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3218 if (air_count >= 2){
3226 // Found a good place
3227 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3233 return intToFloat(nodepos, BS);
3236 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3238 bool newplayer = false;
3241 Try to get an existing player
3243 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3245 // If player is already connected, cancel
3246 if(player != NULL && player->peer_id != 0)
3248 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3253 If player with the wanted peer_id already exists, cancel.
3255 if(m_env->getPlayer(peer_id) != NULL)
3257 infostream<<"emergePlayer(): Player with wrong name but same"
3258 " peer_id already exists"<<std::endl;
3262 // Load player if it isn't already loaded
3264 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3267 // Create player if it doesn't exist
3270 player = new RemotePlayer(this, name);
3271 // Set player position
3272 infostream<<"Server: Finding spawn place for player \""
3273 <<name<<"\""<<std::endl;
3274 v3f pos = findSpawnPos(m_env->getServerMap());
3275 player->setPosition(pos);
3277 // Make sure the player is saved
3278 player->setModified(true);
3280 // Add player to environment
3281 m_env->addPlayer(player);
3284 // Create a new player active object
3285 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3286 getPlayerEffectivePrivs(player->getName()),
3289 /* Clean up old HUD elements from previous sessions */
3292 /* Add object to environment */
3293 m_env->addActiveObject(playersao);
3297 m_script->on_newplayer(playersao);
3303 void dedicated_server_loop(Server &server, bool &kill)
3305 DSTACK(__FUNCTION_NAME);
3307 verbosestream<<"dedicated_server_loop()"<<std::endl;
3309 IntervalLimiter m_profiler_interval;
3313 float steplen = g_settings->getFloat("dedicated_server_step");
3314 // This is kind of a hack but can be done like this
3315 // because server.step() is very light
3317 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3318 sleep_ms((int)(steplen*1000.0));
3320 server.step(steplen);
3322 if(server.getShutdownRequested() || kill)
3324 infostream<<"Dedicated server quitting"<<std::endl;
3326 if(g_settings->getBool("server_announce"))
3327 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3335 float profiler_print_interval =
3336 g_settings->getFloat("profiler_print_interval");
3337 if(profiler_print_interval != 0)
3339 if(m_profiler_interval.step(steplen, profiler_print_interval))
3341 infostream<<"Profiler:"<<std::endl;
3342 g_profiler->print(infostream);
3343 g_profiler->clear();