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"));
588 JMutexAutoLock lock(m_env_mutex);
590 std::list<u16> clientids = m_clients.getClientIDs();
592 ScopeProfiler sp(g_profiler, "Server: handle players");
594 for(std::list<u16>::iterator
595 i = clientids.begin();
596 i != clientids.end(); ++i)
598 PlayerSAO *playersao = getPlayerSAO(*i);
599 if(playersao == NULL)
603 if(playersao->m_moved) {
605 playersao->m_moved = false;
610 /* Transform liquids */
611 m_liquid_transform_timer += dtime;
612 if(m_liquid_transform_timer >= m_liquid_transform_every)
614 m_liquid_transform_timer -= m_liquid_transform_every;
616 JMutexAutoLock lock(m_env_mutex);
618 ScopeProfiler sp(g_profiler, "Server: liquid transform");
620 std::map<v3s16, MapBlock*> modified_blocks;
621 m_env->getMap().transformLiquids(modified_blocks);
626 core::map<v3s16, MapBlock*> lighting_modified_blocks;
627 ServerMap &map = ((ServerMap&)m_env->getMap());
628 map.updateLighting(modified_blocks, lighting_modified_blocks);
630 // Add blocks modified by lighting to modified_blocks
631 for(core::map<v3s16, MapBlock*>::Iterator
632 i = lighting_modified_blocks.getIterator();
633 i.atEnd() == false; i++)
635 MapBlock *block = i.getNode()->getValue();
636 modified_blocks.insert(block->getPos(), block);
640 Set the modified blocks unsent for all the clients
642 if(!modified_blocks.empty())
644 SetBlocksNotSent(modified_blocks);
647 m_clients.step(dtime);
649 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
651 // send masterserver announce
653 float &counter = m_masterserver_timer;
654 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
655 g_settings->getBool("server_announce"))
657 ServerList::sendAnnounce(counter ? "update" : "start",
658 m_bind_addr.getPort(),
659 m_clients.getPlayerNames(),
661 m_env->getGameTime(),
664 m_emerge->params.mg_name,
673 Check added and deleted active objects
676 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
677 JMutexAutoLock envlock(m_env_mutex);
680 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
681 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
683 // Radius inside which objects are active
684 s16 radius = g_settings->getS16("active_object_send_range_blocks");
685 s16 player_radius = g_settings->getS16("player_transfer_distance");
687 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
688 !g_settings->getBool("unlimited_player_transfer_distance"))
689 player_radius = radius;
691 radius *= MAP_BLOCKSIZE;
692 player_radius *= MAP_BLOCKSIZE;
694 for(std::map<u16, RemoteClient*>::iterator
696 i != clients.end(); ++i)
698 RemoteClient *client = i->second;
700 // If definitions and textures have not been sent, don't
701 // send objects either
702 if (client->getState() < CS_DefinitionsSent)
705 Player *player = m_env->getPlayer(client->peer_id);
708 // This can happen if the client timeouts somehow
709 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
711 <<" has no associated player"<<std::endl;*/
714 v3s16 pos = floatToInt(player->getPosition(), BS);
716 std::set<u16> removed_objects;
717 std::set<u16> added_objects;
718 m_env->getRemovedActiveObjects(pos, radius, player_radius,
719 client->m_known_objects, removed_objects);
720 m_env->getAddedActiveObjects(pos, radius, player_radius,
721 client->m_known_objects, added_objects);
723 // Ignore if nothing happened
724 if(removed_objects.empty() && added_objects.empty())
726 //infostream<<"active objects: none changed"<<std::endl;
730 std::string data_buffer;
734 // Handle removed objects
735 writeU16((u8*)buf, removed_objects.size());
736 data_buffer.append(buf, 2);
737 for(std::set<u16>::iterator
738 i = removed_objects.begin();
739 i != removed_objects.end(); ++i)
743 ServerActiveObject* obj = m_env->getActiveObject(id);
745 // Add to data buffer for sending
746 writeU16((u8*)buf, id);
747 data_buffer.append(buf, 2);
749 // Remove from known objects
750 client->m_known_objects.erase(id);
752 if(obj && obj->m_known_by_count > 0)
753 obj->m_known_by_count--;
756 // Handle added objects
757 writeU16((u8*)buf, added_objects.size());
758 data_buffer.append(buf, 2);
759 for(std::set<u16>::iterator
760 i = added_objects.begin();
761 i != added_objects.end(); ++i)
765 ServerActiveObject* obj = m_env->getActiveObject(id);
768 u8 type = ACTIVEOBJECT_TYPE_INVALID;
770 infostream<<"WARNING: "<<__FUNCTION_NAME
771 <<": NULL object"<<std::endl;
773 type = obj->getSendType();
775 // Add to data buffer for sending
776 writeU16((u8*)buf, id);
777 data_buffer.append(buf, 2);
778 writeU8((u8*)buf, type);
779 data_buffer.append(buf, 1);
782 data_buffer.append(serializeLongString(
783 obj->getClientInitializationData(client->net_proto_version)));
785 data_buffer.append(serializeLongString(""));
787 // Add to known objects
788 client->m_known_objects.insert(id);
791 obj->m_known_by_count++;
794 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
795 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
798 verbosestream << "Server: Sent object remove/add: "
799 << removed_objects.size() << " removed, "
800 << added_objects.size() << " added, "
801 << "packet size is " << pkt->getSize() << std::endl;
812 JMutexAutoLock envlock(m_env_mutex);
813 ScopeProfiler sp(g_profiler, "Server: sending object messages");
816 // Value = data sent by object
817 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
819 // Get active object messages from environment
822 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
826 std::list<ActiveObjectMessage>* message_list = NULL;
827 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
828 n = buffered_messages.find(aom.id);
829 if(n == buffered_messages.end())
831 message_list = new std::list<ActiveObjectMessage>;
832 buffered_messages[aom.id] = message_list;
836 message_list = n->second;
838 message_list->push_back(aom);
842 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
843 // Route data to every client
844 for(std::map<u16, RemoteClient*>::iterator
846 i != clients.end(); ++i)
848 RemoteClient *client = i->second;
849 std::string reliable_data;
850 std::string unreliable_data;
851 // Go through all objects in message buffer
852 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
853 j = buffered_messages.begin();
854 j != buffered_messages.end(); ++j)
856 // If object is not known by client, skip it
858 if(client->m_known_objects.find(id) == client->m_known_objects.end())
860 // Get message list of object
861 std::list<ActiveObjectMessage>* list = j->second;
862 // Go through every message
863 for(std::list<ActiveObjectMessage>::iterator
864 k = list->begin(); k != list->end(); ++k)
866 // Compose the full new data with header
867 ActiveObjectMessage aom = *k;
868 std::string new_data;
871 writeU16((u8*)&buf[0], aom.id);
872 new_data.append(buf, 2);
874 new_data += serializeString(aom.datastring);
875 // Add data to buffer
877 reliable_data += new_data;
879 unreliable_data += new_data;
883 reliable_data and unreliable_data are now ready.
886 if(reliable_data.size() > 0) {
887 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
890 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
894 if(unreliable_data.size() > 0) {
895 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
898 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
904 // Clear buffered_messages
905 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
906 i = buffered_messages.begin();
907 i != buffered_messages.end(); ++i)
914 Send queued-for-sending map edit events.
917 // We will be accessing the environment
918 JMutexAutoLock lock(m_env_mutex);
920 // Don't send too many at a time
923 // Single change sending is disabled if queue size is not small
924 bool disable_single_change_sending = false;
925 if(m_unsent_map_edit_queue.size() >= 4)
926 disable_single_change_sending = true;
928 int event_count = m_unsent_map_edit_queue.size();
930 // We'll log the amount of each
933 while(m_unsent_map_edit_queue.size() != 0)
935 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
937 // Players far away from the change are stored here.
938 // Instead of sending the changes, MapBlocks are set not sent
940 std::list<u16> far_players;
942 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
944 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
945 prof.add("MEET_ADDNODE", 1);
946 if(disable_single_change_sending)
947 sendAddNode(event->p, event->n, event->already_known_by_peer,
948 &far_players, 5, event->type == MEET_ADDNODE);
950 sendAddNode(event->p, event->n, event->already_known_by_peer,
951 &far_players, 30, event->type == MEET_ADDNODE);
953 else if(event->type == MEET_REMOVENODE)
955 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
956 prof.add("MEET_REMOVENODE", 1);
957 if(disable_single_change_sending)
958 sendRemoveNode(event->p, event->already_known_by_peer,
961 sendRemoveNode(event->p, event->already_known_by_peer,
964 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
966 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
967 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
968 setBlockNotSent(event->p);
970 else if(event->type == MEET_OTHER)
972 infostream<<"Server: MEET_OTHER"<<std::endl;
973 prof.add("MEET_OTHER", 1);
974 for(std::set<v3s16>::iterator
975 i = event->modified_blocks.begin();
976 i != event->modified_blocks.end(); ++i)
983 prof.add("unknown", 1);
984 infostream<<"WARNING: Server: Unknown MapEditEvent "
985 <<((u32)event->type)<<std::endl;
989 Set blocks not sent to far players
991 if(!far_players.empty())
993 // Convert list format to that wanted by SetBlocksNotSent
994 std::map<v3s16, MapBlock*> modified_blocks2;
995 for(std::set<v3s16>::iterator
996 i = event->modified_blocks.begin();
997 i != event->modified_blocks.end(); ++i)
999 modified_blocks2[*i] =
1000 m_env->getMap().getBlockNoCreateNoEx(*i);
1002 // Set blocks not sent
1003 for(std::list<u16>::iterator
1004 i = far_players.begin();
1005 i != far_players.end(); ++i)
1008 RemoteClient *client = getClient(peer_id);
1011 client->SetBlocksNotSent(modified_blocks2);
1017 /*// Don't send too many at a time
1019 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1023 if(event_count >= 5){
1024 infostream<<"Server: MapEditEvents:"<<std::endl;
1025 prof.print(infostream);
1026 } else if(event_count != 0){
1027 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1028 prof.print(verbosestream);
1034 Trigger emergethread (it somehow gets to a non-triggered but
1035 bysy state sometimes)
1038 float &counter = m_emergethread_trigger_timer;
1044 m_emerge->startThreads();
1048 // Save map, players and auth stuff
1050 float &counter = m_savemap_timer;
1052 if(counter >= g_settings->getFloat("server_map_save_interval"))
1055 JMutexAutoLock lock(m_env_mutex);
1057 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1060 if (m_banmanager->isModified()) {
1061 m_banmanager->save();
1064 // Save changed parts of map
1065 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1068 m_env->saveLoadedPlayers();
1070 // Save environment metadata
1076 void Server::Receive()
1078 DSTACK(__FUNCTION_NAME);
1079 SharedBuffer<u8> data;
1083 datasize = m_con.Receive(peer_id,data);
1084 ProcessData(*data, datasize, peer_id);
1086 catch(con::InvalidIncomingDataException &e) {
1087 infostream<<"Server::Receive(): "
1088 "InvalidIncomingDataException: what()="
1089 <<e.what()<<std::endl;
1091 catch(SerializationError &e) {
1092 infostream<<"Server::Receive(): "
1093 "SerializationError: what()="
1094 <<e.what()<<std::endl;
1096 catch(ClientStateError &e) {
1097 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1098 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1099 L"Try reconnecting or updating your client");
1101 catch(con::PeerNotFoundException &e) {
1106 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1108 std::string playername = "";
1109 PlayerSAO *playersao = NULL;
1112 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1113 if (client != NULL) {
1114 playername = client->getName();
1115 playersao = emergePlayer(playername.c_str(), peer_id);
1117 } catch (std::exception &e) {
1123 RemotePlayer *player =
1124 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1126 // If failed, cancel
1127 if((playersao == NULL) || (player == NULL)) {
1128 if(player && player->peer_id != 0) {
1129 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1130 <<" (player allocated to an another client)"<<std::endl;
1131 DenyAccess(peer_id, L"Another client is connected with this "
1132 L"name. If your client closed unexpectedly, try again in "
1135 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1137 DenyAccess(peer_id, L"Could not allocate player.");
1143 Send complete position information
1145 SendMovePlayer(peer_id);
1148 SendPlayerPrivileges(peer_id);
1150 // Send inventory formspec
1151 SendPlayerInventoryFormspec(peer_id);
1154 SendInventory(peer_id);
1157 if(g_settings->getBool("enable_damage"))
1158 SendPlayerHP(peer_id);
1161 SendPlayerBreath(peer_id);
1163 // Show death screen if necessary
1165 SendDeathscreen(peer_id, false, v3f(0,0,0));
1167 // Note things in chat if not in simple singleplayer mode
1168 if(!m_simple_singleplayer_mode) {
1169 // Send information about server to player in chat
1170 SendChatMessage(peer_id, getStatusString());
1172 // Send information about joining in chat
1174 std::wstring name = L"unknown";
1175 Player *player = m_env->getPlayer(peer_id);
1177 name = narrow_to_wide(player->getName());
1179 std::wstring message;
1182 message += L" joined the game.";
1183 SendChatMessage(PEER_ID_INEXISTENT,message);
1186 Address addr = getPeerAddress(player->peer_id);
1187 std::string ip_str = addr.serializeString();
1188 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1193 std::vector<std::string> names = m_clients.getPlayerNames();
1195 actionstream<<player->getName() <<" joins game. List of players: ";
1197 for (std::vector<std::string>::iterator i = names.begin();
1198 i != names.end(); i++) {
1199 actionstream << *i << " ";
1202 actionstream << player->getName() <<std::endl;
1207 inline void Server::handleCommand(NetworkPacket* pkt)
1209 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1210 (this->*opHandle.handler)(pkt);
1213 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1215 DSTACK(__FUNCTION_NAME);
1216 // Environment is locked first.
1217 JMutexAutoLock envlock(m_env_mutex);
1219 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1222 Address address = getPeerAddress(peer_id);
1223 std::string addr_s = address.serializeString();
1225 if(m_banmanager->isIpBanned(addr_s)) {
1226 std::string ban_name = m_banmanager->getBanName(addr_s);
1227 infostream << "Server: A banned client tried to connect from "
1228 << addr_s << "; banned name was "
1229 << ban_name << std::endl;
1230 // This actually doesn't seem to transfer to the client
1231 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1232 + narrow_to_wide(ban_name));
1236 catch(con::PeerNotFoundException &e) {
1238 * no peer for this packet found
1239 * most common reason is peer timeout, e.g. peer didn't
1240 * respond for some time, your server was overloaded or
1243 infostream << "Server::ProcessData(): Cancelling: peer "
1244 << peer_id << " not found" << std::endl;
1252 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1254 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1256 // Command must be handled into ToServerCommandHandler
1257 if (command >= TOSERVER_NUM_MSG_TYPES) {
1258 infostream << "Server: Ignoring unknown command "
1259 << command << std::endl;
1262 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1268 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1270 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1271 errorstream << "Server::ProcessData(): Cancelling: Peer"
1272 " serialization format invalid or not initialized."
1273 " Skipping incoming command=" << command << std::endl;
1279 /* Handle commands related to client startup */
1280 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1286 if (m_clients.getClientState(peer_id) < CS_Active) {
1287 if (command == TOSERVER_PLAYERPOS) return;
1289 errorstream << "Got packet command: " << command << " for peer id "
1290 << peer_id << " but client isn't active yet. Dropping packet "
1301 catch(SendFailedException &e) {
1302 errorstream << "Server::ProcessData(): SendFailedException: "
1303 << "what=" << e.what()
1308 void Server::setTimeOfDay(u32 time)
1310 m_env->setTimeOfDay(time);
1311 m_time_of_day_send_timer = 0;
1314 void Server::onMapEditEvent(MapEditEvent *event)
1316 if(m_ignore_map_edit_events)
1318 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1320 MapEditEvent *e = event->clone();
1321 m_unsent_map_edit_queue.push_back(e);
1324 Inventory* Server::getInventory(const InventoryLocation &loc)
1327 case InventoryLocation::UNDEFINED:
1328 case InventoryLocation::CURRENT_PLAYER:
1330 case InventoryLocation::PLAYER:
1332 Player *player = m_env->getPlayer(loc.name.c_str());
1335 PlayerSAO *playersao = player->getPlayerSAO();
1338 return playersao->getInventory();
1341 case InventoryLocation::NODEMETA:
1343 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1346 return meta->getInventory();
1349 case InventoryLocation::DETACHED:
1351 if(m_detached_inventories.count(loc.name) == 0)
1353 return m_detached_inventories[loc.name];
1361 void Server::setInventoryModified(const InventoryLocation &loc)
1364 case InventoryLocation::UNDEFINED:
1366 case InventoryLocation::PLAYER:
1368 Player *player = m_env->getPlayer(loc.name.c_str());
1371 PlayerSAO *playersao = player->getPlayerSAO();
1375 SendInventory(playersao->getPeerID());
1378 case InventoryLocation::NODEMETA:
1380 v3s16 blockpos = getNodeBlockPos(loc.p);
1382 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1384 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1386 setBlockNotSent(blockpos);
1389 case InventoryLocation::DETACHED:
1391 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1399 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1401 std::list<u16> clients = m_clients.getClientIDs();
1403 // Set the modified blocks unsent for all the clients
1404 for (std::list<u16>::iterator
1405 i = clients.begin();
1406 i != clients.end(); ++i) {
1407 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
1409 client->SetBlocksNotSent(block);
1414 void Server::peerAdded(con::Peer *peer)
1416 DSTACK(__FUNCTION_NAME);
1417 verbosestream<<"Server::peerAdded(): peer->id="
1418 <<peer->id<<std::endl;
1421 c.type = con::PEER_ADDED;
1422 c.peer_id = peer->id;
1424 m_peer_change_queue.push_back(c);
1427 void Server::deletingPeer(con::Peer *peer, bool timeout)
1429 DSTACK(__FUNCTION_NAME);
1430 verbosestream<<"Server::deletingPeer(): peer->id="
1431 <<peer->id<<", timeout="<<timeout<<std::endl;
1433 m_clients.event(peer->id, CSE_Disconnect);
1435 c.type = con::PEER_REMOVED;
1436 c.peer_id = peer->id;
1437 c.timeout = timeout;
1438 m_peer_change_queue.push_back(c);
1441 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1443 *retval = m_con.getPeerStat(peer_id,type);
1444 if (*retval == -1) return false;
1448 bool Server::getClientInfo(
1457 std::string* vers_string
1460 *state = m_clients.getClientState(peer_id);
1462 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1464 if (client == NULL) {
1469 *uptime = client->uptime();
1470 *ser_vers = client->serialization_version;
1471 *prot_vers = client->net_proto_version;
1473 *major = client->getMajor();
1474 *minor = client->getMinor();
1475 *patch = client->getPatch();
1476 *vers_string = client->getPatch();
1483 void Server::handlePeerChanges()
1485 while(m_peer_change_queue.size() > 0)
1487 con::PeerChange c = m_peer_change_queue.pop_front();
1489 verbosestream<<"Server: Handling peer change: "
1490 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1495 case con::PEER_ADDED:
1496 m_clients.CreateClient(c.peer_id);
1499 case con::PEER_REMOVED:
1500 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1504 assert("Invalid peer change event received!" == 0);
1510 void Server::Send(NetworkPacket* pkt)
1512 m_clients.send(pkt->getPeerId(),
1513 clientCommandFactoryTable[pkt->getCommand()].channel,
1515 clientCommandFactoryTable[pkt->getCommand()].reliable);
1518 void Server::SendMovement(u16 peer_id)
1520 DSTACK(__FUNCTION_NAME);
1521 std::ostringstream os(std::ios_base::binary);
1523 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1525 *pkt << g_settings->getFloat("movement_acceleration_default");
1526 *pkt << g_settings->getFloat("movement_acceleration_air");
1527 *pkt << g_settings->getFloat("movement_acceleration_fast");
1528 *pkt << g_settings->getFloat("movement_speed_walk");
1529 *pkt << g_settings->getFloat("movement_speed_crouch");
1530 *pkt << g_settings->getFloat("movement_speed_fast");
1531 *pkt << g_settings->getFloat("movement_speed_climb");
1532 *pkt << g_settings->getFloat("movement_speed_jump");
1533 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1534 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1535 *pkt << g_settings->getFloat("movement_liquid_sink");
1536 *pkt << g_settings->getFloat("movement_gravity");
1541 void Server::SendHP(u16 peer_id, u8 hp)
1543 DSTACK(__FUNCTION_NAME);
1545 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1550 void Server::SendBreath(u16 peer_id, u16 breath)
1552 DSTACK(__FUNCTION_NAME);
1554 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1555 *pkt << (u16) breath;
1559 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1561 DSTACK(__FUNCTION_NAME);
1563 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1568 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1569 v3f camera_point_target)
1571 DSTACK(__FUNCTION_NAME);
1573 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1574 *pkt << set_camera_point_target << camera_point_target;
1578 void Server::SendItemDef(u16 peer_id,
1579 IItemDefManager *itemdef, u16 protocol_version)
1581 DSTACK(__FUNCTION_NAME);
1583 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1587 u32 length of the next item
1588 zlib-compressed serialized ItemDefManager
1590 std::ostringstream tmp_os(std::ios::binary);
1591 itemdef->serialize(tmp_os, protocol_version);
1592 std::ostringstream tmp_os2(std::ios::binary);
1593 compressZlib(tmp_os.str(), tmp_os2);
1594 pkt->putLongString(tmp_os2.str());
1597 verbosestream << "Server: Sending item definitions to id(" << peer_id
1598 << "): size=" << pkt->getSize() << std::endl;
1603 void Server::SendNodeDef(u16 peer_id,
1604 INodeDefManager *nodedef, u16 protocol_version)
1606 DSTACK(__FUNCTION_NAME);
1608 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1612 u32 length of the next item
1613 zlib-compressed serialized NodeDefManager
1615 std::ostringstream tmp_os(std::ios::binary);
1616 nodedef->serialize(tmp_os, protocol_version);
1617 std::ostringstream tmp_os2(std::ios::binary);
1618 compressZlib(tmp_os.str(), tmp_os2);
1620 pkt->putLongString(tmp_os2.str());
1623 verbosestream << "Server: Sending node definitions to id(" << peer_id
1624 << "): size=" << pkt->getSize() << std::endl;
1630 Non-static send methods
1633 void Server::SendInventory(u16 peer_id)
1635 DSTACK(__FUNCTION_NAME);
1637 PlayerSAO *playersao = getPlayerSAO(peer_id);
1640 UpdateCrafting(playersao->getPlayer());
1646 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0, peer_id);
1648 std::ostringstream os;
1649 playersao->getInventory()->serialize(os);
1651 std::string s = os.str();
1653 pkt->putRawString(s.c_str(), s.size());
1657 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1659 DSTACK(__FUNCTION_NAME);
1661 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1664 if (peer_id != PEER_ID_INEXISTENT) {
1668 m_clients.sendToAll(0,pkt,true);
1672 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1673 const std::string &formname)
1675 DSTACK(__FUNCTION_NAME);
1677 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1679 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1685 // Spawns a particle on peer with peer_id
1686 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1687 float expirationtime, float size, bool collisiondetection,
1688 bool vertical, std::string texture)
1690 DSTACK(__FUNCTION_NAME);
1692 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1694 *pkt << pos << velocity << acceleration << expirationtime
1695 << size << collisiondetection;
1696 pkt->putLongString(texture);
1699 if (peer_id != PEER_ID_INEXISTENT) {
1703 m_clients.sendToAll(0,pkt,true);
1707 // Adds a ParticleSpawner on peer with peer_id
1708 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1709 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1710 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1712 DSTACK(__FUNCTION_NAME);
1714 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1716 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1717 << minacc << maxacc << minexptime << maxexptime << minsize
1718 << maxsize << collisiondetection;
1720 pkt->putLongString(texture);
1722 *pkt << id << vertical;
1724 if (peer_id != PEER_ID_INEXISTENT) {
1728 m_clients.sendToAll(0, pkt, true);
1732 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1734 DSTACK(__FUNCTION_NAME);
1736 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1738 // Ugly error in this packet
1741 if (peer_id != PEER_ID_INEXISTENT) {
1745 m_clients.sendToAll(0, pkt, true);
1750 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1752 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1754 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1755 << form->text << form->number << form->item << form->dir
1756 << form->align << form->offset << form->world_pos << form->size;
1761 void Server::SendHUDRemove(u16 peer_id, u32 id)
1763 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1768 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1770 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1771 *pkt << id << (u8) stat;
1775 case HUD_STAT_SCALE:
1776 case HUD_STAT_ALIGN:
1777 case HUD_STAT_OFFSET:
1778 *pkt << *(v2f *) value;
1782 *pkt << *(std::string *) value;
1784 case HUD_STAT_WORLD_POS:
1785 *pkt << *(v3f *) value;
1788 *pkt << *(v2s32 *) value;
1790 case HUD_STAT_NUMBER:
1794 *pkt << *(u32 *) value;
1801 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1803 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1805 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1807 *pkt << flags << mask;
1812 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1814 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1815 *pkt << param << value;
1819 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1820 const std::string &type, const std::vector<std::string> ¶ms)
1822 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1823 *pkt << bgcolor << type << (u16) params.size();
1825 for(size_t i=0; i<params.size(); i++)
1831 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1834 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1837 *pkt << do_override << (u16) (ratio * 65535);
1842 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1844 DSTACK(__FUNCTION_NAME);
1846 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1847 *pkt << time << time_speed;
1849 if (peer_id == PEER_ID_INEXISTENT) {
1850 m_clients.sendToAll(0, pkt, true);
1857 void Server::SendPlayerHP(u16 peer_id)
1859 DSTACK(__FUNCTION_NAME);
1860 PlayerSAO *playersao = getPlayerSAO(peer_id);
1862 SendHP(peer_id, playersao->getHP());
1863 m_script->player_event(playersao,"health_changed");
1865 // Send to other clients
1866 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1867 ActiveObjectMessage aom(playersao->getId(), true, str);
1868 playersao->m_messages_out.push_back(aom);
1871 void Server::SendPlayerBreath(u16 peer_id)
1873 DSTACK(__FUNCTION_NAME);
1874 PlayerSAO *playersao = getPlayerSAO(peer_id);
1877 m_script->player_event(playersao, "breath_changed");
1878 SendBreath(peer_id, playersao->getBreath());
1881 void Server::SendMovePlayer(u16 peer_id)
1883 DSTACK(__FUNCTION_NAME);
1884 Player *player = m_env->getPlayer(peer_id);
1887 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1888 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1891 v3f pos = player->getPosition();
1892 f32 pitch = player->getPitch();
1893 f32 yaw = player->getYaw();
1894 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1895 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1904 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1906 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1909 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1910 << animation_frames[3] << animation_speed;
1915 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1917 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1918 *pkt << first << third;
1921 void Server::SendPlayerPrivileges(u16 peer_id)
1923 Player *player = m_env->getPlayer(peer_id);
1925 if(player->peer_id == PEER_ID_INEXISTENT)
1928 std::set<std::string> privs;
1929 m_script->getAuth(player->getName(), NULL, &privs);
1931 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1932 *pkt << (u16) privs.size();
1934 for(std::set<std::string>::const_iterator i = privs.begin();
1935 i != privs.end(); i++) {
1942 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1944 Player *player = m_env->getPlayer(peer_id);
1946 if(player->peer_id == PEER_ID_INEXISTENT)
1949 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1950 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1954 s32 Server::playSound(const SimpleSoundSpec &spec,
1955 const ServerSoundParams ¶ms)
1957 // Find out initial position of sound
1958 bool pos_exists = false;
1959 v3f pos = params.getPos(m_env, &pos_exists);
1960 // If position is not found while it should be, cancel sound
1961 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1964 // Filter destination clients
1965 std::list<u16> dst_clients;
1966 if(params.to_player != "")
1968 Player *player = m_env->getPlayer(params.to_player.c_str());
1970 infostream<<"Server::playSound: Player \""<<params.to_player
1971 <<"\" not found"<<std::endl;
1974 if(player->peer_id == PEER_ID_INEXISTENT){
1975 infostream<<"Server::playSound: Player \""<<params.to_player
1976 <<"\" not connected"<<std::endl;
1979 dst_clients.push_back(player->peer_id);
1983 std::list<u16> clients = m_clients.getClientIDs();
1985 for(std::list<u16>::iterator
1986 i = clients.begin(); i != clients.end(); ++i)
1988 Player *player = m_env->getPlayer(*i);
1992 if(player->getPosition().getDistanceFrom(pos) >
1993 params.max_hear_distance)
1996 dst_clients.push_back(*i);
1999 if(dst_clients.empty())
2003 s32 id = m_next_sound_id++;
2004 // The sound will exist as a reference in m_playing_sounds
2005 m_playing_sounds[id] = ServerPlayingSound();
2006 ServerPlayingSound &psound = m_playing_sounds[id];
2007 psound.params = params;
2008 for(std::list<u16>::iterator i = dst_clients.begin();
2009 i != dst_clients.end(); i++)
2010 psound.clients.insert(*i);
2012 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
2013 *pkt << id << spec.name << (float) (spec.gain * params.gain)
2014 << (u8) params.type << pos << params.object << params.loop;
2015 for(std::list<u16>::iterator i = dst_clients.begin();
2016 i != dst_clients.end(); i++) {
2018 m_clients.send(*i, 0, pkt, true, false);
2023 void Server::stopSound(s32 handle)
2025 // Get sound reference
2026 std::map<s32, ServerPlayingSound>::iterator i =
2027 m_playing_sounds.find(handle);
2028 if(i == m_playing_sounds.end())
2030 ServerPlayingSound &psound = i->second;
2032 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2035 for(std::set<u16>::iterator i = psound.clients.begin();
2036 i != psound.clients.end(); i++) {
2038 m_clients.send(*i, 0, pkt, true, false);
2041 // Remove sound reference
2042 m_playing_sounds.erase(i);
2045 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2046 std::list<u16> *far_players, float far_d_nodes)
2048 float maxd = far_d_nodes*BS;
2049 v3f p_f = intToFloat(p, BS);
2051 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2054 std::list<u16> clients = m_clients.getClientIDs();
2055 for(std::list<u16>::iterator
2056 i = clients.begin();
2057 i != clients.end(); ++i) {
2060 if(Player *player = m_env->getPlayer(*i)) {
2061 // If player is far away, only set modified blocks not sent
2062 v3f player_pos = player->getPosition();
2063 if(player_pos.getDistanceFrom(p_f) > maxd) {
2064 far_players->push_back(*i);
2071 m_clients.send(*i, 0, pkt, true, false);
2073 // This loop needs the deletion of the packet here
2077 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2078 std::list<u16> *far_players, float far_d_nodes,
2079 bool remove_metadata)
2081 float maxd = far_d_nodes*BS;
2082 v3f p_f = intToFloat(p, BS);
2084 std::list<u16> clients = m_clients.getClientIDs();
2085 for(std::list<u16>::iterator
2086 i = clients.begin();
2087 i != clients.end(); ++i)
2093 Player *player = m_env->getPlayer(*i);
2096 // If player is far away, only set modified blocks not sent
2097 v3f player_pos = player->getPosition();
2098 if(player_pos.getDistanceFrom(p_f) > maxd)
2100 far_players->push_back(*i);
2106 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2108 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2110 *pkt << p << n.param0 << n.param1 << n.param2
2111 << (u8) (remove_metadata ? 0 : 1);
2113 if (!remove_metadata) {
2114 if (client->net_proto_version <= 21) {
2115 // Old clients always clear metadata; fix it
2116 // by sending the full block again.
2117 client->SetBlockNotSent(p);
2124 if (pkt->getSize() > 0)
2125 m_clients.send(*i, 0, pkt, true);
2129 void Server::setBlockNotSent(v3s16 p)
2131 std::list<u16> clients = m_clients.getClientIDs();
2133 for(std::list<u16>::iterator
2134 i = clients.begin();
2135 i != clients.end(); ++i)
2137 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2138 client->SetBlockNotSent(p);
2143 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2145 DSTACK(__FUNCTION_NAME);
2147 v3s16 p = block->getPos();
2150 Create a packet with the block in the right format
2153 std::ostringstream os(std::ios_base::binary);
2154 block->serialize(os, ver, false);
2155 block->serializeNetworkSpecific(os, net_proto_version);
2156 std::string s = os.str();
2158 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2159 2 + 2 + 2 + 2 + s.size(), peer_id);
2162 pkt->putRawString(s.c_str(), s.size());
2166 void Server::SendBlocks(float dtime)
2168 DSTACK(__FUNCTION_NAME);
2170 JMutexAutoLock envlock(m_env_mutex);
2171 //TODO check if one big lock could be faster then multiple small ones
2173 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2175 std::vector<PrioritySortedBlockTransfer> queue;
2177 s32 total_sending = 0;
2180 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2182 std::list<u16> clients = m_clients.getClientIDs();
2185 for(std::list<u16>::iterator
2186 i = clients.begin();
2187 i != clients.end(); ++i)
2189 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2194 total_sending += client->SendingCount();
2195 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2201 // Lowest priority number comes first.
2202 // Lowest is most important.
2203 std::sort(queue.begin(), queue.end());
2206 for(u32 i=0; i<queue.size(); i++)
2208 //TODO: Calculate limit dynamically
2209 if(total_sending >= g_settings->getS32
2210 ("max_simultaneous_block_sends_server_total"))
2213 PrioritySortedBlockTransfer q = queue[i];
2215 MapBlock *block = NULL;
2218 block = m_env->getMap().getBlockNoCreate(q.pos);
2220 catch(InvalidPositionException &e)
2225 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2230 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2232 client->SentBlock(q.pos);
2238 void Server::fillMediaCache()
2240 DSTACK(__FUNCTION_NAME);
2242 infostream<<"Server: Calculating media file checksums"<<std::endl;
2244 // Collect all media file paths
2245 std::list<std::string> paths;
2246 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2247 i != m_mods.end(); i++){
2248 const ModSpec &mod = *i;
2249 paths.push_back(mod.path + DIR_DELIM + "textures");
2250 paths.push_back(mod.path + DIR_DELIM + "sounds");
2251 paths.push_back(mod.path + DIR_DELIM + "media");
2252 paths.push_back(mod.path + DIR_DELIM + "models");
2254 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2256 // Collect media file information from paths into cache
2257 for(std::list<std::string>::iterator i = paths.begin();
2258 i != paths.end(); i++)
2260 std::string mediapath = *i;
2261 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2262 for(u32 j=0; j<dirlist.size(); j++){
2263 if(dirlist[j].dir) // Ignode dirs
2265 std::string filename = dirlist[j].name;
2266 // If name contains illegal characters, ignore the file
2267 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2268 infostream<<"Server: ignoring illegal file name: \""
2269 <<filename<<"\""<<std::endl;
2272 // If name is not in a supported format, ignore it
2273 const char *supported_ext[] = {
2274 ".png", ".jpg", ".bmp", ".tga",
2275 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2277 ".x", ".b3d", ".md2", ".obj",
2280 if(removeStringEnd(filename, supported_ext) == ""){
2281 infostream<<"Server: ignoring unsupported file extension: \""
2282 <<filename<<"\""<<std::endl;
2285 // Ok, attempt to load the file and add to cache
2286 std::string filepath = mediapath + DIR_DELIM + filename;
2288 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2289 if(fis.good() == false){
2290 errorstream<<"Server::fillMediaCache(): Could not open \""
2291 <<filename<<"\" for reading"<<std::endl;
2294 std::ostringstream tmp_os(std::ios_base::binary);
2298 fis.read(buf, 1024);
2299 std::streamsize len = fis.gcount();
2300 tmp_os.write(buf, len);
2309 errorstream<<"Server::fillMediaCache(): Failed to read \""
2310 <<filename<<"\""<<std::endl;
2313 if(tmp_os.str().length() == 0){
2314 errorstream<<"Server::fillMediaCache(): Empty file \""
2315 <<filepath<<"\""<<std::endl;
2320 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2322 unsigned char *digest = sha1.getDigest();
2323 std::string sha1_base64 = base64_encode(digest, 20);
2324 std::string sha1_hex = hex_encode((char*)digest, 20);
2328 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2329 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2334 struct SendableMediaAnnouncement
2337 std::string sha1_digest;
2339 SendableMediaAnnouncement(const std::string &name_="",
2340 const std::string &sha1_digest_=""):
2342 sha1_digest(sha1_digest_)
2346 void Server::sendMediaAnnouncement(u16 peer_id)
2348 DSTACK(__FUNCTION_NAME);
2350 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2353 std::list<SendableMediaAnnouncement> file_announcements;
2355 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2356 i != m_media.end(); i++){
2358 file_announcements.push_back(
2359 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2363 std::ostringstream os(std::ios_base::binary);
2370 u16 length of sha1_digest
2375 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2376 *pkt << (u16) file_announcements.size();
2378 for(std::list<SendableMediaAnnouncement>::iterator
2379 j = file_announcements.begin();
2380 j != file_announcements.end(); ++j) {
2381 *pkt << j->name << j->sha1_digest;
2384 *pkt << g_settings->get("remote_media");
2388 struct SendableMedia
2394 SendableMedia(const std::string &name_="", const std::string &path_="",
2395 const std::string &data_=""):
2402 void Server::sendRequestedMedia(u16 peer_id,
2403 const std::list<std::string> &tosend)
2405 DSTACK(__FUNCTION_NAME);
2407 verbosestream<<"Server::sendRequestedMedia(): "
2408 <<"Sending files to client"<<std::endl;
2412 // Put 5kB in one bunch (this is not accurate)
2413 u32 bytes_per_bunch = 5000;
2415 std::vector< std::list<SendableMedia> > file_bunches;
2416 file_bunches.push_back(std::list<SendableMedia>());
2418 u32 file_size_bunch_total = 0;
2420 for(std::list<std::string>::const_iterator i = tosend.begin();
2421 i != tosend.end(); ++i)
2423 const std::string &name = *i;
2425 if(m_media.find(name) == m_media.end()) {
2426 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2427 <<"unknown file \""<<(name)<<"\""<<std::endl;
2431 //TODO get path + name
2432 std::string tpath = m_media[name].path;
2435 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2436 if(fis.good() == false){
2437 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2438 <<tpath<<"\" for reading"<<std::endl;
2441 std::ostringstream tmp_os(std::ios_base::binary);
2445 fis.read(buf, 1024);
2446 std::streamsize len = fis.gcount();
2447 tmp_os.write(buf, len);
2448 file_size_bunch_total += len;
2457 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2458 <<name<<"\""<<std::endl;
2461 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2462 <<tname<<"\""<<std::endl;*/
2464 file_bunches[file_bunches.size()-1].push_back(
2465 SendableMedia(name, tpath, tmp_os.str()));
2467 // Start next bunch if got enough data
2468 if(file_size_bunch_total >= bytes_per_bunch) {
2469 file_bunches.push_back(std::list<SendableMedia>());
2470 file_size_bunch_total = 0;
2475 /* Create and send packets */
2477 u16 num_bunches = file_bunches.size();
2478 for(u16 i = 0; i < num_bunches; i++) {
2481 u16 total number of texture bunches
2482 u16 index of this bunch
2483 u32 number of files in this bunch
2492 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2493 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2495 for(std::list<SendableMedia>::iterator
2496 j = file_bunches[i].begin();
2497 j != file_bunches[i].end(); ++j) {
2499 pkt->putLongString(j->data);
2502 verbosestream << "Server::sendRequestedMedia(): bunch "
2503 << i << "/" << num_bunches
2504 << " files=" << file_bunches[i].size()
2505 << " size=" << pkt->getSize() << std::endl;
2510 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2512 if(m_detached_inventories.count(name) == 0) {
2513 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2516 Inventory *inv = m_detached_inventories[name];
2517 std::ostringstream os(std::ios_base::binary);
2519 os << serializeString(name);
2523 std::string s = os.str();
2525 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2526 pkt->putRawString(s.c_str(), s.size());
2528 if (peer_id != PEER_ID_INEXISTENT) {
2532 m_clients.sendToAll(0, pkt, true);
2536 void Server::sendDetachedInventories(u16 peer_id)
2538 DSTACK(__FUNCTION_NAME);
2540 for(std::map<std::string, Inventory*>::iterator
2541 i = m_detached_inventories.begin();
2542 i != m_detached_inventories.end(); i++) {
2543 const std::string &name = i->first;
2544 //Inventory *inv = i->second;
2545 sendDetachedInventory(name, peer_id);
2553 void Server::DiePlayer(u16 peer_id)
2555 DSTACK(__FUNCTION_NAME);
2557 PlayerSAO *playersao = getPlayerSAO(peer_id);
2560 infostream << "Server::DiePlayer(): Player "
2561 << playersao->getPlayer()->getName()
2562 << " dies" << std::endl;
2564 playersao->setHP(0);
2566 // Trigger scripted stuff
2567 m_script->on_dieplayer(playersao);
2569 SendPlayerHP(peer_id);
2570 SendDeathscreen(peer_id, false, v3f(0,0,0));
2573 void Server::RespawnPlayer(u16 peer_id)
2575 DSTACK(__FUNCTION_NAME);
2577 PlayerSAO *playersao = getPlayerSAO(peer_id);
2580 infostream << "Server::RespawnPlayer(): Player "
2581 << playersao->getPlayer()->getName()
2582 << " respawns" << std::endl;
2584 playersao->setHP(PLAYER_MAX_HP);
2585 playersao->setBreath(PLAYER_MAX_BREATH);
2587 SendPlayerHP(peer_id);
2588 SendPlayerBreath(peer_id);
2590 bool repositioned = m_script->on_respawnplayer(playersao);
2592 v3f pos = findSpawnPos(m_env->getServerMap());
2593 playersao->setPos(pos);
2597 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2599 DSTACK(__FUNCTION_NAME);
2601 SendAccessDenied(peer_id, reason);
2602 m_clients.event(peer_id, CSE_SetDenied);
2603 m_con.DisconnectPeer(peer_id);
2606 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2608 DSTACK(__FUNCTION_NAME);
2609 std::wstring message;
2612 Clear references to playing sounds
2614 for(std::map<s32, ServerPlayingSound>::iterator
2615 i = m_playing_sounds.begin();
2616 i != m_playing_sounds.end();)
2618 ServerPlayingSound &psound = i->second;
2619 psound.clients.erase(peer_id);
2620 if(psound.clients.empty())
2621 m_playing_sounds.erase(i++);
2626 Player *player = m_env->getPlayer(peer_id);
2628 // Collect information about leaving in chat
2630 if(player != NULL && reason != CDR_DENY)
2632 std::wstring name = narrow_to_wide(player->getName());
2635 message += L" left the game.";
2636 if(reason == CDR_TIMEOUT)
2637 message += L" (timed out)";
2641 /* Run scripts and remove from environment */
2645 PlayerSAO *playersao = player->getPlayerSAO();
2648 m_script->on_leaveplayer(playersao);
2650 playersao->disconnected();
2658 if(player != NULL && reason != CDR_DENY)
2660 std::ostringstream os(std::ios_base::binary);
2661 std::list<u16> clients = m_clients.getClientIDs();
2663 for(std::list<u16>::iterator
2664 i = clients.begin();
2665 i != clients.end(); ++i)
2668 Player *player = m_env->getPlayer(*i);
2671 // Get name of player
2672 os<<player->getName()<<" ";
2675 actionstream<<player->getName()<<" "
2676 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2677 <<" List of players: "<<os.str()<<std::endl;
2681 JMutexAutoLock env_lock(m_env_mutex);
2682 m_clients.DeleteClient(peer_id);
2686 // Send leave chat message to all remaining clients
2687 if(message.length() != 0)
2688 SendChatMessage(PEER_ID_INEXISTENT,message);
2691 void Server::UpdateCrafting(Player* player)
2693 DSTACK(__FUNCTION_NAME);
2695 // Get a preview for crafting
2697 InventoryLocation loc;
2698 loc.setPlayer(player->getName());
2699 getCraftingResult(&player->inventory, preview, false, this);
2700 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2702 // Put the new preview in
2703 InventoryList *plist = player->inventory.getList("craftpreview");
2705 assert(plist->getSize() >= 1);
2706 plist->changeItem(0, preview);
2709 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2711 RemoteClient *client = getClientNoEx(peer_id,state_min);
2713 throw ClientNotFoundException("Client not found");
2717 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2719 return m_clients.getClientNoEx(peer_id, state_min);
2722 std::string Server::getPlayerName(u16 peer_id)
2724 Player *player = m_env->getPlayer(peer_id);
2726 return "[id="+itos(peer_id)+"]";
2727 return player->getName();
2730 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2732 Player *player = m_env->getPlayer(peer_id);
2735 return player->getPlayerSAO();
2738 std::wstring Server::getStatusString()
2740 std::wostringstream os(std::ios_base::binary);
2743 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2745 os<<L", uptime="<<m_uptime.get();
2747 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2748 // Information about clients
2751 std::list<u16> clients = m_clients.getClientIDs();
2752 for(std::list<u16>::iterator i = clients.begin();
2753 i != clients.end(); ++i)
2756 Player *player = m_env->getPlayer(*i);
2757 // Get name of player
2758 std::wstring name = L"unknown";
2760 name = narrow_to_wide(player->getName());
2761 // Add name to information string
2769 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2770 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2771 if(g_settings->get("motd") != "")
2772 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2776 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2778 std::set<std::string> privs;
2779 m_script->getAuth(name, NULL, &privs);
2783 bool Server::checkPriv(const std::string &name, const std::string &priv)
2785 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2786 return (privs.count(priv) != 0);
2789 void Server::reportPrivsModified(const std::string &name)
2792 std::list<u16> clients = m_clients.getClientIDs();
2793 for(std::list<u16>::iterator
2794 i = clients.begin();
2795 i != clients.end(); ++i){
2796 Player *player = m_env->getPlayer(*i);
2797 reportPrivsModified(player->getName());
2800 Player *player = m_env->getPlayer(name.c_str());
2803 SendPlayerPrivileges(player->peer_id);
2804 PlayerSAO *sao = player->getPlayerSAO();
2807 sao->updatePrivileges(
2808 getPlayerEffectivePrivs(name),
2813 void Server::reportInventoryFormspecModified(const std::string &name)
2815 Player *player = m_env->getPlayer(name.c_str());
2818 SendPlayerInventoryFormspec(player->peer_id);
2821 void Server::setIpBanned(const std::string &ip, const std::string &name)
2823 m_banmanager->add(ip, name);
2826 void Server::unsetIpBanned(const std::string &ip_or_name)
2828 m_banmanager->remove(ip_or_name);
2831 std::string Server::getBanDescription(const std::string &ip_or_name)
2833 return m_banmanager->getBanDescription(ip_or_name);
2836 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2838 Player *player = m_env->getPlayer(name);
2842 if (player->peer_id == PEER_ID_INEXISTENT)
2845 SendChatMessage(player->peer_id, msg);
2848 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2850 Player *player = m_env->getPlayer(playername);
2854 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2858 SendShowFormspecMessage(player->peer_id, formspec, formname);
2862 u32 Server::hudAdd(Player *player, HudElement *form) {
2866 u32 id = player->addHud(form);
2868 SendHUDAdd(player->peer_id, id, form);
2873 bool Server::hudRemove(Player *player, u32 id) {
2877 HudElement* todel = player->removeHud(id);
2884 SendHUDRemove(player->peer_id, id);
2888 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2892 SendHUDChange(player->peer_id, id, stat, data);
2896 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2900 SendHUDSetFlags(player->peer_id, flags, mask);
2901 player->hud_flags = flags;
2903 PlayerSAO* playersao = player->getPlayerSAO();
2905 if (playersao == NULL)
2908 m_script->player_event(playersao, "hud_changed");
2912 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2915 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2918 std::ostringstream os(std::ios::binary);
2919 writeS32(os, hotbar_itemcount);
2920 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2924 void Server::hudSetHotbarImage(Player *player, std::string name) {
2928 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2931 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2935 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2938 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2943 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2947 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2952 SendEyeOffset(player->peer_id, first, third);
2956 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2957 const std::string &type, const std::vector<std::string> ¶ms)
2962 SendSetSky(player->peer_id, bgcolor, type, params);
2966 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2972 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2976 void Server::notifyPlayers(const std::wstring &msg)
2978 SendChatMessage(PEER_ID_INEXISTENT,msg);
2981 void Server::spawnParticle(const char *playername, v3f pos,
2982 v3f velocity, v3f acceleration,
2983 float expirationtime, float size, bool
2984 collisiondetection, bool vertical, std::string texture)
2986 Player *player = m_env->getPlayer(playername);
2989 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2990 expirationtime, size, collisiondetection, vertical, texture);
2993 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2994 float expirationtime, float size,
2995 bool collisiondetection, bool vertical, std::string texture)
2997 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2998 expirationtime, size, collisiondetection, vertical, texture);
3001 u32 Server::addParticleSpawner(const char *playername,
3002 u16 amount, float spawntime,
3003 v3f minpos, v3f maxpos,
3004 v3f minvel, v3f maxvel,
3005 v3f minacc, v3f maxacc,
3006 float minexptime, float maxexptime,
3007 float minsize, float maxsize,
3008 bool collisiondetection, bool vertical, std::string texture)
3010 Player *player = m_env->getPlayer(playername);
3015 for(;;) // look for unused particlespawner id
3018 if (std::find(m_particlespawner_ids.begin(),
3019 m_particlespawner_ids.end(), id)
3020 == m_particlespawner_ids.end())
3022 m_particlespawner_ids.push_back(id);
3027 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3028 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3029 minexptime, maxexptime, minsize, maxsize,
3030 collisiondetection, vertical, texture, id);
3035 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3036 v3f minpos, v3f maxpos,
3037 v3f minvel, v3f maxvel,
3038 v3f minacc, v3f maxacc,
3039 float minexptime, float maxexptime,
3040 float minsize, float maxsize,
3041 bool collisiondetection, bool vertical, std::string texture)
3044 for(;;) // look for unused particlespawner id
3047 if (std::find(m_particlespawner_ids.begin(),
3048 m_particlespawner_ids.end(), id)
3049 == m_particlespawner_ids.end())
3051 m_particlespawner_ids.push_back(id);
3056 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3057 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3058 minexptime, maxexptime, minsize, maxsize,
3059 collisiondetection, vertical, texture, id);
3064 void Server::deleteParticleSpawner(const char *playername, u32 id)
3066 Player *player = m_env->getPlayer(playername);
3070 m_particlespawner_ids.erase(
3071 std::remove(m_particlespawner_ids.begin(),
3072 m_particlespawner_ids.end(), id),
3073 m_particlespawner_ids.end());
3074 SendDeleteParticleSpawner(player->peer_id, id);
3077 void Server::deleteParticleSpawnerAll(u32 id)
3079 m_particlespawner_ids.erase(
3080 std::remove(m_particlespawner_ids.begin(),
3081 m_particlespawner_ids.end(), id),
3082 m_particlespawner_ids.end());
3083 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3086 Inventory* Server::createDetachedInventory(const std::string &name)
3088 if(m_detached_inventories.count(name) > 0){
3089 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3090 delete m_detached_inventories[name];
3092 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3094 Inventory *inv = new Inventory(m_itemdef);
3096 m_detached_inventories[name] = inv;
3097 //TODO find a better way to do this
3098 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3105 BoolScopeSet(bool *dst, bool val):
3108 m_orig_state = *m_dst;
3113 *m_dst = m_orig_state;
3120 // actions: time-reversed list
3121 // Return value: success/failure
3122 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3123 std::list<std::string> *log)
3125 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3126 ServerMap *map = (ServerMap*)(&m_env->getMap());
3128 // Fail if no actions to handle
3129 if(actions.empty()){
3130 log->push_back("Nothing to do.");
3137 for(std::list<RollbackAction>::const_iterator
3138 i = actions.begin();
3139 i != actions.end(); i++)
3141 const RollbackAction &action = *i;
3143 bool success = action.applyRevert(map, this, this);
3146 std::ostringstream os;
3147 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3148 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3150 log->push_back(os.str());
3152 std::ostringstream os;
3153 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3154 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3156 log->push_back(os.str());
3160 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3161 <<" failed"<<std::endl;
3163 // Call it done if less than half failed
3164 return num_failed <= num_tried/2;
3167 // IGameDef interface
3169 IItemDefManager* Server::getItemDefManager()
3173 INodeDefManager* Server::getNodeDefManager()
3177 ICraftDefManager* Server::getCraftDefManager()
3181 ITextureSource* Server::getTextureSource()
3185 IShaderSource* Server::getShaderSource()
3189 scene::ISceneManager* Server::getSceneManager()
3194 u16 Server::allocateUnknownNodeId(const std::string &name)
3196 return m_nodedef->allocateDummy(name);
3198 ISoundManager* Server::getSoundManager()
3200 return &dummySoundManager;
3202 MtEventManager* Server::getEventManager()
3207 IWritableItemDefManager* Server::getWritableItemDefManager()
3211 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3215 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3220 const ModSpec* Server::getModSpec(const std::string &modname)
3222 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3223 i != m_mods.end(); i++){
3224 const ModSpec &mod = *i;
3225 if(mod.name == modname)
3230 void Server::getModNames(std::list<std::string> &modlist)
3232 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3234 modlist.push_back(i->name);
3237 std::string Server::getBuiltinLuaPath()
3239 return porting::path_share + DIR_DELIM + "builtin";
3242 v3f findSpawnPos(ServerMap &map)
3244 //return v3f(50,50,50)*BS;
3249 nodepos = v2s16(0,0);
3254 s16 water_level = map.getWaterLevel();
3256 // Try to find a good place a few times
3257 for(s32 i=0; i<1000; i++)
3260 // We're going to try to throw the player to this position
3261 v2s16 nodepos2d = v2s16(
3262 -range + (myrand() % (range * 2)),
3263 -range + (myrand() % (range * 2)));
3265 // Get ground height at point
3266 s16 groundheight = map.findGroundLevel(nodepos2d);
3267 if (groundheight <= water_level) // Don't go underwater
3269 if (groundheight > water_level + 6) // Don't go to high places
3272 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3273 bool is_good = false;
3275 for (s32 i = 0; i < 10; i++) {
3276 v3s16 blockpos = getNodeBlockPos(nodepos);
3277 map.emergeBlock(blockpos, true);
3278 content_t c = map.getNodeNoEx(nodepos).getContent();
3279 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3281 if (air_count >= 2){
3289 // Found a good place
3290 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3296 return intToFloat(nodepos, BS);
3299 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3301 bool newplayer = false;
3304 Try to get an existing player
3306 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3308 // If player is already connected, cancel
3309 if(player != NULL && player->peer_id != 0)
3311 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3316 If player with the wanted peer_id already exists, cancel.
3318 if(m_env->getPlayer(peer_id) != NULL)
3320 infostream<<"emergePlayer(): Player with wrong name but same"
3321 " peer_id already exists"<<std::endl;
3325 // Load player if it isn't already loaded
3327 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3330 // Create player if it doesn't exist
3333 player = new RemotePlayer(this, name);
3334 // Set player position
3335 infostream<<"Server: Finding spawn place for player \""
3336 <<name<<"\""<<std::endl;
3337 v3f pos = findSpawnPos(m_env->getServerMap());
3338 player->setPosition(pos);
3340 // Make sure the player is saved
3341 player->setModified(true);
3343 // Add player to environment
3344 m_env->addPlayer(player);
3347 // Create a new player active object
3348 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3349 getPlayerEffectivePrivs(player->getName()),
3352 /* Clean up old HUD elements from previous sessions */
3355 /* Add object to environment */
3356 m_env->addActiveObject(playersao);
3360 m_script->on_newplayer(playersao);
3366 void dedicated_server_loop(Server &server, bool &kill)
3368 DSTACK(__FUNCTION_NAME);
3370 verbosestream<<"dedicated_server_loop()"<<std::endl;
3372 IntervalLimiter m_profiler_interval;
3376 float steplen = g_settings->getFloat("dedicated_server_step");
3377 // This is kind of a hack but can be done like this
3378 // because server.step() is very light
3380 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3381 sleep_ms((int)(steplen*1000.0));
3383 server.step(steplen);
3385 if(server.getShutdownRequested() || kill)
3387 infostream<<"Dedicated server quitting"<<std::endl;
3389 if(g_settings->getBool("server_announce"))
3390 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3398 float profiler_print_interval =
3399 g_settings->getFloat("profiler_print_interval");
3400 if(profiler_print_interval != 0)
3402 if(m_profiler_interval.step(steplen, profiler_print_interval))
3404 infostream<<"Profiler:"<<std::endl;
3405 g_profiler->print(infostream);
3406 g_profiler->clear();