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"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/mathconstants.h"
63 #include "util/serialize.h"
64 #include "util/thread.h"
65 #include "defaultsettings.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, 2 + 2 + 2);
2085 std::list<u16> clients = m_clients.getClientIDs();
2086 for(std::list<u16>::iterator
2087 i = clients.begin();
2088 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);
2107 m_clients.send(*i, 0, pkt, true, false);
2109 // This loop needs the deletion of the packet here
2113 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2114 std::list<u16> *far_players, float far_d_nodes,
2115 bool remove_metadata)
2117 float maxd = far_d_nodes*BS;
2118 v3f p_f = intToFloat(p, BS);
2120 std::list<u16> clients = m_clients.getClientIDs();
2121 for(std::list<u16>::iterator
2122 i = clients.begin();
2123 i != clients.end(); ++i)
2129 Player *player = m_env->getPlayer(*i);
2132 // If player is far away, only set modified blocks not sent
2133 v3f player_pos = player->getPosition();
2134 if(player_pos.getDistanceFrom(p_f) > maxd)
2136 far_players->push_back(*i);
2142 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 0);
2144 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2146 *pkt << p << n.param0 << n.param1 << n.param2
2147 << (u8) (remove_metadata ? 0 : 1);
2149 if (!remove_metadata) {
2150 if (client->net_proto_version <= 21) {
2151 // Old clients always clear metadata; fix it
2152 // by sending the full block again.
2153 client->SetBlockNotSent(p);
2160 if (pkt->getSize() > 0)
2161 m_clients.send(*i, 0, pkt, true);
2165 void Server::setBlockNotSent(v3s16 p)
2167 std::list<u16> clients = m_clients.getClientIDs();
2169 for(std::list<u16>::iterator
2170 i = clients.begin();
2171 i != clients.end(); ++i)
2173 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2174 client->SetBlockNotSent(p);
2179 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2181 DSTACK(__FUNCTION_NAME);
2183 v3s16 p = block->getPos();
2186 Create a packet with the block in the right format
2189 std::ostringstream os(std::ios_base::binary);
2190 block->serialize(os, ver, false);
2191 block->serializeNetworkSpecific(os, net_proto_version);
2192 std::string s = os.str();
2194 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2195 2 + 2 + 2 + 2 + s.size(), peer_id);
2198 pkt->putRawString(s.c_str(), s.size());
2202 void Server::SendBlocks(float dtime)
2204 DSTACK(__FUNCTION_NAME);
2206 JMutexAutoLock envlock(m_env_mutex);
2207 //TODO check if one big lock could be faster then multiple small ones
2209 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2211 std::vector<PrioritySortedBlockTransfer> queue;
2213 s32 total_sending = 0;
2216 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2218 std::list<u16> clients = m_clients.getClientIDs();
2221 for(std::list<u16>::iterator
2222 i = clients.begin();
2223 i != clients.end(); ++i)
2225 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2230 total_sending += client->SendingCount();
2231 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2237 // Lowest priority number comes first.
2238 // Lowest is most important.
2239 std::sort(queue.begin(), queue.end());
2242 for(u32 i=0; i<queue.size(); i++)
2244 //TODO: Calculate limit dynamically
2245 if(total_sending >= g_settings->getS32
2246 ("max_simultaneous_block_sends_server_total"))
2249 PrioritySortedBlockTransfer q = queue[i];
2251 MapBlock *block = NULL;
2254 block = m_env->getMap().getBlockNoCreate(q.pos);
2256 catch(InvalidPositionException &e)
2261 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2266 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2268 client->SentBlock(q.pos);
2274 void Server::fillMediaCache()
2276 DSTACK(__FUNCTION_NAME);
2278 infostream<<"Server: Calculating media file checksums"<<std::endl;
2280 // Collect all media file paths
2281 std::list<std::string> paths;
2282 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2283 i != m_mods.end(); i++){
2284 const ModSpec &mod = *i;
2285 paths.push_back(mod.path + DIR_DELIM + "textures");
2286 paths.push_back(mod.path + DIR_DELIM + "sounds");
2287 paths.push_back(mod.path + DIR_DELIM + "media");
2288 paths.push_back(mod.path + DIR_DELIM + "models");
2290 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2292 // Collect media file information from paths into cache
2293 for(std::list<std::string>::iterator i = paths.begin();
2294 i != paths.end(); i++)
2296 std::string mediapath = *i;
2297 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2298 for(u32 j=0; j<dirlist.size(); j++){
2299 if(dirlist[j].dir) // Ignode dirs
2301 std::string filename = dirlist[j].name;
2302 // If name contains illegal characters, ignore the file
2303 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2304 infostream<<"Server: ignoring illegal file name: \""
2305 <<filename<<"\""<<std::endl;
2308 // If name is not in a supported format, ignore it
2309 const char *supported_ext[] = {
2310 ".png", ".jpg", ".bmp", ".tga",
2311 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2313 ".x", ".b3d", ".md2", ".obj",
2316 if(removeStringEnd(filename, supported_ext) == ""){
2317 infostream<<"Server: ignoring unsupported file extension: \""
2318 <<filename<<"\""<<std::endl;
2321 // Ok, attempt to load the file and add to cache
2322 std::string filepath = mediapath + DIR_DELIM + filename;
2324 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2325 if(fis.good() == false){
2326 errorstream<<"Server::fillMediaCache(): Could not open \""
2327 <<filename<<"\" for reading"<<std::endl;
2330 std::ostringstream tmp_os(std::ios_base::binary);
2334 fis.read(buf, 1024);
2335 std::streamsize len = fis.gcount();
2336 tmp_os.write(buf, len);
2345 errorstream<<"Server::fillMediaCache(): Failed to read \""
2346 <<filename<<"\""<<std::endl;
2349 if(tmp_os.str().length() == 0){
2350 errorstream<<"Server::fillMediaCache(): Empty file \""
2351 <<filepath<<"\""<<std::endl;
2356 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2358 unsigned char *digest = sha1.getDigest();
2359 std::string sha1_base64 = base64_encode(digest, 20);
2360 std::string sha1_hex = hex_encode((char*)digest, 20);
2364 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2365 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2370 struct SendableMediaAnnouncement
2373 std::string sha1_digest;
2375 SendableMediaAnnouncement(const std::string &name_="",
2376 const std::string &sha1_digest_=""):
2378 sha1_digest(sha1_digest_)
2382 void Server::sendMediaAnnouncement(u16 peer_id)
2384 DSTACK(__FUNCTION_NAME);
2386 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2389 std::list<SendableMediaAnnouncement> file_announcements;
2391 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2392 i != m_media.end(); i++){
2394 file_announcements.push_back(
2395 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2399 std::ostringstream os(std::ios_base::binary);
2406 u16 length of sha1_digest
2411 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2412 *pkt << (u16) file_announcements.size();
2414 for(std::list<SendableMediaAnnouncement>::iterator
2415 j = file_announcements.begin();
2416 j != file_announcements.end(); ++j) {
2417 *pkt << j->name << j->sha1_digest;
2420 *pkt << g_settings->get("remote_media");
2424 struct SendableMedia
2430 SendableMedia(const std::string &name_="", const std::string &path_="",
2431 const std::string &data_=""):
2438 void Server::sendRequestedMedia(u16 peer_id,
2439 const std::list<std::string> &tosend)
2441 DSTACK(__FUNCTION_NAME);
2443 verbosestream<<"Server::sendRequestedMedia(): "
2444 <<"Sending files to client"<<std::endl;
2448 // Put 5kB in one bunch (this is not accurate)
2449 u32 bytes_per_bunch = 5000;
2451 std::vector< std::list<SendableMedia> > file_bunches;
2452 file_bunches.push_back(std::list<SendableMedia>());
2454 u32 file_size_bunch_total = 0;
2456 for(std::list<std::string>::const_iterator i = tosend.begin();
2457 i != tosend.end(); ++i)
2459 const std::string &name = *i;
2461 if(m_media.find(name) == m_media.end()) {
2462 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2463 <<"unknown file \""<<(name)<<"\""<<std::endl;
2467 //TODO get path + name
2468 std::string tpath = m_media[name].path;
2471 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2472 if(fis.good() == false){
2473 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2474 <<tpath<<"\" for reading"<<std::endl;
2477 std::ostringstream tmp_os(std::ios_base::binary);
2481 fis.read(buf, 1024);
2482 std::streamsize len = fis.gcount();
2483 tmp_os.write(buf, len);
2484 file_size_bunch_total += len;
2493 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2494 <<name<<"\""<<std::endl;
2497 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2498 <<tname<<"\""<<std::endl;*/
2500 file_bunches[file_bunches.size()-1].push_back(
2501 SendableMedia(name, tpath, tmp_os.str()));
2503 // Start next bunch if got enough data
2504 if(file_size_bunch_total >= bytes_per_bunch) {
2505 file_bunches.push_back(std::list<SendableMedia>());
2506 file_size_bunch_total = 0;
2511 /* Create and send packets */
2513 u16 num_bunches = file_bunches.size();
2514 for(u16 i = 0; i < num_bunches; i++) {
2517 u16 total number of texture bunches
2518 u16 index of this bunch
2519 u32 number of files in this bunch
2528 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2529 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2531 for(std::list<SendableMedia>::iterator
2532 j = file_bunches[i].begin();
2533 j != file_bunches[i].end(); ++j) {
2535 pkt->putLongString(j->data);
2538 verbosestream << "Server::sendRequestedMedia(): bunch "
2539 << i << "/" << num_bunches
2540 << " files=" << file_bunches[i].size()
2541 << " size=" << pkt->getSize() << std::endl;
2546 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2548 if(m_detached_inventories.count(name) == 0) {
2549 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2552 Inventory *inv = m_detached_inventories[name];
2553 std::ostringstream os(std::ios_base::binary);
2555 os << serializeString(name);
2559 std::string s = os.str();
2561 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2562 pkt->putRawString(s.c_str(), s.size());
2564 if (peer_id != PEER_ID_INEXISTENT) {
2568 m_clients.sendToAll(0, pkt, true);
2572 void Server::sendDetachedInventories(u16 peer_id)
2574 DSTACK(__FUNCTION_NAME);
2576 for(std::map<std::string, Inventory*>::iterator
2577 i = m_detached_inventories.begin();
2578 i != m_detached_inventories.end(); i++) {
2579 const std::string &name = i->first;
2580 //Inventory *inv = i->second;
2581 sendDetachedInventory(name, peer_id);
2589 void Server::DiePlayer(u16 peer_id)
2591 DSTACK(__FUNCTION_NAME);
2593 PlayerSAO *playersao = getPlayerSAO(peer_id);
2596 infostream<<"Server::DiePlayer(): Player "
2597 <<playersao->getPlayer()->getName()
2598 <<" dies"<<std::endl;
2600 playersao->setHP(0);
2602 // Trigger scripted stuff
2603 m_script->on_dieplayer(playersao);
2605 SendPlayerHP(peer_id);
2606 SendDeathscreen(peer_id, false, v3f(0,0,0));
2609 void Server::RespawnPlayer(u16 peer_id)
2611 DSTACK(__FUNCTION_NAME);
2613 PlayerSAO *playersao = getPlayerSAO(peer_id);
2616 infostream<<"Server::RespawnPlayer(): Player "
2617 <<playersao->getPlayer()->getName()
2618 <<" respawns"<<std::endl;
2620 playersao->setHP(PLAYER_MAX_HP);
2621 playersao->setBreath(PLAYER_MAX_BREATH);
2623 bool repositioned = m_script->on_respawnplayer(playersao);
2625 v3f pos = findSpawnPos(m_env->getServerMap());
2626 playersao->setPos(pos);
2630 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2632 DSTACK(__FUNCTION_NAME);
2634 SendAccessDenied(peer_id, reason);
2635 m_clients.event(peer_id, CSE_SetDenied);
2636 m_con.DisconnectPeer(peer_id);
2639 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2641 DSTACK(__FUNCTION_NAME);
2642 std::wstring message;
2645 Clear references to playing sounds
2647 for(std::map<s32, ServerPlayingSound>::iterator
2648 i = m_playing_sounds.begin();
2649 i != m_playing_sounds.end();)
2651 ServerPlayingSound &psound = i->second;
2652 psound.clients.erase(peer_id);
2653 if(psound.clients.empty())
2654 m_playing_sounds.erase(i++);
2659 Player *player = m_env->getPlayer(peer_id);
2661 // Collect information about leaving in chat
2663 if(player != NULL && reason != CDR_DENY)
2665 std::wstring name = narrow_to_wide(player->getName());
2668 message += L" left the game.";
2669 if(reason == CDR_TIMEOUT)
2670 message += L" (timed out)";
2674 /* Run scripts and remove from environment */
2678 PlayerSAO *playersao = player->getPlayerSAO();
2681 m_script->on_leaveplayer(playersao);
2683 playersao->disconnected();
2691 if(player != NULL && reason != CDR_DENY)
2693 std::ostringstream os(std::ios_base::binary);
2694 std::list<u16> clients = m_clients.getClientIDs();
2696 for(std::list<u16>::iterator
2697 i = clients.begin();
2698 i != clients.end(); ++i)
2701 Player *player = m_env->getPlayer(*i);
2704 // Get name of player
2705 os<<player->getName()<<" ";
2708 actionstream<<player->getName()<<" "
2709 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
2710 <<" List of players: "<<os.str()<<std::endl;
2714 JMutexAutoLock env_lock(m_env_mutex);
2715 m_clients.DeleteClient(peer_id);
2719 // Send leave chat message to all remaining clients
2720 if(message.length() != 0)
2721 SendChatMessage(PEER_ID_INEXISTENT,message);
2724 void Server::UpdateCrafting(u16 peer_id)
2726 DSTACK(__FUNCTION_NAME);
2728 Player* player = m_env->getPlayer(peer_id);
2731 // Get a preview for crafting
2733 InventoryLocation loc;
2734 loc.setPlayer(player->getName());
2735 getCraftingResult(&player->inventory, preview, false, this);
2736 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2738 // Put the new preview in
2739 InventoryList *plist = player->inventory.getList("craftpreview");
2741 assert(plist->getSize() >= 1);
2742 plist->changeItem(0, preview);
2745 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2747 RemoteClient *client = getClientNoEx(peer_id,state_min);
2749 throw ClientNotFoundException("Client not found");
2753 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2755 return m_clients.getClientNoEx(peer_id, state_min);
2758 std::string Server::getPlayerName(u16 peer_id)
2760 Player *player = m_env->getPlayer(peer_id);
2762 return "[id="+itos(peer_id)+"]";
2763 return player->getName();
2766 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2768 Player *player = m_env->getPlayer(peer_id);
2771 return player->getPlayerSAO();
2774 std::wstring Server::getStatusString()
2776 std::wostringstream os(std::ios_base::binary);
2779 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2781 os<<L", uptime="<<m_uptime.get();
2783 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2784 // Information about clients
2787 std::list<u16> clients = m_clients.getClientIDs();
2788 for(std::list<u16>::iterator i = clients.begin();
2789 i != clients.end(); ++i)
2792 Player *player = m_env->getPlayer(*i);
2793 // Get name of player
2794 std::wstring name = L"unknown";
2796 name = narrow_to_wide(player->getName());
2797 // Add name to information string
2805 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2806 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2807 if(g_settings->get("motd") != "")
2808 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2812 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2814 std::set<std::string> privs;
2815 m_script->getAuth(name, NULL, &privs);
2819 bool Server::checkPriv(const std::string &name, const std::string &priv)
2821 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2822 return (privs.count(priv) != 0);
2825 void Server::reportPrivsModified(const std::string &name)
2828 std::list<u16> clients = m_clients.getClientIDs();
2829 for(std::list<u16>::iterator
2830 i = clients.begin();
2831 i != clients.end(); ++i){
2832 Player *player = m_env->getPlayer(*i);
2833 reportPrivsModified(player->getName());
2836 Player *player = m_env->getPlayer(name.c_str());
2839 SendPlayerPrivileges(player->peer_id);
2840 PlayerSAO *sao = player->getPlayerSAO();
2843 sao->updatePrivileges(
2844 getPlayerEffectivePrivs(name),
2849 void Server::reportInventoryFormspecModified(const std::string &name)
2851 Player *player = m_env->getPlayer(name.c_str());
2854 SendPlayerInventoryFormspec(player->peer_id);
2857 void Server::setIpBanned(const std::string &ip, const std::string &name)
2859 m_banmanager->add(ip, name);
2862 void Server::unsetIpBanned(const std::string &ip_or_name)
2864 m_banmanager->remove(ip_or_name);
2867 std::string Server::getBanDescription(const std::string &ip_or_name)
2869 return m_banmanager->getBanDescription(ip_or_name);
2872 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2874 Player *player = m_env->getPlayer(name);
2878 if (player->peer_id == PEER_ID_INEXISTENT)
2881 SendChatMessage(player->peer_id, msg);
2884 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2886 Player *player = m_env->getPlayer(playername);
2890 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2894 SendShowFormspecMessage(player->peer_id, formspec, formname);
2898 u32 Server::hudAdd(Player *player, HudElement *form) {
2902 u32 id = player->addHud(form);
2904 SendHUDAdd(player->peer_id, id, form);
2909 bool Server::hudRemove(Player *player, u32 id) {
2913 HudElement* todel = player->removeHud(id);
2920 SendHUDRemove(player->peer_id, id);
2924 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2928 SendHUDChange(player->peer_id, id, stat, data);
2932 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2936 SendHUDSetFlags(player->peer_id, flags, mask);
2937 player->hud_flags = flags;
2939 PlayerSAO* playersao = player->getPlayerSAO();
2941 if (playersao == NULL)
2944 m_script->player_event(playersao, "hud_changed");
2948 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2951 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2954 std::ostringstream os(std::ios::binary);
2955 writeS32(os, hotbar_itemcount);
2956 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2960 void Server::hudSetHotbarImage(Player *player, std::string name) {
2964 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2967 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2971 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2974 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2979 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2983 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2988 SendEyeOffset(player->peer_id, first, third);
2992 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2993 const std::string &type, const std::vector<std::string> ¶ms)
2998 SendSetSky(player->peer_id, bgcolor, type, params);
3002 bool Server::overrideDayNightRatio(Player *player, bool do_override,
3008 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3012 void Server::notifyPlayers(const std::wstring &msg)
3014 SendChatMessage(PEER_ID_INEXISTENT,msg);
3017 void Server::spawnParticle(const char *playername, v3f pos,
3018 v3f velocity, v3f acceleration,
3019 float expirationtime, float size, bool
3020 collisiondetection, bool vertical, std::string texture)
3022 Player *player = m_env->getPlayer(playername);
3025 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3026 expirationtime, size, collisiondetection, vertical, texture);
3029 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3030 float expirationtime, float size,
3031 bool collisiondetection, bool vertical, std::string texture)
3033 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3034 expirationtime, size, collisiondetection, vertical, texture);
3037 u32 Server::addParticleSpawner(const char *playername,
3038 u16 amount, float spawntime,
3039 v3f minpos, v3f maxpos,
3040 v3f minvel, v3f maxvel,
3041 v3f minacc, v3f maxacc,
3042 float minexptime, float maxexptime,
3043 float minsize, float maxsize,
3044 bool collisiondetection, bool vertical, std::string texture)
3046 Player *player = m_env->getPlayer(playername);
3051 for(;;) // look for unused particlespawner id
3054 if (std::find(m_particlespawner_ids.begin(),
3055 m_particlespawner_ids.end(), id)
3056 == m_particlespawner_ids.end())
3058 m_particlespawner_ids.push_back(id);
3063 SendAddParticleSpawner(player->peer_id, amount, spawntime,
3064 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3065 minexptime, maxexptime, minsize, maxsize,
3066 collisiondetection, vertical, texture, id);
3071 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3072 v3f minpos, v3f maxpos,
3073 v3f minvel, v3f maxvel,
3074 v3f minacc, v3f maxacc,
3075 float minexptime, float maxexptime,
3076 float minsize, float maxsize,
3077 bool collisiondetection, bool vertical, std::string texture)
3080 for(;;) // look for unused particlespawner id
3083 if (std::find(m_particlespawner_ids.begin(),
3084 m_particlespawner_ids.end(), id)
3085 == m_particlespawner_ids.end())
3087 m_particlespawner_ids.push_back(id);
3092 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3093 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3094 minexptime, maxexptime, minsize, maxsize,
3095 collisiondetection, vertical, texture, id);
3100 void Server::deleteParticleSpawner(const char *playername, u32 id)
3102 Player *player = m_env->getPlayer(playername);
3106 m_particlespawner_ids.erase(
3107 std::remove(m_particlespawner_ids.begin(),
3108 m_particlespawner_ids.end(), id),
3109 m_particlespawner_ids.end());
3110 SendDeleteParticleSpawner(player->peer_id, id);
3113 void Server::deleteParticleSpawnerAll(u32 id)
3115 m_particlespawner_ids.erase(
3116 std::remove(m_particlespawner_ids.begin(),
3117 m_particlespawner_ids.end(), id),
3118 m_particlespawner_ids.end());
3119 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3122 Inventory* Server::createDetachedInventory(const std::string &name)
3124 if(m_detached_inventories.count(name) > 0){
3125 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3126 delete m_detached_inventories[name];
3128 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3130 Inventory *inv = new Inventory(m_itemdef);
3132 m_detached_inventories[name] = inv;
3133 //TODO find a better way to do this
3134 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3141 BoolScopeSet(bool *dst, bool val):
3144 m_orig_state = *m_dst;
3149 *m_dst = m_orig_state;
3156 // actions: time-reversed list
3157 // Return value: success/failure
3158 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3159 std::list<std::string> *log)
3161 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3162 ServerMap *map = (ServerMap*)(&m_env->getMap());
3164 // Fail if no actions to handle
3165 if(actions.empty()){
3166 log->push_back("Nothing to do.");
3173 for(std::list<RollbackAction>::const_iterator
3174 i = actions.begin();
3175 i != actions.end(); i++)
3177 const RollbackAction &action = *i;
3179 bool success = action.applyRevert(map, this, this);
3182 std::ostringstream os;
3183 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3184 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3186 log->push_back(os.str());
3188 std::ostringstream os;
3189 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3190 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3192 log->push_back(os.str());
3196 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3197 <<" failed"<<std::endl;
3199 // Call it done if less than half failed
3200 return num_failed <= num_tried/2;
3203 // IGameDef interface
3205 IItemDefManager* Server::getItemDefManager()
3209 INodeDefManager* Server::getNodeDefManager()
3213 ICraftDefManager* Server::getCraftDefManager()
3217 ITextureSource* Server::getTextureSource()
3221 IShaderSource* Server::getShaderSource()
3225 scene::ISceneManager* Server::getSceneManager()
3230 u16 Server::allocateUnknownNodeId(const std::string &name)
3232 return m_nodedef->allocateDummy(name);
3234 ISoundManager* Server::getSoundManager()
3236 return &dummySoundManager;
3238 MtEventManager* Server::getEventManager()
3243 IWritableItemDefManager* Server::getWritableItemDefManager()
3247 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3251 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3256 const ModSpec* Server::getModSpec(const std::string &modname)
3258 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3259 i != m_mods.end(); i++){
3260 const ModSpec &mod = *i;
3261 if(mod.name == modname)
3266 void Server::getModNames(std::list<std::string> &modlist)
3268 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
3270 modlist.push_back(i->name);
3273 std::string Server::getBuiltinLuaPath()
3275 return porting::path_share + DIR_DELIM + "builtin";
3278 v3f findSpawnPos(ServerMap &map)
3280 //return v3f(50,50,50)*BS;
3285 nodepos = v2s16(0,0);
3290 s16 water_level = map.getWaterLevel();
3292 // Try to find a good place a few times
3293 for(s32 i=0; i<1000; i++)
3296 // We're going to try to throw the player to this position
3297 v2s16 nodepos2d = v2s16(
3298 -range + (myrand() % (range * 2)),
3299 -range + (myrand() % (range * 2)));
3301 // Get ground height at point
3302 s16 groundheight = map.findGroundLevel(nodepos2d);
3303 if (groundheight <= water_level) // Don't go underwater
3305 if (groundheight > water_level + 6) // Don't go to high places
3308 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3309 bool is_good = false;
3311 for (s32 i = 0; i < 10; i++) {
3312 v3s16 blockpos = getNodeBlockPos(nodepos);
3313 map.emergeBlock(blockpos, true);
3314 content_t c = map.getNodeNoEx(nodepos).getContent();
3315 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3317 if (air_count >= 2){
3325 // Found a good place
3326 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3332 return intToFloat(nodepos, BS);
3335 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3337 bool newplayer = false;
3340 Try to get an existing player
3342 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3344 // If player is already connected, cancel
3345 if(player != NULL && player->peer_id != 0)
3347 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3352 If player with the wanted peer_id already exists, cancel.
3354 if(m_env->getPlayer(peer_id) != NULL)
3356 infostream<<"emergePlayer(): Player with wrong name but same"
3357 " peer_id already exists"<<std::endl;
3361 // Load player if it isn't already loaded
3363 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3366 // Create player if it doesn't exist
3369 player = new RemotePlayer(this, name);
3370 // Set player position
3371 infostream<<"Server: Finding spawn place for player \""
3372 <<name<<"\""<<std::endl;
3373 v3f pos = findSpawnPos(m_env->getServerMap());
3374 player->setPosition(pos);
3376 // Make sure the player is saved
3377 player->setModified(true);
3379 // Add player to environment
3380 m_env->addPlayer(player);
3383 // Create a new player active object
3384 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3385 getPlayerEffectivePrivs(player->getName()),
3388 /* Clean up old HUD elements from previous sessions */
3391 /* Add object to environment */
3392 m_env->addActiveObject(playersao);
3396 m_script->on_newplayer(playersao);
3402 void dedicated_server_loop(Server &server, bool &kill)
3404 DSTACK(__FUNCTION_NAME);
3406 verbosestream<<"dedicated_server_loop()"<<std::endl;
3408 IntervalLimiter m_profiler_interval;
3412 float steplen = g_settings->getFloat("dedicated_server_step");
3413 // This is kind of a hack but can be done like this
3414 // because server.step() is very light
3416 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3417 sleep_ms((int)(steplen*1000.0));
3419 server.step(steplen);
3421 if(server.getShutdownRequested() || kill)
3423 infostream<<"Dedicated server quitting"<<std::endl;
3425 if(g_settings->getBool("server_announce"))
3426 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3434 float profiler_print_interval =
3435 g_settings->getFloat("profiler_print_interval");
3436 if(profiler_print_interval != 0)
3438 if(m_profiler_interval.step(steplen, profiler_print_interval))
3440 infostream<<"Profiler:"<<std::endl;
3441 g_profiler->print(infostream);
3442 g_profiler->clear();