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
539 JMutexAutoLock envlock(m_env_mutex);
541 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
544 Send to clients at constant intervals
547 m_time_of_day_send_timer -= dtime;
548 if(m_time_of_day_send_timer < 0.0)
550 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
551 u16 time = m_env->getTimeOfDay();
552 float time_speed = g_settings->getFloat("time_speed");
553 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
558 JMutexAutoLock lock(m_env_mutex);
559 // Figure out and report maximum lag to environment
560 float max_lag = m_env->getMaxLagEstimate();
561 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
563 if(dtime > 0.1 && dtime > max_lag * 2.0)
564 infostream<<"Server: Maximum lag peaked to "<<dtime
568 m_env->reportMaxLagEstimate(max_lag);
570 ScopeProfiler sp(g_profiler, "SEnv step");
571 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
575 static const float map_timer_and_unload_dtime = 2.92;
576 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
578 JMutexAutoLock lock(m_env_mutex);
579 // Run Map's timers and unload unused data
580 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
581 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
582 g_settings->getFloat("server_unload_unused_data_timeout"));
593 JMutexAutoLock lock(m_env_mutex);
595 std::list<u16> clientids = m_clients.getClientIDs();
597 ScopeProfiler sp(g_profiler, "Server: handle players");
599 for(std::list<u16>::iterator
600 i = clientids.begin();
601 i != clientids.end(); ++i)
603 PlayerSAO *playersao = getPlayerSAO(*i);
604 if(playersao == NULL)
608 Handle player HPs (die if hp=0)
610 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
612 if(playersao->getHP() == 0)
619 Send player breath if changed
621 if(playersao->m_breath_not_sent) {
622 SendPlayerBreath(*i);
626 Send player inventories if necessary
628 if(playersao->m_moved) {
630 playersao->m_moved = false;
632 if(playersao->m_inventory_not_sent) {
639 /* Transform liquids */
640 m_liquid_transform_timer += dtime;
641 if(m_liquid_transform_timer >= m_liquid_transform_every)
643 m_liquid_transform_timer -= m_liquid_transform_every;
645 JMutexAutoLock lock(m_env_mutex);
647 ScopeProfiler sp(g_profiler, "Server: liquid transform");
649 std::map<v3s16, MapBlock*> modified_blocks;
650 m_env->getMap().transformLiquids(modified_blocks);
655 core::map<v3s16, MapBlock*> lighting_modified_blocks;
656 ServerMap &map = ((ServerMap&)m_env->getMap());
657 map.updateLighting(modified_blocks, lighting_modified_blocks);
659 // Add blocks modified by lighting to modified_blocks
660 for(core::map<v3s16, MapBlock*>::Iterator
661 i = lighting_modified_blocks.getIterator();
662 i.atEnd() == false; i++)
664 MapBlock *block = i.getNode()->getValue();
665 modified_blocks.insert(block->getPos(), block);
669 Set the modified blocks unsent for all the clients
671 if(!modified_blocks.empty())
673 SetBlocksNotSent(modified_blocks);
676 m_clients.step(dtime);
678 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
680 // send masterserver announce
682 float &counter = m_masterserver_timer;
683 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
684 g_settings->getBool("server_announce"))
686 ServerList::sendAnnounce(counter ? "update" : "start",
687 m_bind_addr.getPort(),
688 m_clients.getPlayerNames(),
690 m_env->getGameTime(),
693 m_emerge->params.mg_name,
702 Check added and deleted active objects
705 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
706 JMutexAutoLock envlock(m_env_mutex);
709 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
710 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
712 // Radius inside which objects are active
713 s16 radius = g_settings->getS16("active_object_send_range_blocks");
714 s16 player_radius = g_settings->getS16("player_transfer_distance");
716 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
717 !g_settings->getBool("unlimited_player_transfer_distance"))
718 player_radius = radius;
720 radius *= MAP_BLOCKSIZE;
721 player_radius *= MAP_BLOCKSIZE;
723 for(std::map<u16, RemoteClient*>::iterator
725 i != clients.end(); ++i)
727 RemoteClient *client = i->second;
729 // If definitions and textures have not been sent, don't
730 // send objects either
731 if (client->getState() < CS_DefinitionsSent)
734 Player *player = m_env->getPlayer(client->peer_id);
737 // This can happen if the client timeouts somehow
738 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
740 <<" has no associated player"<<std::endl;*/
743 v3s16 pos = floatToInt(player->getPosition(), BS);
745 std::set<u16> removed_objects;
746 std::set<u16> added_objects;
747 m_env->getRemovedActiveObjects(pos, radius, player_radius,
748 client->m_known_objects, removed_objects);
749 m_env->getAddedActiveObjects(pos, radius, player_radius,
750 client->m_known_objects, added_objects);
752 // Ignore if nothing happened
753 if(removed_objects.empty() && added_objects.empty())
755 //infostream<<"active objects: none changed"<<std::endl;
759 std::string data_buffer;
763 // Handle removed objects
764 writeU16((u8*)buf, removed_objects.size());
765 data_buffer.append(buf, 2);
766 for(std::set<u16>::iterator
767 i = removed_objects.begin();
768 i != removed_objects.end(); ++i)
772 ServerActiveObject* obj = m_env->getActiveObject(id);
774 // Add to data buffer for sending
775 writeU16((u8*)buf, id);
776 data_buffer.append(buf, 2);
778 // Remove from known objects
779 client->m_known_objects.erase(id);
781 if(obj && obj->m_known_by_count > 0)
782 obj->m_known_by_count--;
785 // Handle added objects
786 writeU16((u8*)buf, added_objects.size());
787 data_buffer.append(buf, 2);
788 for(std::set<u16>::iterator
789 i = added_objects.begin();
790 i != added_objects.end(); ++i)
794 ServerActiveObject* obj = m_env->getActiveObject(id);
797 u8 type = ACTIVEOBJECT_TYPE_INVALID;
799 infostream<<"WARNING: "<<__FUNCTION_NAME
800 <<": NULL object"<<std::endl;
802 type = obj->getSendType();
804 // Add to data buffer for sending
805 writeU16((u8*)buf, id);
806 data_buffer.append(buf, 2);
807 writeU8((u8*)buf, type);
808 data_buffer.append(buf, 1);
811 data_buffer.append(serializeLongString(
812 obj->getClientInitializationData(client->net_proto_version)));
814 data_buffer.append(serializeLongString(""));
816 // Add to known objects
817 client->m_known_objects.insert(id);
820 obj->m_known_by_count++;
823 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
824 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
827 verbosestream << "Server: Sent object remove/add: "
828 << removed_objects.size() << " removed, "
829 << added_objects.size() << " added, "
830 << "packet size is " << pkt->getSize() << std::endl;
841 JMutexAutoLock envlock(m_env_mutex);
842 ScopeProfiler sp(g_profiler, "Server: sending object messages");
845 // Value = data sent by object
846 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
848 // Get active object messages from environment
851 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
855 std::list<ActiveObjectMessage>* message_list = NULL;
856 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
857 n = buffered_messages.find(aom.id);
858 if(n == buffered_messages.end())
860 message_list = new std::list<ActiveObjectMessage>;
861 buffered_messages[aom.id] = message_list;
865 message_list = n->second;
867 message_list->push_back(aom);
871 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
872 // Route data to every client
873 for(std::map<u16, RemoteClient*>::iterator
875 i != clients.end(); ++i)
877 RemoteClient *client = i->second;
878 std::string reliable_data;
879 std::string unreliable_data;
880 // Go through all objects in message buffer
881 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
882 j = buffered_messages.begin();
883 j != buffered_messages.end(); ++j)
885 // If object is not known by client, skip it
887 if(client->m_known_objects.find(id) == client->m_known_objects.end())
889 // Get message list of object
890 std::list<ActiveObjectMessage>* list = j->second;
891 // Go through every message
892 for(std::list<ActiveObjectMessage>::iterator
893 k = list->begin(); k != list->end(); ++k)
895 // Compose the full new data with header
896 ActiveObjectMessage aom = *k;
897 std::string new_data;
900 writeU16((u8*)&buf[0], aom.id);
901 new_data.append(buf, 2);
903 new_data += serializeString(aom.datastring);
904 // Add data to buffer
906 reliable_data += new_data;
908 unreliable_data += new_data;
912 reliable_data and unreliable_data are now ready.
915 if(reliable_data.size() > 0) {
916 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
919 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
923 if(unreliable_data.size() > 0) {
924 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
927 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
933 // Clear buffered_messages
934 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
935 i = buffered_messages.begin();
936 i != buffered_messages.end(); ++i)
943 Send queued-for-sending map edit events.
946 // We will be accessing the environment
947 JMutexAutoLock lock(m_env_mutex);
949 // Don't send too many at a time
952 // Single change sending is disabled if queue size is not small
953 bool disable_single_change_sending = false;
954 if(m_unsent_map_edit_queue.size() >= 4)
955 disable_single_change_sending = true;
957 int event_count = m_unsent_map_edit_queue.size();
959 // We'll log the amount of each
962 while(m_unsent_map_edit_queue.size() != 0)
964 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
966 // Players far away from the change are stored here.
967 // Instead of sending the changes, MapBlocks are set not sent
969 std::list<u16> far_players;
971 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
973 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
974 prof.add("MEET_ADDNODE", 1);
975 if(disable_single_change_sending)
976 sendAddNode(event->p, event->n, event->already_known_by_peer,
977 &far_players, 5, event->type == MEET_ADDNODE);
979 sendAddNode(event->p, event->n, event->already_known_by_peer,
980 &far_players, 30, event->type == MEET_ADDNODE);
982 else if(event->type == MEET_REMOVENODE)
984 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
985 prof.add("MEET_REMOVENODE", 1);
986 if(disable_single_change_sending)
987 sendRemoveNode(event->p, event->already_known_by_peer,
990 sendRemoveNode(event->p, event->already_known_by_peer,
993 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
995 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
996 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
997 setBlockNotSent(event->p);
999 else if(event->type == MEET_OTHER)
1001 infostream<<"Server: MEET_OTHER"<<std::endl;
1002 prof.add("MEET_OTHER", 1);
1003 for(std::set<v3s16>::iterator
1004 i = event->modified_blocks.begin();
1005 i != event->modified_blocks.end(); ++i)
1007 setBlockNotSent(*i);
1012 prof.add("unknown", 1);
1013 infostream<<"WARNING: Server: Unknown MapEditEvent "
1014 <<((u32)event->type)<<std::endl;
1018 Set blocks not sent to far players
1020 if(!far_players.empty())
1022 // Convert list format to that wanted by SetBlocksNotSent
1023 std::map<v3s16, MapBlock*> modified_blocks2;
1024 for(std::set<v3s16>::iterator
1025 i = event->modified_blocks.begin();
1026 i != event->modified_blocks.end(); ++i)
1028 modified_blocks2[*i] =
1029 m_env->getMap().getBlockNoCreateNoEx(*i);
1031 // Set blocks not sent
1032 for(std::list<u16>::iterator
1033 i = far_players.begin();
1034 i != far_players.end(); ++i)
1037 RemoteClient *client = getClient(peer_id);
1040 client->SetBlocksNotSent(modified_blocks2);
1046 /*// Don't send too many at a time
1048 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1052 if(event_count >= 5){
1053 infostream<<"Server: MapEditEvents:"<<std::endl;
1054 prof.print(infostream);
1055 } else if(event_count != 0){
1056 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1057 prof.print(verbosestream);
1063 Trigger emergethread (it somehow gets to a non-triggered but
1064 bysy state sometimes)
1067 float &counter = m_emergethread_trigger_timer;
1073 m_emerge->startThreads();
1077 // Save map, players and auth stuff
1079 float &counter = m_savemap_timer;
1081 if(counter >= g_settings->getFloat("server_map_save_interval"))
1084 JMutexAutoLock lock(m_env_mutex);
1086 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1089 if (m_banmanager->isModified()) {
1090 m_banmanager->save();
1093 // Save changed parts of map
1094 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1097 m_env->saveLoadedPlayers();
1099 // Save environment metadata
1105 void Server::Receive()
1107 DSTACK(__FUNCTION_NAME);
1108 SharedBuffer<u8> data;
1112 datasize = m_con.Receive(peer_id,data);
1113 ProcessData(*data, datasize, peer_id);
1115 catch(con::InvalidIncomingDataException &e) {
1116 infostream<<"Server::Receive(): "
1117 "InvalidIncomingDataException: what()="
1118 <<e.what()<<std::endl;
1120 catch(SerializationError &e) {
1121 infostream<<"Server::Receive(): "
1122 "SerializationError: what()="
1123 <<e.what()<<std::endl;
1125 catch(ClientStateError &e) {
1126 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1127 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1128 L"Try reconnecting or updating your client");
1130 catch(con::PeerNotFoundException &e) {
1135 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1137 std::string playername = "";
1138 PlayerSAO *playersao = NULL;
1141 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1142 if (client != NULL) {
1143 playername = client->getName();
1144 playersao = emergePlayer(playername.c_str(), peer_id);
1146 } catch (std::exception &e) {
1152 RemotePlayer *player =
1153 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1155 // If failed, cancel
1156 if((playersao == NULL) || (player == NULL)) {
1157 if(player && player->peer_id != 0) {
1158 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1159 <<" (player allocated to an another client)"<<std::endl;
1160 DenyAccess(peer_id, L"Another client is connected with this "
1161 L"name. If your client closed unexpectedly, try again in "
1164 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1166 DenyAccess(peer_id, L"Could not allocate player.");
1172 Send complete position information
1174 SendMovePlayer(peer_id);
1177 SendPlayerPrivileges(peer_id);
1179 // Send inventory formspec
1180 SendPlayerInventoryFormspec(peer_id);
1183 UpdateCrafting(peer_id);
1184 SendInventory(peer_id);
1187 if(g_settings->getBool("enable_damage"))
1188 SendPlayerHP(peer_id);
1191 SendPlayerBreath(peer_id);
1193 // Show death screen if necessary
1195 SendDeathscreen(peer_id, false, v3f(0,0,0));
1197 // Note things in chat if not in simple singleplayer mode
1198 if(!m_simple_singleplayer_mode) {
1199 // Send information about server to player in chat
1200 SendChatMessage(peer_id, getStatusString());
1202 // Send information about joining in chat
1204 std::wstring name = L"unknown";
1205 Player *player = m_env->getPlayer(peer_id);
1207 name = narrow_to_wide(player->getName());
1209 std::wstring message;
1212 message += L" joined the game.";
1213 SendChatMessage(PEER_ID_INEXISTENT,message);
1216 Address addr = getPeerAddress(player->peer_id);
1217 std::string ip_str = addr.serializeString();
1218 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1223 std::vector<std::string> names = m_clients.getPlayerNames();
1225 actionstream<<player->getName() <<" joins game. List of players: ";
1227 for (std::vector<std::string>::iterator i = names.begin();
1228 i != names.end(); i++) {
1229 actionstream << *i << " ";
1232 actionstream << player->getName() <<std::endl;
1237 inline void Server::handleCommand(NetworkPacket* pkt)
1239 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1240 (this->*opHandle.handler)(pkt);
1243 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1245 DSTACK(__FUNCTION_NAME);
1246 // Environment is locked first.
1247 JMutexAutoLock envlock(m_env_mutex);
1249 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1252 Address address = getPeerAddress(peer_id);
1253 std::string addr_s = address.serializeString();
1255 if(m_banmanager->isIpBanned(addr_s)) {
1256 std::string ban_name = m_banmanager->getBanName(addr_s);
1257 infostream << "Server: A banned client tried to connect from "
1258 << addr_s << "; banned name was "
1259 << ban_name << std::endl;
1260 // This actually doesn't seem to transfer to the client
1261 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1262 + narrow_to_wide(ban_name));
1266 catch(con::PeerNotFoundException &e) {
1268 * no peer for this packet found
1269 * most common reason is peer timeout, e.g. peer didn't
1270 * respond for some time, your server was overloaded or
1273 infostream << "Server::ProcessData(): Cancelling: peer "
1274 << peer_id << " not found" << std::endl;
1282 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1284 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1286 // Command must be handled into ToServerCommandHandler
1287 if (command >= TOSERVER_NUM_MSG_TYPES) {
1288 infostream << "Server: Ignoring unknown command "
1289 << command << std::endl;
1292 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1298 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1300 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1301 errorstream << "Server::ProcessData(): Cancelling: Peer"
1302 " serialization format invalid or not initialized."
1303 " Skipping incoming command=" << command << std::endl;
1309 /* Handle commands related to client startup */
1310 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1316 if (m_clients.getClientState(peer_id) < CS_Active) {
1317 if (command == TOSERVER_PLAYERPOS) return;
1319 errorstream << "Got packet command: " << command << " for peer id "
1320 << peer_id << " but client isn't active yet. Dropping packet "
1331 catch(SendFailedException &e) {
1332 errorstream << "Server::ProcessData(): SendFailedException: "
1333 << "what=" << e.what()
1338 void Server::setTimeOfDay(u32 time)
1340 m_env->setTimeOfDay(time);
1341 m_time_of_day_send_timer = 0;
1344 void Server::onMapEditEvent(MapEditEvent *event)
1346 if(m_ignore_map_edit_events)
1348 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1350 MapEditEvent *e = event->clone();
1351 m_unsent_map_edit_queue.push_back(e);
1354 Inventory* Server::getInventory(const InventoryLocation &loc)
1357 case InventoryLocation::UNDEFINED:
1358 case InventoryLocation::CURRENT_PLAYER:
1360 case InventoryLocation::PLAYER:
1362 Player *player = m_env->getPlayer(loc.name.c_str());
1365 PlayerSAO *playersao = player->getPlayerSAO();
1368 return playersao->getInventory();
1371 case InventoryLocation::NODEMETA:
1373 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1376 return meta->getInventory();
1379 case InventoryLocation::DETACHED:
1381 if(m_detached_inventories.count(loc.name) == 0)
1383 return m_detached_inventories[loc.name];
1391 void Server::setInventoryModified(const InventoryLocation &loc)
1394 case InventoryLocation::UNDEFINED:
1396 case InventoryLocation::PLAYER:
1398 Player *player = m_env->getPlayer(loc.name.c_str());
1401 PlayerSAO *playersao = player->getPlayerSAO();
1404 playersao->m_inventory_not_sent = true;
1405 playersao->m_wielded_item_not_sent = true;
1408 case InventoryLocation::NODEMETA:
1410 v3s16 blockpos = getNodeBlockPos(loc.p);
1412 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1414 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1416 setBlockNotSent(blockpos);
1419 case InventoryLocation::DETACHED:
1421 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1429 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1431 std::list<u16> clients = m_clients.getClientIDs();
1433 // Set the modified blocks unsent for all the clients
1434 for (std::list<u16>::iterator
1435 i = clients.begin();
1436 i != clients.end(); ++i) {
1437 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
1439 client->SetBlocksNotSent(block);
1444 void Server::peerAdded(con::Peer *peer)
1446 DSTACK(__FUNCTION_NAME);
1447 verbosestream<<"Server::peerAdded(): peer->id="
1448 <<peer->id<<std::endl;
1451 c.type = con::PEER_ADDED;
1452 c.peer_id = peer->id;
1454 m_peer_change_queue.push_back(c);
1457 void Server::deletingPeer(con::Peer *peer, bool timeout)
1459 DSTACK(__FUNCTION_NAME);
1460 verbosestream<<"Server::deletingPeer(): peer->id="
1461 <<peer->id<<", timeout="<<timeout<<std::endl;
1463 m_clients.event(peer->id, CSE_Disconnect);
1465 c.type = con::PEER_REMOVED;
1466 c.peer_id = peer->id;
1467 c.timeout = timeout;
1468 m_peer_change_queue.push_back(c);
1471 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1473 *retval = m_con.getPeerStat(peer_id,type);
1474 if (*retval == -1) return false;
1478 bool Server::getClientInfo(
1487 std::string* vers_string
1490 *state = m_clients.getClientState(peer_id);
1492 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1494 if (client == NULL) {
1499 *uptime = client->uptime();
1500 *ser_vers = client->serialization_version;
1501 *prot_vers = client->net_proto_version;
1503 *major = client->getMajor();
1504 *minor = client->getMinor();
1505 *patch = client->getPatch();
1506 *vers_string = client->getPatch();
1513 void Server::handlePeerChanges()
1515 while(m_peer_change_queue.size() > 0)
1517 con::PeerChange c = m_peer_change_queue.pop_front();
1519 verbosestream<<"Server: Handling peer change: "
1520 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1525 case con::PEER_ADDED:
1526 m_clients.CreateClient(c.peer_id);
1529 case con::PEER_REMOVED:
1530 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1534 assert("Invalid peer change event received!" == 0);
1540 void Server::Send(NetworkPacket* pkt)
1542 m_clients.send(pkt->getPeerId(),
1543 clientCommandFactoryTable[pkt->getCommand()].channel,
1545 clientCommandFactoryTable[pkt->getCommand()].reliable);
1548 void Server::SendMovement(u16 peer_id)
1550 DSTACK(__FUNCTION_NAME);
1551 std::ostringstream os(std::ios_base::binary);
1553 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1555 *pkt << g_settings->getFloat("movement_acceleration_default");
1556 *pkt << g_settings->getFloat("movement_acceleration_air");
1557 *pkt << g_settings->getFloat("movement_acceleration_fast");
1558 *pkt << g_settings->getFloat("movement_speed_walk");
1559 *pkt << g_settings->getFloat("movement_speed_crouch");
1560 *pkt << g_settings->getFloat("movement_speed_fast");
1561 *pkt << g_settings->getFloat("movement_speed_climb");
1562 *pkt << g_settings->getFloat("movement_speed_jump");
1563 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1564 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1565 *pkt << g_settings->getFloat("movement_liquid_sink");
1566 *pkt << g_settings->getFloat("movement_gravity");
1571 void Server::SendHP(u16 peer_id, u8 hp)
1573 DSTACK(__FUNCTION_NAME);
1575 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1580 void Server::SendBreath(u16 peer_id, u16 breath)
1582 DSTACK(__FUNCTION_NAME);
1584 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1585 *pkt << (u16) breath;
1589 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1591 DSTACK(__FUNCTION_NAME);
1593 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1598 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1599 v3f camera_point_target)
1601 DSTACK(__FUNCTION_NAME);
1603 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1604 *pkt << set_camera_point_target << camera_point_target;
1608 void Server::SendItemDef(u16 peer_id,
1609 IItemDefManager *itemdef, u16 protocol_version)
1611 DSTACK(__FUNCTION_NAME);
1613 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1617 u32 length of the next item
1618 zlib-compressed serialized ItemDefManager
1620 std::ostringstream tmp_os(std::ios::binary);
1621 itemdef->serialize(tmp_os, protocol_version);
1622 std::ostringstream tmp_os2(std::ios::binary);
1623 compressZlib(tmp_os.str(), tmp_os2);
1624 pkt->putLongString(tmp_os2.str());
1627 verbosestream << "Server: Sending item definitions to id(" << peer_id
1628 << "): size=" << pkt->getSize() << std::endl;
1633 void Server::SendNodeDef(u16 peer_id,
1634 INodeDefManager *nodedef, u16 protocol_version)
1636 DSTACK(__FUNCTION_NAME);
1638 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1642 u32 length of the next item
1643 zlib-compressed serialized NodeDefManager
1645 std::ostringstream tmp_os(std::ios::binary);
1646 nodedef->serialize(tmp_os, protocol_version);
1647 std::ostringstream tmp_os2(std::ios::binary);
1648 compressZlib(tmp_os.str(), tmp_os2);
1650 pkt->putLongString(tmp_os2.str());
1653 verbosestream << "Server: Sending node definitions to id(" << peer_id
1654 << "): size=" << pkt->getSize() << std::endl;
1660 Non-static send methods
1663 void Server::SendInventory(u16 peer_id)
1665 DSTACK(__FUNCTION_NAME);
1667 PlayerSAO *playersao = getPlayerSAO(peer_id);
1670 playersao->m_inventory_not_sent = false;
1676 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0, peer_id);
1678 std::ostringstream os;
1679 playersao->getInventory()->serialize(os);
1681 std::string s = os.str();
1683 pkt->putRawString(s.c_str(), s.size());
1687 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1689 DSTACK(__FUNCTION_NAME);
1691 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1694 if (peer_id != PEER_ID_INEXISTENT) {
1698 m_clients.sendToAll(0,pkt,true);
1702 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1703 const std::string &formname)
1705 DSTACK(__FUNCTION_NAME);
1707 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1709 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1715 // Spawns a particle on peer with peer_id
1716 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1717 float expirationtime, float size, bool collisiondetection,
1718 bool vertical, std::string texture)
1720 DSTACK(__FUNCTION_NAME);
1722 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1724 *pkt << pos << velocity << acceleration << expirationtime
1725 << size << collisiondetection;
1726 pkt->putLongString(texture);
1729 if (peer_id != PEER_ID_INEXISTENT) {
1733 m_clients.sendToAll(0,pkt,true);
1737 // Adds a ParticleSpawner on peer with peer_id
1738 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1739 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1740 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1742 DSTACK(__FUNCTION_NAME);
1744 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1746 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1747 << minacc << maxacc << minexptime << maxexptime << minsize
1748 << maxsize << collisiondetection;
1750 pkt->putLongString(texture);
1752 *pkt << id << vertical;
1754 if (peer_id != PEER_ID_INEXISTENT) {
1758 m_clients.sendToAll(0, pkt, true);
1762 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1764 DSTACK(__FUNCTION_NAME);
1766 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1768 // Ugly error in this packet
1771 if (peer_id != PEER_ID_INEXISTENT) {
1775 m_clients.sendToAll(0, pkt, true);
1780 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1782 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1784 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1785 << form->text << form->number << form->item << form->dir
1786 << form->align << form->offset << form->world_pos << form->size;
1791 void Server::SendHUDRemove(u16 peer_id, u32 id)
1793 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1798 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1800 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1801 *pkt << id << (u8) stat;
1805 case HUD_STAT_SCALE:
1806 case HUD_STAT_ALIGN:
1807 case HUD_STAT_OFFSET:
1808 *pkt << *(v2f *) value;
1812 *pkt << *(std::string *) value;
1814 case HUD_STAT_WORLD_POS:
1815 *pkt << *(v3f *) value;
1818 *pkt << *(v2s32 *) value;
1820 case HUD_STAT_NUMBER:
1824 *pkt << *(u32 *) value;
1831 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1833 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1835 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1837 *pkt << flags << mask;
1842 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1844 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1845 *pkt << param << value;
1849 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1850 const std::string &type, const std::vector<std::string> ¶ms)
1852 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1853 *pkt << bgcolor << type << (u16) params.size();
1855 for(size_t i=0; i<params.size(); i++)
1861 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1864 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1867 *pkt << do_override << (u16) (ratio * 65535);
1872 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1874 DSTACK(__FUNCTION_NAME);
1876 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1877 *pkt << time << time_speed;
1879 if (peer_id == PEER_ID_INEXISTENT) {
1880 m_clients.sendToAll(0, pkt, true);
1887 void Server::SendPlayerHP(u16 peer_id)
1889 DSTACK(__FUNCTION_NAME);
1890 PlayerSAO *playersao = getPlayerSAO(peer_id);
1892 playersao->m_hp_not_sent = false;
1893 SendHP(peer_id, playersao->getHP());
1894 m_script->player_event(playersao,"health_changed");
1896 // Send to other clients
1897 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1898 ActiveObjectMessage aom(playersao->getId(), true, str);
1899 playersao->m_messages_out.push_back(aom);
1902 void Server::SendPlayerBreath(u16 peer_id)
1904 DSTACK(__FUNCTION_NAME);
1905 PlayerSAO *playersao = getPlayerSAO(peer_id);
1907 playersao->m_breath_not_sent = false;
1908 m_script->player_event(playersao,"breath_changed");
1909 SendBreath(peer_id, playersao->getBreath());
1912 void Server::SendMovePlayer(u16 peer_id)
1914 DSTACK(__FUNCTION_NAME);
1915 Player *player = m_env->getPlayer(peer_id);
1918 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1919 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1922 v3f pos = player->getPosition();
1923 f32 pitch = player->getPitch();
1924 f32 yaw = player->getYaw();
1925 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1926 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1935 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1937 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1940 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1941 << animation_frames[3] << animation_speed;
1946 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1948 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1949 *pkt << first << third;
1952 void Server::SendPlayerPrivileges(u16 peer_id)
1954 Player *player = m_env->getPlayer(peer_id);
1956 if(player->peer_id == PEER_ID_INEXISTENT)
1959 std::set<std::string> privs;
1960 m_script->getAuth(player->getName(), NULL, &privs);
1962 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1963 *pkt << (u16) privs.size();
1965 for(std::set<std::string>::const_iterator i = privs.begin();
1966 i != privs.end(); i++) {
1973 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1975 Player *player = m_env->getPlayer(peer_id);
1977 if(player->peer_id == PEER_ID_INEXISTENT)
1980 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1981 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1985 s32 Server::playSound(const SimpleSoundSpec &spec,
1986 const ServerSoundParams ¶ms)
1988 // Find out initial position of sound
1989 bool pos_exists = false;
1990 v3f pos = params.getPos(m_env, &pos_exists);
1991 // If position is not found while it should be, cancel sound
1992 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1995 // Filter destination clients
1996 std::list<u16> dst_clients;
1997 if(params.to_player != "")
1999 Player *player = m_env->getPlayer(params.to_player.c_str());
2001 infostream<<"Server::playSound: Player \""<<params.to_player
2002 <<"\" not found"<<std::endl;
2005 if(player->peer_id == PEER_ID_INEXISTENT){
2006 infostream<<"Server::playSound: Player \""<<params.to_player
2007 <<"\" not connected"<<std::endl;
2010 dst_clients.push_back(player->peer_id);
2014 std::list<u16> clients = m_clients.getClientIDs();
2016 for(std::list<u16>::iterator
2017 i = clients.begin(); i != clients.end(); ++i)
2019 Player *player = m_env->getPlayer(*i);
2023 if(player->getPosition().getDistanceFrom(pos) >
2024 params.max_hear_distance)
2027 dst_clients.push_back(*i);
2030 if(dst_clients.empty())
2034 s32 id = m_next_sound_id++;
2035 // The sound will exist as a reference in m_playing_sounds
2036 m_playing_sounds[id] = ServerPlayingSound();
2037 ServerPlayingSound &psound = m_playing_sounds[id];
2038 psound.params = params;
2039 for(std::list<u16>::iterator i = dst_clients.begin();
2040 i != dst_clients.end(); i++)
2041 psound.clients.insert(*i);
2043 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
2044 *pkt << id << spec.name << (float) (spec.gain * params.gain)
2045 << (u8) params.type << pos << params.object << params.loop;
2046 for(std::list<u16>::iterator i = dst_clients.begin();
2047 i != dst_clients.end(); i++) {
2049 m_clients.send(*i, 0, pkt, true, false);
2054 void Server::stopSound(s32 handle)
2056 // Get sound reference
2057 std::map<s32, ServerPlayingSound>::iterator i =
2058 m_playing_sounds.find(handle);
2059 if(i == m_playing_sounds.end())
2061 ServerPlayingSound &psound = i->second;
2063 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
2066 for(std::set<u16>::iterator i = psound.clients.begin();
2067 i != psound.clients.end(); i++) {
2069 m_clients.send(*i, 0, pkt, true, false);
2072 // Remove sound reference
2073 m_playing_sounds.erase(i);
2076 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2077 std::list<u16> *far_players, float far_d_nodes)
2079 float maxd = far_d_nodes*BS;
2080 v3f p_f = intToFloat(p, BS);
2082 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2085 std::list<u16> clients = m_clients.getClientIDs();
2086 for(std::list<u16>::iterator
2087 i = clients.begin();
2088 i != clients.end(); ++i) {
2091 if(Player *player = m_env->getPlayer(*i)) {
2092 // If player is far away, only set modified blocks not sent
2093 v3f player_pos = player->getPosition();
2094 if(player_pos.getDistanceFrom(p_f) > maxd) {
2095 far_players->push_back(*i);
2102 m_clients.send(*i, 0, pkt, true, false);
2104 // This loop needs the deletion of the packet here
2108 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2109 std::list<u16> *far_players, float far_d_nodes,
2110 bool remove_metadata)
2112 float maxd = far_d_nodes*BS;
2113 v3f p_f = intToFloat(p, BS);
2115 std::list<u16> clients = m_clients.getClientIDs();
2116 for(std::list<u16>::iterator
2117 i = clients.begin();
2118 i != clients.end(); ++i)
2124 Player *player = m_env->getPlayer(*i);
2127 // If player is far away, only set modified blocks not sent
2128 v3f player_pos = player->getPosition();
2129 if(player_pos.getDistanceFrom(p_f) > maxd)
2131 far_players->push_back(*i);
2137 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2139 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2141 *pkt << p << n.param0 << n.param1 << n.param2
2142 << (u8) (remove_metadata ? 0 : 1);
2144 if (!remove_metadata) {
2145 if (client->net_proto_version <= 21) {
2146 // Old clients always clear metadata; fix it
2147 // by sending the full block again.
2148 client->SetBlockNotSent(p);
2155 if (pkt->getSize() > 0)
2156 m_clients.send(*i, 0, pkt, true);
2160 void Server::setBlockNotSent(v3s16 p)
2162 std::list<u16> clients = m_clients.getClientIDs();
2164 for(std::list<u16>::iterator
2165 i = clients.begin();
2166 i != clients.end(); ++i)
2168 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2169 client->SetBlockNotSent(p);
2174 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2176 DSTACK(__FUNCTION_NAME);
2178 v3s16 p = block->getPos();
2181 Create a packet with the block in the right format
2184 std::ostringstream os(std::ios_base::binary);
2185 block->serialize(os, ver, false);
2186 block->serializeNetworkSpecific(os, net_proto_version);
2187 std::string s = os.str();
2189 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2190 2 + 2 + 2 + 2 + s.size(), peer_id);
2193 pkt->putRawString(s.c_str(), s.size());
2197 void Server::SendBlocks(float dtime)
2199 DSTACK(__FUNCTION_NAME);
2201 JMutexAutoLock envlock(m_env_mutex);
2202 //TODO check if one big lock could be faster then multiple small ones
2204 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2206 std::vector<PrioritySortedBlockTransfer> queue;
2208 s32 total_sending = 0;
2211 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2213 std::list<u16> clients = m_clients.getClientIDs();
2216 for(std::list<u16>::iterator
2217 i = clients.begin();
2218 i != clients.end(); ++i)
2220 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2225 total_sending += client->SendingCount();
2226 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2232 // Lowest priority number comes first.
2233 // Lowest is most important.
2234 std::sort(queue.begin(), queue.end());
2237 for(u32 i=0; i<queue.size(); i++)
2239 //TODO: Calculate limit dynamically
2240 if(total_sending >= g_settings->getS32
2241 ("max_simultaneous_block_sends_server_total"))
2244 PrioritySortedBlockTransfer q = queue[i];
2246 MapBlock *block = NULL;
2249 block = m_env->getMap().getBlockNoCreate(q.pos);
2251 catch(InvalidPositionException &e)
2256 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2261 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2263 client->SentBlock(q.pos);
2269 void Server::fillMediaCache()
2271 DSTACK(__FUNCTION_NAME);
2273 infostream<<"Server: Calculating media file checksums"<<std::endl;
2275 // Collect all media file paths
2276 std::list<std::string> paths;
2277 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2278 i != m_mods.end(); i++){
2279 const ModSpec &mod = *i;
2280 paths.push_back(mod.path + DIR_DELIM + "textures");
2281 paths.push_back(mod.path + DIR_DELIM + "sounds");
2282 paths.push_back(mod.path + DIR_DELIM + "media");
2283 paths.push_back(mod.path + DIR_DELIM + "models");
2285 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2287 // Collect media file information from paths into cache
2288 for(std::list<std::string>::iterator i = paths.begin();
2289 i != paths.end(); i++)
2291 std::string mediapath = *i;
2292 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2293 for(u32 j=0; j<dirlist.size(); j++){
2294 if(dirlist[j].dir) // Ignode dirs
2296 std::string filename = dirlist[j].name;
2297 // If name contains illegal characters, ignore the file
2298 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2299 infostream<<"Server: ignoring illegal file name: \""
2300 <<filename<<"\""<<std::endl;
2303 // If name is not in a supported format, ignore it
2304 const char *supported_ext[] = {
2305 ".png", ".jpg", ".bmp", ".tga",
2306 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2308 ".x", ".b3d", ".md2", ".obj",
2311 if(removeStringEnd(filename, supported_ext) == ""){
2312 infostream<<"Server: ignoring unsupported file extension: \""
2313 <<filename<<"\""<<std::endl;
2316 // Ok, attempt to load the file and add to cache
2317 std::string filepath = mediapath + DIR_DELIM + filename;
2319 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2320 if(fis.good() == false){
2321 errorstream<<"Server::fillMediaCache(): Could not open \""
2322 <<filename<<"\" for reading"<<std::endl;
2325 std::ostringstream tmp_os(std::ios_base::binary);
2329 fis.read(buf, 1024);
2330 std::streamsize len = fis.gcount();
2331 tmp_os.write(buf, len);
2340 errorstream<<"Server::fillMediaCache(): Failed to read \""
2341 <<filename<<"\""<<std::endl;
2344 if(tmp_os.str().length() == 0){
2345 errorstream<<"Server::fillMediaCache(): Empty file \""
2346 <<filepath<<"\""<<std::endl;
2351 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2353 unsigned char *digest = sha1.getDigest();
2354 std::string sha1_base64 = base64_encode(digest, 20);
2355 std::string sha1_hex = hex_encode((char*)digest, 20);
2359 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2360 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2365 struct SendableMediaAnnouncement
2368 std::string sha1_digest;
2370 SendableMediaAnnouncement(const std::string &name_="",
2371 const std::string &sha1_digest_=""):
2373 sha1_digest(sha1_digest_)
2377 void Server::sendMediaAnnouncement(u16 peer_id)
2379 DSTACK(__FUNCTION_NAME);
2381 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2384 std::list<SendableMediaAnnouncement> file_announcements;
2386 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2387 i != m_media.end(); i++){
2389 file_announcements.push_back(
2390 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2394 std::ostringstream os(std::ios_base::binary);
2401 u16 length of sha1_digest
2406 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2407 *pkt << (u16) file_announcements.size();
2409 for(std::list<SendableMediaAnnouncement>::iterator
2410 j = file_announcements.begin();
2411 j != file_announcements.end(); ++j) {
2412 *pkt << j->name << j->sha1_digest;
2415 *pkt << g_settings->get("remote_media");
2419 struct SendableMedia
2425 SendableMedia(const std::string &name_="", const std::string &path_="",
2426 const std::string &data_=""):
2433 void Server::sendRequestedMedia(u16 peer_id,
2434 const std::list<std::string> &tosend)
2436 DSTACK(__FUNCTION_NAME);
2438 verbosestream<<"Server::sendRequestedMedia(): "
2439 <<"Sending files to client"<<std::endl;
2443 // Put 5kB in one bunch (this is not accurate)
2444 u32 bytes_per_bunch = 5000;
2446 std::vector< std::list<SendableMedia> > file_bunches;
2447 file_bunches.push_back(std::list<SendableMedia>());
2449 u32 file_size_bunch_total = 0;
2451 for(std::list<std::string>::const_iterator i = tosend.begin();
2452 i != tosend.end(); ++i)
2454 const std::string &name = *i;
2456 if(m_media.find(name) == m_media.end()) {
2457 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2458 <<"unknown file \""<<(name)<<"\""<<std::endl;
2462 //TODO get path + name
2463 std::string tpath = m_media[name].path;
2466 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2467 if(fis.good() == false){
2468 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2469 <<tpath<<"\" for reading"<<std::endl;
2472 std::ostringstream tmp_os(std::ios_base::binary);
2476 fis.read(buf, 1024);
2477 std::streamsize len = fis.gcount();
2478 tmp_os.write(buf, len);
2479 file_size_bunch_total += len;
2488 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2489 <<name<<"\""<<std::endl;
2492 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2493 <<tname<<"\""<<std::endl;*/
2495 file_bunches[file_bunches.size()-1].push_back(
2496 SendableMedia(name, tpath, tmp_os.str()));
2498 // Start next bunch if got enough data
2499 if(file_size_bunch_total >= bytes_per_bunch) {
2500 file_bunches.push_back(std::list<SendableMedia>());
2501 file_size_bunch_total = 0;
2506 /* Create and send packets */
2508 u16 num_bunches = file_bunches.size();
2509 for(u16 i = 0; i < num_bunches; i++) {
2512 u16 total number of texture bunches
2513 u16 index of this bunch
2514 u32 number of files in this bunch
2523 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2524 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2526 for(std::list<SendableMedia>::iterator
2527 j = file_bunches[i].begin();
2528 j != file_bunches[i].end(); ++j) {
2530 pkt->putLongString(j->data);
2533 verbosestream << "Server::sendRequestedMedia(): bunch "
2534 << i << "/" << num_bunches
2535 << " files=" << file_bunches[i].size()
2536 << " size=" << pkt->getSize() << std::endl;
2541 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2543 if(m_detached_inventories.count(name) == 0) {
2544 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2547 Inventory *inv = m_detached_inventories[name];
2548 std::ostringstream os(std::ios_base::binary);
2550 os << serializeString(name);
2554 std::string s = os.str();
2556 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2557 pkt->putRawString(s.c_str(), s.size());
2559 if (peer_id != PEER_ID_INEXISTENT) {
2563 m_clients.sendToAll(0, pkt, true);
2567 void Server::sendDetachedInventories(u16 peer_id)
2569 DSTACK(__FUNCTION_NAME);
2571 for(std::map<std::string, Inventory*>::iterator
2572 i = m_detached_inventories.begin();
2573 i != m_detached_inventories.end(); i++) {
2574 const std::string &name = i->first;
2575 //Inventory *inv = i->second;
2576 sendDetachedInventory(name, peer_id);
2584 void Server::DiePlayer(u16 peer_id)
2586 DSTACK(__FUNCTION_NAME);
2588 PlayerSAO *playersao = getPlayerSAO(peer_id);
2591 infostream<<"Server::DiePlayer(): Player "
2592 <<playersao->getPlayer()->getName()
2593 <<" dies"<<std::endl;
2595 playersao->setHP(0);
2597 // Trigger scripted stuff
2598 m_script->on_dieplayer(playersao);
2600 SendPlayerHP(peer_id);
2601 SendDeathscreen(peer_id, false, v3f(0,0,0));
2604 void Server::RespawnPlayer(u16 peer_id)
2606 DSTACK(__FUNCTION_NAME);
2608 PlayerSAO *playersao = getPlayerSAO(peer_id);
2611 infostream<<"Server::RespawnPlayer(): Player "
2612 <<playersao->getPlayer()->getName()
2613 <<" respawns"<<std::endl;
2615 playersao->setHP(PLAYER_MAX_HP);
2616 playersao->setBreath(PLAYER_MAX_BREATH);
2618 bool repositioned = m_script->on_respawnplayer(playersao);
2620 v3f pos = findSpawnPos(m_env->getServerMap());
2621 playersao->setPos(pos);
2625 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2627 DSTACK(__FUNCTION_NAME);
2629 SendAccessDenied(peer_id, reason);
2630 m_clients.event(peer_id, CSE_SetDenied);
2631 m_con.DisconnectPeer(peer_id);
2634 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2636 DSTACK(__FUNCTION_NAME);
2637 std::wstring message;
2640 Clear references to playing sounds
2642 for(std::map<s32, ServerPlayingSound>::iterator
2643 i = m_playing_sounds.begin();
2644 i != m_playing_sounds.end();)
2646 ServerPlayingSound &psound = i->second;
2647 psound.clients.erase(peer_id);
2648 if(psound.clients.empty())
2649 m_playing_sounds.erase(i++);
2654 Player *player = m_env->getPlayer(peer_id);
2656 // Collect information about leaving in chat
2658 if(player != NULL && reason != CDR_DENY)
2660 std::wstring name = narrow_to_wide(player->getName());
2663 message += L" left the game.";
2664 if(reason == CDR_TIMEOUT)
2665 message += L" (timed out)";
2669 /* Run scripts and remove from environment */
2673 PlayerSAO *playersao = player->getPlayerSAO();
2676 m_script->on_leaveplayer(playersao);
2678 playersao->disconnected();
2686 if(player != NULL && reason != CDR_DENY)
2688 std::ostringstream os(std::ios_base::binary);
2689 std::list<u16> clients = m_clients.getClientIDs();
2691 for(std::list<u16>::iterator
2692 i = clients.begin();
2693 i != clients.end(); ++i)
2696 Player *player = m_env->getPlayer(*i);
2699 // Get name of player
2700 os<<player->getName()<<" ";
2703 actionstream<<player->getName()<<" "
2704 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2705 <<" List of players: "<<os.str()<<std::endl;
2709 JMutexAutoLock env_lock(m_env_mutex);
2710 m_clients.DeleteClient(peer_id);
2714 // Send leave chat message to all remaining clients
2715 if(message.length() != 0)
2716 SendChatMessage(PEER_ID_INEXISTENT,message);
2719 void Server::UpdateCrafting(u16 peer_id)
2721 DSTACK(__FUNCTION_NAME);
2723 Player* player = m_env->getPlayer(peer_id);
2726 // Get a preview for crafting
2728 InventoryLocation loc;
2729 loc.setPlayer(player->getName());
2730 getCraftingResult(&player->inventory, preview, false, this);
2731 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2733 // Put the new preview in
2734 InventoryList *plist = player->inventory.getList("craftpreview");
2736 assert(plist->getSize() >= 1);
2737 plist->changeItem(0, preview);
2740 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2742 RemoteClient *client = getClientNoEx(peer_id,state_min);
2744 throw ClientNotFoundException("Client not found");
2748 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2750 return m_clients.getClientNoEx(peer_id, state_min);
2753 std::string Server::getPlayerName(u16 peer_id)
2755 Player *player = m_env->getPlayer(peer_id);
2757 return "[id="+itos(peer_id)+"]";
2758 return player->getName();
2761 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2763 Player *player = m_env->getPlayer(peer_id);
2766 return player->getPlayerSAO();
2769 std::wstring Server::getStatusString()
2771 std::wostringstream os(std::ios_base::binary);
2774 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2776 os<<L", uptime="<<m_uptime.get();
2778 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2779 // Information about clients
2782 std::list<u16> clients = m_clients.getClientIDs();
2783 for(std::list<u16>::iterator i = clients.begin();
2784 i != clients.end(); ++i)
2787 Player *player = m_env->getPlayer(*i);
2788 // Get name of player
2789 std::wstring name = L"unknown";
2791 name = narrow_to_wide(player->getName());
2792 // Add name to information string
2800 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2801 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2802 if(g_settings->get("motd") != "")
2803 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2807 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2809 std::set<std::string> privs;
2810 m_script->getAuth(name, NULL, &privs);
2814 bool Server::checkPriv(const std::string &name, const std::string &priv)
2816 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2817 return (privs.count(priv) != 0);
2820 void Server::reportPrivsModified(const std::string &name)
2823 std::list<u16> clients = m_clients.getClientIDs();
2824 for(std::list<u16>::iterator
2825 i = clients.begin();
2826 i != clients.end(); ++i){
2827 Player *player = m_env->getPlayer(*i);
2828 reportPrivsModified(player->getName());
2831 Player *player = m_env->getPlayer(name.c_str());
2834 SendPlayerPrivileges(player->peer_id);
2835 PlayerSAO *sao = player->getPlayerSAO();
2838 sao->updatePrivileges(
2839 getPlayerEffectivePrivs(name),
2844 void Server::reportInventoryFormspecModified(const std::string &name)
2846 Player *player = m_env->getPlayer(name.c_str());
2849 SendPlayerInventoryFormspec(player->peer_id);
2852 void Server::setIpBanned(const std::string &ip, const std::string &name)
2854 m_banmanager->add(ip, name);
2857 void Server::unsetIpBanned(const std::string &ip_or_name)
2859 m_banmanager->remove(ip_or_name);
2862 std::string Server::getBanDescription(const std::string &ip_or_name)
2864 return m_banmanager->getBanDescription(ip_or_name);
2867 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2869 Player *player = m_env->getPlayer(name);
2873 if (player->peer_id == PEER_ID_INEXISTENT)
2876 SendChatMessage(player->peer_id, msg);
2879 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2881 Player *player = m_env->getPlayer(playername);
2885 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2889 SendShowFormspecMessage(player->peer_id, formspec, formname);
2893 u32 Server::hudAdd(Player *player, HudElement *form) {
2897 u32 id = player->addHud(form);
2899 SendHUDAdd(player->peer_id, id, form);
2904 bool Server::hudRemove(Player *player, u32 id) {
2908 HudElement* todel = player->removeHud(id);
2915 SendHUDRemove(player->peer_id, id);
2919 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2923 SendHUDChange(player->peer_id, id, stat, data);
2927 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2931 SendHUDSetFlags(player->peer_id, flags, mask);
2932 player->hud_flags = flags;
2934 PlayerSAO* playersao = player->getPlayerSAO();
2936 if (playersao == NULL)
2939 m_script->player_event(playersao, "hud_changed");
2943 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2946 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2949 std::ostringstream os(std::ios::binary);
2950 writeS32(os, hotbar_itemcount);
2951 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2955 void Server::hudSetHotbarImage(Player *player, std::string name) {
2959 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2962 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2966 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2969 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2974 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2978 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2983 SendEyeOffset(player->peer_id, first, third);
2987 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2988 const std::string &type, const std::vector<std::string> ¶ms)
2993 SendSetSky(player->peer_id, bgcolor, type, params);
2997 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3003 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3007 void Server::notifyPlayers(const std::wstring &msg)
3009 SendChatMessage(PEER_ID_INEXISTENT,msg);
3012 void Server::spawnParticle(const char *playername, v3f pos,
3013 v3f velocity, v3f acceleration,
3014 float expirationtime, float size, bool
3015 collisiondetection, bool vertical, std::string texture)
3017 Player *player = m_env->getPlayer(playername);
3020 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3021 expirationtime, size, collisiondetection, vertical, texture);
3024 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3025 float expirationtime, float size,
3026 bool collisiondetection, bool vertical, std::string texture)
3028 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3029 expirationtime, size, collisiondetection, vertical, texture);
3032 u32 Server::addParticleSpawner(const char *playername,
3033 u16 amount, float spawntime,
3034 v3f minpos, v3f maxpos,
3035 v3f minvel, v3f maxvel,
3036 v3f minacc, v3f maxacc,
3037 float minexptime, float maxexptime,
3038 float minsize, float maxsize,
3039 bool collisiondetection, bool vertical, std::string texture)
3041 Player *player = m_env->getPlayer(playername);
3046 for(;;) // look for unused particlespawner id
3049 if (std::find(m_particlespawner_ids.begin(),
3050 m_particlespawner_ids.end(), id)
3051 == m_particlespawner_ids.end())
3053 m_particlespawner_ids.push_back(id);
3058 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3059 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3060 minexptime, maxexptime, minsize, maxsize,
3061 collisiondetection, vertical, texture, id);
3066 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3067 v3f minpos, v3f maxpos,
3068 v3f minvel, v3f maxvel,
3069 v3f minacc, v3f maxacc,
3070 float minexptime, float maxexptime,
3071 float minsize, float maxsize,
3072 bool collisiondetection, bool vertical, std::string texture)
3075 for(;;) // look for unused particlespawner id
3078 if (std::find(m_particlespawner_ids.begin(),
3079 m_particlespawner_ids.end(), id)
3080 == m_particlespawner_ids.end())
3082 m_particlespawner_ids.push_back(id);
3087 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3088 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3089 minexptime, maxexptime, minsize, maxsize,
3090 collisiondetection, vertical, texture, id);
3095 void Server::deleteParticleSpawner(const char *playername, u32 id)
3097 Player *player = m_env->getPlayer(playername);
3101 m_particlespawner_ids.erase(
3102 std::remove(m_particlespawner_ids.begin(),
3103 m_particlespawner_ids.end(), id),
3104 m_particlespawner_ids.end());
3105 SendDeleteParticleSpawner(player->peer_id, id);
3108 void Server::deleteParticleSpawnerAll(u32 id)
3110 m_particlespawner_ids.erase(
3111 std::remove(m_particlespawner_ids.begin(),
3112 m_particlespawner_ids.end(), id),
3113 m_particlespawner_ids.end());
3114 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3117 Inventory* Server::createDetachedInventory(const std::string &name)
3119 if(m_detached_inventories.count(name) > 0){
3120 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3121 delete m_detached_inventories[name];
3123 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3125 Inventory *inv = new Inventory(m_itemdef);
3127 m_detached_inventories[name] = inv;
3128 //TODO find a better way to do this
3129 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3136 BoolScopeSet(bool *dst, bool val):
3139 m_orig_state = *m_dst;
3144 *m_dst = m_orig_state;
3151 // actions: time-reversed list
3152 // Return value: success/failure
3153 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3154 std::list<std::string> *log)
3156 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3157 ServerMap *map = (ServerMap*)(&m_env->getMap());
3159 // Fail if no actions to handle
3160 if(actions.empty()){
3161 log->push_back("Nothing to do.");
3168 for(std::list<RollbackAction>::const_iterator
3169 i = actions.begin();
3170 i != actions.end(); i++)
3172 const RollbackAction &action = *i;
3174 bool success = action.applyRevert(map, this, this);
3177 std::ostringstream os;
3178 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3179 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3181 log->push_back(os.str());
3183 std::ostringstream os;
3184 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3185 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3187 log->push_back(os.str());
3191 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3192 <<" failed"<<std::endl;
3194 // Call it done if less than half failed
3195 return num_failed <= num_tried/2;
3198 // IGameDef interface
3200 IItemDefManager* Server::getItemDefManager()
3204 INodeDefManager* Server::getNodeDefManager()
3208 ICraftDefManager* Server::getCraftDefManager()
3212 ITextureSource* Server::getTextureSource()
3216 IShaderSource* Server::getShaderSource()
3220 scene::ISceneManager* Server::getSceneManager()
3225 u16 Server::allocateUnknownNodeId(const std::string &name)
3227 return m_nodedef->allocateDummy(name);
3229 ISoundManager* Server::getSoundManager()
3231 return &dummySoundManager;
3233 MtEventManager* Server::getEventManager()
3238 IWritableItemDefManager* Server::getWritableItemDefManager()
3242 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3246 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3251 const ModSpec* Server::getModSpec(const std::string &modname)
3253 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3254 i != m_mods.end(); i++){
3255 const ModSpec &mod = *i;
3256 if(mod.name == modname)
3261 void Server::getModNames(std::list<std::string> &modlist)
3263 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3265 modlist.push_back(i->name);
3268 std::string Server::getBuiltinLuaPath()
3270 return porting::path_share + DIR_DELIM + "builtin";
3273 v3f findSpawnPos(ServerMap &map)
3275 //return v3f(50,50,50)*BS;
3280 nodepos = v2s16(0,0);
3285 s16 water_level = map.getWaterLevel();
3287 // Try to find a good place a few times
3288 for(s32 i=0; i<1000; i++)
3291 // We're going to try to throw the player to this position
3292 v2s16 nodepos2d = v2s16(
3293 -range + (myrand() % (range * 2)),
3294 -range + (myrand() % (range * 2)));
3296 // Get ground height at point
3297 s16 groundheight = map.findGroundLevel(nodepos2d);
3298 if (groundheight <= water_level) // Don't go underwater
3300 if (groundheight > water_level + 6) // Don't go to high places
3303 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3304 bool is_good = false;
3306 for (s32 i = 0; i < 10; i++) {
3307 v3s16 blockpos = getNodeBlockPos(nodepos);
3308 map.emergeBlock(blockpos, true);
3309 content_t c = map.getNodeNoEx(nodepos).getContent();
3310 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3312 if (air_count >= 2){
3320 // Found a good place
3321 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3327 return intToFloat(nodepos, BS);
3330 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3332 bool newplayer = false;
3335 Try to get an existing player
3337 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3339 // If player is already connected, cancel
3340 if(player != NULL && player->peer_id != 0)
3342 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3347 If player with the wanted peer_id already exists, cancel.
3349 if(m_env->getPlayer(peer_id) != NULL)
3351 infostream<<"emergePlayer(): Player with wrong name but same"
3352 " peer_id already exists"<<std::endl;
3356 // Load player if it isn't already loaded
3358 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3361 // Create player if it doesn't exist
3364 player = new RemotePlayer(this, name);
3365 // Set player position
3366 infostream<<"Server: Finding spawn place for player \""
3367 <<name<<"\""<<std::endl;
3368 v3f pos = findSpawnPos(m_env->getServerMap());
3369 player->setPosition(pos);
3371 // Make sure the player is saved
3372 player->setModified(true);
3374 // Add player to environment
3375 m_env->addPlayer(player);
3378 // Create a new player active object
3379 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3380 getPlayerEffectivePrivs(player->getName()),
3383 /* Clean up old HUD elements from previous sessions */
3386 /* Add object to environment */
3387 m_env->addActiveObject(playersao);
3391 m_script->on_newplayer(playersao);
3397 void dedicated_server_loop(Server &server, bool &kill)
3399 DSTACK(__FUNCTION_NAME);
3401 verbosestream<<"dedicated_server_loop()"<<std::endl;
3403 IntervalLimiter m_profiler_interval;
3407 float steplen = g_settings->getFloat("dedicated_server_step");
3408 // This is kind of a hack but can be done like this
3409 // because server.step() is very light
3411 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3412 sleep_ms((int)(steplen*1000.0));
3414 server.step(steplen);
3416 if(server.getShutdownRequested() || kill)
3418 infostream<<"Dedicated server quitting"<<std::endl;
3420 if(g_settings->getBool("server_announce"))
3421 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3429 float profiler_print_interval =
3430 g_settings->getFloat("profiler_print_interval");
3431 if(profiler_print_interval != 0)
3433 if(m_profiler_interval.step(steplen, profiler_print_interval))
3435 infostream<<"Profiler:"<<std::endl;
3436 g_profiler->print(infostream);
3437 g_profiler->clear();