3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "jthread/jmutexautolock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_game.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_abm.h"
52 #include "content_sao.h"
54 #include "sound.h" // dummySoundManager
55 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "util/thread.h"
62 #include "defaultsettings.h"
63 #include "util/base64.h"
64 #include "util/sha1.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public JThread
81 ServerThread(Server *server):
90 void * ServerThread::Thread()
92 log_register_thread("ServerThread");
94 DSTACK(__FUNCTION_NAME);
95 BEGIN_DEBUG_EXCEPTION_HANDLER
97 m_server->AsyncRunStep(true);
101 porting::setThreadName("ServerThread");
103 while(!StopRequested())
106 //TimeTaker timer("AsyncRunStep() + Receive()");
108 m_server->AsyncRunStep();
113 catch(con::NoIncomingDataException &e)
116 catch(con::PeerNotFoundException &e)
118 infostream<<"Server: PeerNotFoundException"<<std::endl;
120 catch(ClientNotFoundException &e)
123 catch(con::ConnectionBindFailed &e)
125 m_server->setAsyncFatalError(e.what());
129 m_server->setAsyncFatalError(e.what());
133 END_DEBUG_EXCEPTION_HANDLER(errorstream)
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
140 if(pos_exists) *pos_exists = false;
145 if(pos_exists) *pos_exists = true;
150 ServerActiveObject *sao = env->getActiveObject(object);
153 if(pos_exists) *pos_exists = true;
154 return sao->getBasePosition(); }
166 const std::string &path_world,
167 const SubgameSpec &gamespec,
168 bool simple_singleplayer_mode,
171 m_path_world(path_world),
172 m_gamespec(gamespec),
173 m_simple_singleplayer_mode(simple_singleplayer_mode),
174 m_async_fatal_error(""),
183 m_enable_rollback_recording(false),
186 m_itemdef(createItemDefManager()),
187 m_nodedef(createNodeDefManager()),
188 m_craftdef(createCraftDefManager()),
189 m_event(new EventManager()),
191 m_time_of_day_send_timer(0),
194 m_shutdown_requested(false),
195 m_ignore_map_edit_events(false),
196 m_ignore_map_edit_events_peer_id(0),
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 ModConfiguration modconf(m_path_world);
247 m_mods = modconf.getMods();
248 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
249 // complain about mods with unsatisfied dependencies
250 if(!modconf.isConsistent())
252 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
253 it != unsatisfied_mods.end(); ++it)
256 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
257 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
258 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
259 errorstream << " \"" << *dep_it << "\"";
260 errorstream << std::endl;
264 Settings worldmt_settings;
265 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
266 worldmt_settings.readConfigFile(worldmt.c_str());
267 std::vector<std::string> names = worldmt_settings.getNames();
268 std::set<std::string> load_mod_names;
269 for(std::vector<std::string>::iterator it = names.begin();
270 it != names.end(); ++it)
272 std::string name = *it;
273 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
274 load_mod_names.insert(name.substr(9));
276 // complain about mods declared to be loaded, but not found
277 for(std::vector<ModSpec>::iterator it = m_mods.begin();
278 it != m_mods.end(); ++it)
279 load_mod_names.erase((*it).name);
280 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
281 it != unsatisfied_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 if(!load_mod_names.empty())
285 errorstream << "The following mods could not be found:";
286 for(std::set<std::string>::iterator it = load_mod_names.begin();
287 it != load_mod_names.end(); ++it)
288 errorstream << " \"" << (*it) << "\"";
289 errorstream << std::endl;
293 JMutexAutoLock envlock(m_env_mutex);
295 // Load mapgen params from Settings
296 m_emerge->loadMapgenParams();
298 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
299 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
301 // Initialize scripting
302 infostream<<"Server: Initializing Lua"<<std::endl;
304 m_script = new GameScripting(this);
306 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
308 if (!m_script->loadScript(scriptpath))
309 throw ModError("Failed to load and run " + scriptpath);
312 infostream<<"Server: Loading mods: ";
313 for(std::vector<ModSpec>::iterator i = m_mods.begin();
314 i != m_mods.end(); i++){
315 const ModSpec &mod = *i;
316 infostream<<mod.name<<" ";
318 infostream<<std::endl;
319 // Load and run "mod" scripts
320 for(std::vector<ModSpec>::iterator i = m_mods.begin();
321 i != m_mods.end(); i++){
322 const ModSpec &mod = *i;
323 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
324 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
325 <<scriptpath<<"\"]"<<std::endl;
326 bool success = m_script->loadMod(scriptpath, mod.name);
328 errorstream<<"Server: Failed to load and run "
329 <<scriptpath<<std::endl;
330 throw ModError("Failed to load and run "+scriptpath);
334 // Read Textures and calculate sha1 sums
337 // Apply item aliases in the node definition manager
338 m_nodedef->updateAliases(m_itemdef);
340 m_nodedef->setNodeRegistrationStatus(true);
342 // Perform pending node name resolutions
343 m_nodedef->runNodeResolverCallbacks();
345 // Initialize Environment
346 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
348 m_clients.setEnv(m_env);
350 // Initialize mapgens
351 m_emerge->initMapgens();
353 m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
354 if (m_enable_rollback_recording) {
355 // Create rollback manager
356 m_rollback = new RollbackManager(m_path_world, this);
359 // Give environment reference to scripting api
360 m_script->initializeEnvironment(m_env);
362 // Register us to receive map edit events
363 servermap->addEventReceiver(this);
365 // If file exists, load environment metadata
366 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
368 infostream<<"Server: Loading environment metadata"<<std::endl;
372 // Add some test ActiveBlockModifiers to environment
373 add_legacy_abms(m_env, m_nodedef);
375 m_liquid_transform_every = g_settings->getFloat("liquid_update");
380 infostream<<"Server destructing"<<std::endl;
382 // Send shutdown message
383 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
386 JMutexAutoLock envlock(m_env_mutex);
388 // Execute script shutdown hooks
389 m_script->on_shutdown();
391 infostream<<"Server: Saving players"<<std::endl;
392 m_env->saveLoadedPlayers();
394 infostream<<"Server: Saving environment metadata"<<std::endl;
402 // stop all emerge threads before deleting players that may have
403 // requested blocks to be emerged
404 m_emerge->stopThreads();
406 // Delete things in the reverse order of creation
409 // N.B. the EmergeManager should be deleted after the Environment since Map
410 // depends on EmergeManager to write its current params to the map meta
419 // Deinitialize scripting
420 infostream<<"Server: Deinitializing scripting"<<std::endl;
423 // Delete detached inventories
424 for (std::map<std::string, Inventory*>::iterator
425 i = m_detached_inventories.begin();
426 i != m_detached_inventories.end(); i++) {
431 void Server::start(Address bind_addr)
433 DSTACK(__FUNCTION_NAME);
435 m_bind_addr = bind_addr;
437 infostream<<"Starting server on "
438 << bind_addr.serializeString() <<"..."<<std::endl;
440 // Stop thread if already running
443 // Initialize connection
444 m_con.SetTimeoutMs(30);
445 m_con.Serve(bind_addr);
450 // ASCII art for the win!
452 <<" .__ __ __ "<<std::endl
453 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
454 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
455 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
456 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
457 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
458 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
459 actionstream<<"Server for gameid=\""<<m_gamespec.id
460 <<"\" listening on "<<bind_addr.serializeString()<<":"
461 <<bind_addr.getPort() << "."<<std::endl;
466 DSTACK(__FUNCTION_NAME);
468 infostream<<"Server: Stopping and waiting threads"<<std::endl;
470 // Stop threads (set run=false first so both start stopping)
472 //m_emergethread.setRun(false);
474 //m_emergethread.stop();
476 infostream<<"Server: Threads stopped"<<std::endl;
479 void Server::step(float dtime)
481 DSTACK(__FUNCTION_NAME);
486 JMutexAutoLock lock(m_step_dtime_mutex);
487 m_step_dtime += dtime;
489 // Throw if fatal error occurred in thread
490 std::string async_err = m_async_fatal_error.get();
492 throw ServerError(async_err);
496 void Server::AsyncRunStep(bool initial_step)
498 DSTACK(__FUNCTION_NAME);
500 g_profiler->add("Server::AsyncRunStep (num)", 1);
504 JMutexAutoLock lock1(m_step_dtime_mutex);
505 dtime = m_step_dtime;
509 // Send blocks to clients
513 if((dtime < 0.001) && (initial_step == false))
516 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
518 //infostream<<"Server steps "<<dtime<<std::endl;
519 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
522 JMutexAutoLock lock1(m_step_dtime_mutex);
523 m_step_dtime -= dtime;
530 m_uptime.set(m_uptime.get() + dtime);
536 Update time of day and overall game time
538 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
541 Send to clients at constant intervals
544 m_time_of_day_send_timer -= dtime;
545 if(m_time_of_day_send_timer < 0.0) {
546 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
547 u16 time = m_env->getTimeOfDay();
548 float time_speed = g_settings->getFloat("time_speed");
549 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
553 JMutexAutoLock lock(m_env_mutex);
554 // Figure out and report maximum lag to environment
555 float max_lag = m_env->getMaxLagEstimate();
556 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
558 if(dtime > 0.1 && dtime > max_lag * 2.0)
559 infostream<<"Server: Maximum lag peaked to "<<dtime
563 m_env->reportMaxLagEstimate(max_lag);
565 ScopeProfiler sp(g_profiler, "SEnv step");
566 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
570 static const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 JMutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"));
584 /* Transform liquids */
585 m_liquid_transform_timer += dtime;
586 if(m_liquid_transform_timer >= m_liquid_transform_every)
588 m_liquid_transform_timer -= m_liquid_transform_every;
590 JMutexAutoLock lock(m_env_mutex);
592 ScopeProfiler sp(g_profiler, "Server: liquid transform");
594 std::map<v3s16, MapBlock*> modified_blocks;
595 m_env->getMap().transformLiquids(modified_blocks);
600 core::map<v3s16, MapBlock*> lighting_modified_blocks;
601 ServerMap &map = ((ServerMap&)m_env->getMap());
602 map.updateLighting(modified_blocks, lighting_modified_blocks);
604 // Add blocks modified by lighting to modified_blocks
605 for(core::map<v3s16, MapBlock*>::Iterator
606 i = lighting_modified_blocks.getIterator();
607 i.atEnd() == false; i++)
609 MapBlock *block = i.getNode()->getValue();
610 modified_blocks.insert(block->getPos(), block);
614 Set the modified blocks unsent for all the clients
616 if(!modified_blocks.empty())
618 SetBlocksNotSent(modified_blocks);
621 m_clients.step(dtime);
623 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
625 // send masterserver announce
627 float &counter = m_masterserver_timer;
628 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
629 g_settings->getBool("server_announce"))
631 ServerList::sendAnnounce(counter ? "update" : "start",
632 m_bind_addr.getPort(),
633 m_clients.getPlayerNames(),
635 m_env->getGameTime(),
638 m_emerge->params.mg_name,
647 Check added and deleted active objects
650 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
651 JMutexAutoLock envlock(m_env_mutex);
654 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
655 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
657 // Radius inside which objects are active
658 s16 radius = g_settings->getS16("active_object_send_range_blocks");
659 s16 player_radius = g_settings->getS16("player_transfer_distance");
661 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
662 !g_settings->getBool("unlimited_player_transfer_distance"))
663 player_radius = radius;
665 radius *= MAP_BLOCKSIZE;
666 player_radius *= MAP_BLOCKSIZE;
668 for(std::map<u16, RemoteClient*>::iterator
670 i != clients.end(); ++i)
672 RemoteClient *client = i->second;
674 // If definitions and textures have not been sent, don't
675 // send objects either
676 if (client->getState() < CS_DefinitionsSent)
679 Player *player = m_env->getPlayer(client->peer_id);
682 // This can happen if the client timeouts somehow
683 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
685 <<" has no associated player"<<std::endl;*/
688 v3s16 pos = floatToInt(player->getPosition(), BS);
690 std::set<u16> removed_objects;
691 std::set<u16> added_objects;
692 m_env->getRemovedActiveObjects(pos, radius, player_radius,
693 client->m_known_objects, removed_objects);
694 m_env->getAddedActiveObjects(pos, radius, player_radius,
695 client->m_known_objects, added_objects);
697 // Ignore if nothing happened
698 if(removed_objects.empty() && added_objects.empty())
700 //infostream<<"active objects: none changed"<<std::endl;
704 std::string data_buffer;
708 // Handle removed objects
709 writeU16((u8*)buf, removed_objects.size());
710 data_buffer.append(buf, 2);
711 for(std::set<u16>::iterator
712 i = removed_objects.begin();
713 i != removed_objects.end(); ++i)
717 ServerActiveObject* obj = m_env->getActiveObject(id);
719 // Add to data buffer for sending
720 writeU16((u8*)buf, id);
721 data_buffer.append(buf, 2);
723 // Remove from known objects
724 client->m_known_objects.erase(id);
726 if(obj && obj->m_known_by_count > 0)
727 obj->m_known_by_count--;
730 // Handle added objects
731 writeU16((u8*)buf, added_objects.size());
732 data_buffer.append(buf, 2);
733 for(std::set<u16>::iterator
734 i = added_objects.begin();
735 i != added_objects.end(); ++i)
739 ServerActiveObject* obj = m_env->getActiveObject(id);
742 u8 type = ACTIVEOBJECT_TYPE_INVALID;
744 infostream<<"WARNING: "<<__FUNCTION_NAME
745 <<": NULL object"<<std::endl;
747 type = obj->getSendType();
749 // Add to data buffer for sending
750 writeU16((u8*)buf, id);
751 data_buffer.append(buf, 2);
752 writeU8((u8*)buf, type);
753 data_buffer.append(buf, 1);
756 data_buffer.append(serializeLongString(
757 obj->getClientInitializationData(client->net_proto_version)));
759 data_buffer.append(serializeLongString(""));
761 // Add to known objects
762 client->m_known_objects.insert(id);
765 obj->m_known_by_count++;
768 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
769 pkt->putRawString(data_buffer.c_str(), data_buffer.size());
772 verbosestream << "Server: Sent object remove/add: "
773 << removed_objects.size() << " removed, "
774 << added_objects.size() << " added, "
775 << "packet size is " << pkt->getSize() << std::endl;
786 JMutexAutoLock envlock(m_env_mutex);
787 ScopeProfiler sp(g_profiler, "Server: sending object messages");
790 // Value = data sent by object
791 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
793 // Get active object messages from environment
795 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
799 std::vector<ActiveObjectMessage>* message_list = NULL;
800 std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
801 n = buffered_messages.find(aom.id);
802 if (n == buffered_messages.end()) {
803 message_list = new std::vector<ActiveObjectMessage>;
804 buffered_messages[aom.id] = message_list;
807 message_list = n->second;
809 message_list->push_back(aom);
813 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
814 // Route data to every client
815 for (std::map<u16, RemoteClient*>::iterator
817 i != clients.end(); ++i) {
818 RemoteClient *client = i->second;
819 std::string reliable_data;
820 std::string unreliable_data;
821 // Go through all objects in message buffer
822 for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
823 j = buffered_messages.begin();
824 j != buffered_messages.end(); ++j) {
825 // If object is not known by client, skip it
827 if (client->m_known_objects.find(id) == client->m_known_objects.end())
830 // Get message list of object
831 std::vector<ActiveObjectMessage>* list = j->second;
832 // Go through every message
833 for (std::vector<ActiveObjectMessage>::iterator
834 k = list->begin(); k != list->end(); ++k) {
835 // Compose the full new data with header
836 ActiveObjectMessage aom = *k;
837 std::string new_data;
840 writeU16((u8*)&buf[0], aom.id);
841 new_data.append(buf, 2);
843 new_data += serializeString(aom.datastring);
844 // Add data to buffer
846 reliable_data += new_data;
848 unreliable_data += new_data;
852 reliable_data and unreliable_data are now ready.
855 if(reliable_data.size() > 0) {
856 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
859 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
863 if(unreliable_data.size() > 0) {
864 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
867 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
873 // Clear buffered_messages
874 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
875 i = buffered_messages.begin();
876 i != buffered_messages.end(); ++i) {
882 Send queued-for-sending map edit events.
885 // We will be accessing the environment
886 JMutexAutoLock lock(m_env_mutex);
888 // Don't send too many at a time
891 // Single change sending is disabled if queue size is not small
892 bool disable_single_change_sending = false;
893 if(m_unsent_map_edit_queue.size() >= 4)
894 disable_single_change_sending = true;
896 int event_count = m_unsent_map_edit_queue.size();
898 // We'll log the amount of each
901 while(m_unsent_map_edit_queue.size() != 0)
903 MapEditEvent* event = m_unsent_map_edit_queue.front();
904 m_unsent_map_edit_queue.pop();
906 // Players far away from the change are stored here.
907 // Instead of sending the changes, MapBlocks are set not sent
909 std::vector<u16> far_players;
911 switch (event->type) {
914 prof.add("MEET_ADDNODE", 1);
915 sendAddNode(event->p, event->n, event->already_known_by_peer,
916 &far_players, disable_single_change_sending ? 5 : 30,
917 event->type == MEET_ADDNODE);
919 case MEET_REMOVENODE:
920 prof.add("MEET_REMOVENODE", 1);
921 sendRemoveNode(event->p, event->already_known_by_peer,
922 &far_players, disable_single_change_sending ? 5 : 30);
924 case MEET_BLOCK_NODE_METADATA_CHANGED:
925 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
926 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
927 setBlockNotSent(event->p);
930 infostream << "Server: MEET_OTHER" << std::endl;
931 prof.add("MEET_OTHER", 1);
932 for(std::set<v3s16>::iterator
933 i = event->modified_blocks.begin();
934 i != event->modified_blocks.end(); ++i) {
939 prof.add("unknown", 1);
940 infostream << "WARNING: Server: Unknown MapEditEvent "
941 << ((u32)event->type) << std::endl;
946 Set blocks not sent to far players
948 if(!far_players.empty()) {
949 // Convert list format to that wanted by SetBlocksNotSent
950 std::map<v3s16, MapBlock*> modified_blocks2;
951 for(std::set<v3s16>::iterator
952 i = event->modified_blocks.begin();
953 i != event->modified_blocks.end(); ++i) {
954 modified_blocks2[*i] =
955 m_env->getMap().getBlockNoCreateNoEx(*i);
958 // Set blocks not sent
959 for(std::vector<u16>::iterator
960 i = far_players.begin();
961 i != far_players.end(); ++i) {
962 if(RemoteClient *client = getClient(*i))
963 client->SetBlocksNotSent(modified_blocks2);
969 /*// Don't send too many at a time
971 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
975 if(event_count >= 5){
976 infostream<<"Server: MapEditEvents:"<<std::endl;
977 prof.print(infostream);
978 } else if(event_count != 0){
979 verbosestream<<"Server: MapEditEvents:"<<std::endl;
980 prof.print(verbosestream);
986 Trigger emergethread (it somehow gets to a non-triggered but
987 bysy state sometimes)
990 float &counter = m_emergethread_trigger_timer;
996 m_emerge->startThreads();
1000 // Save map, players and auth stuff
1002 float &counter = m_savemap_timer;
1004 if(counter >= g_settings->getFloat("server_map_save_interval"))
1007 JMutexAutoLock lock(m_env_mutex);
1009 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1012 if (m_banmanager->isModified()) {
1013 m_banmanager->save();
1016 // Save changed parts of map
1017 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1020 m_env->saveLoadedPlayers();
1022 // Save environment metadata
1028 void Server::Receive()
1030 DSTACK(__FUNCTION_NAME);
1031 SharedBuffer<u8> data;
1035 datasize = m_con.Receive(peer_id,data);
1036 ProcessData(*data, datasize, peer_id);
1038 catch(con::InvalidIncomingDataException &e) {
1039 infostream<<"Server::Receive(): "
1040 "InvalidIncomingDataException: what()="
1041 <<e.what()<<std::endl;
1043 catch(SerializationError &e) {
1044 infostream<<"Server::Receive(): "
1045 "SerializationError: what()="
1046 <<e.what()<<std::endl;
1048 catch(ClientStateError &e) {
1049 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1050 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1051 L"Try reconnecting or updating your client");
1053 catch(con::PeerNotFoundException &e) {
1058 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1060 std::string playername = "";
1061 PlayerSAO *playersao = NULL;
1064 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1065 if (client != NULL) {
1066 playername = client->getName();
1067 playersao = emergePlayer(playername.c_str(), peer_id);
1069 } catch (std::exception &e) {
1075 RemotePlayer *player =
1076 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1078 // If failed, cancel
1079 if((playersao == NULL) || (player == NULL)) {
1080 if(player && player->peer_id != 0) {
1081 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1082 <<" (player allocated to an another client)"<<std::endl;
1083 DenyAccess(peer_id, L"Another client is connected with this "
1084 L"name. If your client closed unexpectedly, try again in "
1087 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1089 DenyAccess(peer_id, L"Could not allocate player.");
1095 Send complete position information
1097 SendMovePlayer(peer_id);
1100 SendPlayerPrivileges(peer_id);
1102 // Send inventory formspec
1103 SendPlayerInventoryFormspec(peer_id);
1106 SendInventory(playersao);
1109 if(g_settings->getBool("enable_damage"))
1110 SendPlayerHP(peer_id);
1113 SendPlayerBreath(peer_id);
1115 // Show death screen if necessary
1117 SendDeathscreen(peer_id, false, v3f(0,0,0));
1119 // Note things in chat if not in simple singleplayer mode
1120 if(!m_simple_singleplayer_mode) {
1121 // Send information about server to player in chat
1122 SendChatMessage(peer_id, getStatusString());
1124 // Send information about joining in chat
1126 std::wstring name = L"unknown";
1127 Player *player = m_env->getPlayer(peer_id);
1129 name = narrow_to_wide(player->getName());
1131 std::wstring message;
1134 message += L" joined the game.";
1135 SendChatMessage(PEER_ID_INEXISTENT,message);
1138 Address addr = getPeerAddress(player->peer_id);
1139 std::string ip_str = addr.serializeString();
1140 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1145 std::vector<std::string> names = m_clients.getPlayerNames();
1147 actionstream<<player->getName() <<" joins game. List of players: ";
1149 for (std::vector<std::string>::iterator i = names.begin();
1150 i != names.end(); i++) {
1151 actionstream << *i << " ";
1154 actionstream << player->getName() <<std::endl;
1159 inline void Server::handleCommand(NetworkPacket* pkt)
1161 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1162 (this->*opHandle.handler)(pkt);
1165 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1167 DSTACK(__FUNCTION_NAME);
1168 // Environment is locked first.
1169 JMutexAutoLock envlock(m_env_mutex);
1171 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1174 Address address = getPeerAddress(peer_id);
1175 std::string addr_s = address.serializeString();
1177 if(m_banmanager->isIpBanned(addr_s)) {
1178 std::string ban_name = m_banmanager->getBanName(addr_s);
1179 infostream << "Server: A banned client tried to connect from "
1180 << addr_s << "; banned name was "
1181 << ban_name << std::endl;
1182 // This actually doesn't seem to transfer to the client
1183 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1184 + narrow_to_wide(ban_name));
1188 catch(con::PeerNotFoundException &e) {
1190 * no peer for this packet found
1191 * most common reason is peer timeout, e.g. peer didn't
1192 * respond for some time, your server was overloaded or
1195 infostream << "Server::ProcessData(): Cancelling: peer "
1196 << peer_id << " not found" << std::endl;
1204 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1206 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1208 // Command must be handled into ToServerCommandHandler
1209 if (command >= TOSERVER_NUM_MSG_TYPES) {
1210 infostream << "Server: Ignoring unknown command "
1211 << command << std::endl;
1214 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1220 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1222 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1223 errorstream << "Server::ProcessData(): Cancelling: Peer"
1224 " serialization format invalid or not initialized."
1225 " Skipping incoming command=" << command << std::endl;
1231 /* Handle commands related to client startup */
1232 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1238 if (m_clients.getClientState(peer_id) < CS_Active) {
1239 if (command == TOSERVER_PLAYERPOS) return;
1241 errorstream << "Got packet command: " << command << " for peer id "
1242 << peer_id << " but client isn't active yet. Dropping packet "
1253 catch(SendFailedException &e) {
1254 errorstream << "Server::ProcessData(): SendFailedException: "
1255 << "what=" << e.what()
1260 void Server::setTimeOfDay(u32 time)
1262 m_env->setTimeOfDay(time);
1263 m_time_of_day_send_timer = 0;
1266 void Server::onMapEditEvent(MapEditEvent *event)
1268 if(m_ignore_map_edit_events)
1270 if(m_ignore_map_edit_events_area.contains(event->getArea()))
1272 MapEditEvent *e = event->clone();
1273 m_unsent_map_edit_queue.push(e);
1276 Inventory* Server::getInventory(const InventoryLocation &loc)
1279 case InventoryLocation::UNDEFINED:
1280 case InventoryLocation::CURRENT_PLAYER:
1282 case InventoryLocation::PLAYER:
1284 Player *player = m_env->getPlayer(loc.name.c_str());
1287 PlayerSAO *playersao = player->getPlayerSAO();
1290 return playersao->getInventory();
1293 case InventoryLocation::NODEMETA:
1295 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1298 return meta->getInventory();
1301 case InventoryLocation::DETACHED:
1303 if(m_detached_inventories.count(loc.name) == 0)
1305 return m_detached_inventories[loc.name];
1314 void Server::setInventoryModified(const InventoryLocation &loc)
1317 case InventoryLocation::UNDEFINED:
1319 case InventoryLocation::PLAYER:
1321 Player *player = m_env->getPlayer(loc.name.c_str());
1324 PlayerSAO *playersao = player->getPlayerSAO();
1328 SendInventory(playersao);
1331 case InventoryLocation::NODEMETA:
1333 v3s16 blockpos = getNodeBlockPos(loc.p);
1335 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1337 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1339 setBlockNotSent(blockpos);
1342 case InventoryLocation::DETACHED:
1344 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1353 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1355 std::vector<u16> clients = m_clients.getClientIDs();
1357 // Set the modified blocks unsent for all the clients
1358 for (std::vector<u16>::iterator i = clients.begin();
1359 i != clients.end(); ++i) {
1360 if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1361 client->SetBlocksNotSent(block);
1366 void Server::peerAdded(con::Peer *peer)
1368 DSTACK(__FUNCTION_NAME);
1369 verbosestream<<"Server::peerAdded(): peer->id="
1370 <<peer->id<<std::endl;
1373 c.type = con::PEER_ADDED;
1374 c.peer_id = peer->id;
1376 m_peer_change_queue.push(c);
1379 void Server::deletingPeer(con::Peer *peer, bool timeout)
1381 DSTACK(__FUNCTION_NAME);
1382 verbosestream<<"Server::deletingPeer(): peer->id="
1383 <<peer->id<<", timeout="<<timeout<<std::endl;
1385 m_clients.event(peer->id, CSE_Disconnect);
1387 c.type = con::PEER_REMOVED;
1388 c.peer_id = peer->id;
1389 c.timeout = timeout;
1390 m_peer_change_queue.push(c);
1393 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1395 *retval = m_con.getPeerStat(peer_id,type);
1396 if (*retval == -1) return false;
1400 bool Server::getClientInfo(
1409 std::string* vers_string
1412 *state = m_clients.getClientState(peer_id);
1414 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1416 if (client == NULL) {
1421 *uptime = client->uptime();
1422 *ser_vers = client->serialization_version;
1423 *prot_vers = client->net_proto_version;
1425 *major = client->getMajor();
1426 *minor = client->getMinor();
1427 *patch = client->getPatch();
1428 *vers_string = client->getPatch();
1435 void Server::handlePeerChanges()
1437 while(m_peer_change_queue.size() > 0)
1439 con::PeerChange c = m_peer_change_queue.front();
1440 m_peer_change_queue.pop();
1442 verbosestream<<"Server: Handling peer change: "
1443 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1448 case con::PEER_ADDED:
1449 m_clients.CreateClient(c.peer_id);
1452 case con::PEER_REMOVED:
1453 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1457 assert("Invalid peer change event received!" == 0);
1463 void Server::Send(NetworkPacket* pkt)
1465 m_clients.send(pkt->getPeerId(),
1466 clientCommandFactoryTable[pkt->getCommand()].channel,
1468 clientCommandFactoryTable[pkt->getCommand()].reliable);
1471 void Server::SendMovement(u16 peer_id)
1473 DSTACK(__FUNCTION_NAME);
1474 std::ostringstream os(std::ios_base::binary);
1476 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1478 *pkt << g_settings->getFloat("movement_acceleration_default");
1479 *pkt << g_settings->getFloat("movement_acceleration_air");
1480 *pkt << g_settings->getFloat("movement_acceleration_fast");
1481 *pkt << g_settings->getFloat("movement_speed_walk");
1482 *pkt << g_settings->getFloat("movement_speed_crouch");
1483 *pkt << g_settings->getFloat("movement_speed_fast");
1484 *pkt << g_settings->getFloat("movement_speed_climb");
1485 *pkt << g_settings->getFloat("movement_speed_jump");
1486 *pkt << g_settings->getFloat("movement_liquid_fluidity");
1487 *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1488 *pkt << g_settings->getFloat("movement_liquid_sink");
1489 *pkt << g_settings->getFloat("movement_gravity");
1494 void Server::SendHP(u16 peer_id, u8 hp)
1496 DSTACK(__FUNCTION_NAME);
1498 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1503 void Server::SendBreath(u16 peer_id, u16 breath)
1505 DSTACK(__FUNCTION_NAME);
1507 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1508 *pkt << (u16) breath;
1512 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1514 DSTACK(__FUNCTION_NAME);
1516 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1521 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1522 v3f camera_point_target)
1524 DSTACK(__FUNCTION_NAME);
1526 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1527 *pkt << set_camera_point_target << camera_point_target;
1531 void Server::SendItemDef(u16 peer_id,
1532 IItemDefManager *itemdef, u16 protocol_version)
1534 DSTACK(__FUNCTION_NAME);
1536 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1540 u32 length of the next item
1541 zlib-compressed serialized ItemDefManager
1543 std::ostringstream tmp_os(std::ios::binary);
1544 itemdef->serialize(tmp_os, protocol_version);
1545 std::ostringstream tmp_os2(std::ios::binary);
1546 compressZlib(tmp_os.str(), tmp_os2);
1547 pkt->putLongString(tmp_os2.str());
1550 verbosestream << "Server: Sending item definitions to id(" << peer_id
1551 << "): size=" << pkt->getSize() << std::endl;
1556 void Server::SendNodeDef(u16 peer_id,
1557 INodeDefManager *nodedef, u16 protocol_version)
1559 DSTACK(__FUNCTION_NAME);
1561 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1565 u32 length of the next item
1566 zlib-compressed serialized NodeDefManager
1568 std::ostringstream tmp_os(std::ios::binary);
1569 nodedef->serialize(tmp_os, protocol_version);
1570 std::ostringstream tmp_os2(std::ios::binary);
1571 compressZlib(tmp_os.str(), tmp_os2);
1573 pkt->putLongString(tmp_os2.str());
1576 verbosestream << "Server: Sending node definitions to id(" << peer_id
1577 << "): size=" << pkt->getSize() << std::endl;
1583 Non-static send methods
1586 void Server::SendInventory(PlayerSAO* playerSAO)
1588 DSTACK(__FUNCTION_NAME);
1590 UpdateCrafting(playerSAO->getPlayer());
1596 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1597 playerSAO->getPeerID());
1599 std::ostringstream os;
1600 playerSAO->getInventory()->serialize(os);
1602 std::string s = os.str();
1604 pkt->putRawString(s.c_str(), s.size());
1608 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1610 DSTACK(__FUNCTION_NAME);
1612 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1615 if (peer_id != PEER_ID_INEXISTENT) {
1619 m_clients.sendToAll(0,pkt,true);
1623 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1624 const std::string &formname)
1626 DSTACK(__FUNCTION_NAME);
1628 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1630 pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1636 // Spawns a particle on peer with peer_id
1637 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1638 float expirationtime, float size, bool collisiondetection,
1639 bool vertical, std::string texture)
1641 DSTACK(__FUNCTION_NAME);
1643 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1645 *pkt << pos << velocity << acceleration << expirationtime
1646 << size << collisiondetection;
1647 pkt->putLongString(texture);
1650 if (peer_id != PEER_ID_INEXISTENT) {
1654 m_clients.sendToAll(0,pkt,true);
1658 // Adds a ParticleSpawner on peer with peer_id
1659 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1660 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1661 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1663 DSTACK(__FUNCTION_NAME);
1665 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1667 *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1668 << minacc << maxacc << minexptime << maxexptime << minsize
1669 << maxsize << collisiondetection;
1671 pkt->putLongString(texture);
1673 *pkt << id << vertical;
1675 if (peer_id != PEER_ID_INEXISTENT) {
1679 m_clients.sendToAll(0, pkt, true);
1683 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1685 DSTACK(__FUNCTION_NAME);
1687 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1689 // Ugly error in this packet
1692 if (peer_id != PEER_ID_INEXISTENT) {
1696 m_clients.sendToAll(0, pkt, true);
1701 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1703 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1705 *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1706 << form->text << form->number << form->item << form->dir
1707 << form->align << form->offset << form->world_pos << form->size;
1712 void Server::SendHUDRemove(u16 peer_id, u32 id)
1714 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1719 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1721 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1722 *pkt << id << (u8) stat;
1726 case HUD_STAT_SCALE:
1727 case HUD_STAT_ALIGN:
1728 case HUD_STAT_OFFSET:
1729 *pkt << *(v2f *) value;
1733 *pkt << *(std::string *) value;
1735 case HUD_STAT_WORLD_POS:
1736 *pkt << *(v3f *) value;
1739 *pkt << *(v2s32 *) value;
1741 case HUD_STAT_NUMBER:
1745 *pkt << *(u32 *) value;
1752 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1754 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1756 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1758 *pkt << flags << mask;
1763 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1765 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1766 *pkt << param << value;
1770 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1771 const std::string &type, const std::vector<std::string> ¶ms)
1773 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1774 *pkt << bgcolor << type << (u16) params.size();
1776 for(size_t i=0; i<params.size(); i++)
1782 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1785 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1788 *pkt << do_override << (u16) (ratio * 65535);
1793 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1795 DSTACK(__FUNCTION_NAME);
1797 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1798 *pkt << time << time_speed;
1800 if (peer_id == PEER_ID_INEXISTENT) {
1801 m_clients.sendToAll(0, pkt, true);
1808 void Server::SendPlayerHP(u16 peer_id)
1810 DSTACK(__FUNCTION_NAME);
1811 PlayerSAO *playersao = getPlayerSAO(peer_id);
1813 SendHP(peer_id, playersao->getHP());
1814 m_script->player_event(playersao,"health_changed");
1816 // Send to other clients
1817 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1818 ActiveObjectMessage aom(playersao->getId(), true, str);
1819 playersao->m_messages_out.push(aom);
1822 void Server::SendPlayerBreath(u16 peer_id)
1824 DSTACK(__FUNCTION_NAME);
1825 PlayerSAO *playersao = getPlayerSAO(peer_id);
1828 m_script->player_event(playersao, "breath_changed");
1829 SendBreath(peer_id, playersao->getBreath());
1832 void Server::SendMovePlayer(u16 peer_id)
1834 DSTACK(__FUNCTION_NAME);
1835 Player *player = m_env->getPlayer(peer_id);
1838 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1839 *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1842 v3f pos = player->getPosition();
1843 f32 pitch = player->getPitch();
1844 f32 yaw = player->getYaw();
1845 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1846 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1855 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1857 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1860 *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1861 << animation_frames[3] << animation_speed;
1866 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1868 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1869 *pkt << first << third;
1872 void Server::SendPlayerPrivileges(u16 peer_id)
1874 Player *player = m_env->getPlayer(peer_id);
1876 if(player->peer_id == PEER_ID_INEXISTENT)
1879 std::set<std::string> privs;
1880 m_script->getAuth(player->getName(), NULL, &privs);
1882 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1883 *pkt << (u16) privs.size();
1885 for(std::set<std::string>::const_iterator i = privs.begin();
1886 i != privs.end(); i++) {
1893 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1895 Player *player = m_env->getPlayer(peer_id);
1897 if(player->peer_id == PEER_ID_INEXISTENT)
1900 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1901 pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1905 s32 Server::playSound(const SimpleSoundSpec &spec,
1906 const ServerSoundParams ¶ms)
1908 // Find out initial position of sound
1909 bool pos_exists = false;
1910 v3f pos = params.getPos(m_env, &pos_exists);
1911 // If position is not found while it should be, cancel sound
1912 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1915 // Filter destination clients
1916 std::vector<u16> dst_clients;
1917 if(params.to_player != "")
1919 Player *player = m_env->getPlayer(params.to_player.c_str());
1921 infostream<<"Server::playSound: Player \""<<params.to_player
1922 <<"\" not found"<<std::endl;
1925 if(player->peer_id == PEER_ID_INEXISTENT){
1926 infostream<<"Server::playSound: Player \""<<params.to_player
1927 <<"\" not connected"<<std::endl;
1930 dst_clients.push_back(player->peer_id);
1933 std::vector<u16> clients = m_clients.getClientIDs();
1935 for(std::vector<u16>::iterator
1936 i = clients.begin(); i != clients.end(); ++i) {
1937 Player *player = m_env->getPlayer(*i);
1942 if(player->getPosition().getDistanceFrom(pos) >
1943 params.max_hear_distance)
1946 dst_clients.push_back(*i);
1950 if(dst_clients.empty())
1954 s32 id = m_next_sound_id++;
1955 // The sound will exist as a reference in m_playing_sounds
1956 m_playing_sounds[id] = ServerPlayingSound();
1957 ServerPlayingSound &psound = m_playing_sounds[id];
1958 psound.params = params;
1960 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1961 *pkt << id << spec.name << (float) (spec.gain * params.gain)
1962 << (u8) params.type << pos << params.object << params.loop;
1964 for(std::vector<u16>::iterator i = dst_clients.begin();
1965 i != dst_clients.end(); i++) {
1966 psound.clients.insert(*i);
1967 m_clients.send(*i, 0, pkt, true, false);
1972 void Server::stopSound(s32 handle)
1974 // Get sound reference
1975 std::map<s32, ServerPlayingSound>::iterator i =
1976 m_playing_sounds.find(handle);
1977 if(i == m_playing_sounds.end())
1979 ServerPlayingSound &psound = i->second;
1981 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
1984 for(std::set<u16>::iterator i = psound.clients.begin();
1985 i != psound.clients.end(); i++) {
1987 m_clients.send(*i, 0, pkt, true, false);
1990 // Remove sound reference
1991 m_playing_sounds.erase(i);
1994 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1995 std::vector<u16> *far_players, float far_d_nodes)
1997 float maxd = far_d_nodes*BS;
1998 v3f p_f = intToFloat(p, BS);
2000 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2003 std::vector<u16> clients = m_clients.getClientIDs();
2004 for(std::vector<u16>::iterator i = clients.begin();
2005 i != clients.end(); ++i) {
2008 if(Player *player = m_env->getPlayer(*i)) {
2009 // If player is far away, only set modified blocks not sent
2010 v3f player_pos = player->getPosition();
2011 if(player_pos.getDistanceFrom(p_f) > maxd) {
2012 far_players->push_back(*i);
2019 m_clients.send(*i, 0, pkt, true, false);
2021 // This loop needs the deletion of the packet here
2025 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2026 std::vector<u16> *far_players, float far_d_nodes,
2027 bool remove_metadata)
2029 float maxd = far_d_nodes*BS;
2030 v3f p_f = intToFloat(p, BS);
2032 std::vector<u16> clients = m_clients.getClientIDs();
2033 for(std::vector<u16>::iterator i = clients.begin();
2034 i != clients.end(); ++i) {
2038 if(Player *player = m_env->getPlayer(*i)) {
2039 // If player is far away, only set modified blocks not sent
2040 v3f player_pos = player->getPosition();
2041 if(player_pos.getDistanceFrom(p_f) > maxd) {
2042 far_players->push_back(*i);
2048 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2050 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2052 *pkt << p << n.param0 << n.param1 << n.param2
2053 << (u8) (remove_metadata ? 0 : 1);
2055 if (!remove_metadata) {
2056 if (client->net_proto_version <= 21) {
2057 // Old clients always clear metadata; fix it
2058 // by sending the full block again.
2059 client->SetBlockNotSent(p);
2066 if (pkt->getSize() > 0)
2067 m_clients.send(*i, 0, pkt, true);
2071 void Server::setBlockNotSent(v3s16 p)
2073 std::vector<u16> clients = m_clients.getClientIDs();
2075 for(std::vector<u16>::iterator i = clients.begin();
2076 i != clients.end(); ++i) {
2077 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2078 client->SetBlockNotSent(p);
2083 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2085 DSTACK(__FUNCTION_NAME);
2087 v3s16 p = block->getPos();
2090 Create a packet with the block in the right format
2093 std::ostringstream os(std::ios_base::binary);
2094 block->serialize(os, ver, false);
2095 block->serializeNetworkSpecific(os, net_proto_version);
2096 std::string s = os.str();
2098 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2099 2 + 2 + 2 + 2 + s.size(), peer_id);
2102 pkt->putRawString(s.c_str(), s.size());
2106 void Server::SendBlocks(float dtime)
2108 DSTACK(__FUNCTION_NAME);
2110 JMutexAutoLock envlock(m_env_mutex);
2111 //TODO check if one big lock could be faster then multiple small ones
2113 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2115 std::vector<PrioritySortedBlockTransfer> queue;
2117 s32 total_sending = 0;
2120 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2122 std::vector<u16> clients = m_clients.getClientIDs();
2125 for(std::vector<u16>::iterator i = clients.begin();
2126 i != clients.end(); ++i) {
2127 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2132 total_sending += client->SendingCount();
2133 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2139 // Lowest priority number comes first.
2140 // Lowest is most important.
2141 std::sort(queue.begin(), queue.end());
2144 for(u32 i=0; i<queue.size(); i++)
2146 //TODO: Calculate limit dynamically
2147 if(total_sending >= g_settings->getS32
2148 ("max_simultaneous_block_sends_server_total"))
2151 PrioritySortedBlockTransfer q = queue[i];
2153 MapBlock *block = NULL;
2156 block = m_env->getMap().getBlockNoCreate(q.pos);
2158 catch(InvalidPositionException &e)
2163 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2168 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2170 client->SentBlock(q.pos);
2176 void Server::fillMediaCache()
2178 DSTACK(__FUNCTION_NAME);
2180 infostream<<"Server: Calculating media file checksums"<<std::endl;
2182 // Collect all media file paths
2183 std::vector<std::string> paths;
2184 for(std::vector<ModSpec>::iterator i = m_mods.begin();
2185 i != m_mods.end(); i++) {
2186 const ModSpec &mod = *i;
2187 paths.push_back(mod.path + DIR_DELIM + "textures");
2188 paths.push_back(mod.path + DIR_DELIM + "sounds");
2189 paths.push_back(mod.path + DIR_DELIM + "media");
2190 paths.push_back(mod.path + DIR_DELIM + "models");
2192 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2194 // Collect media file information from paths into cache
2195 for(std::vector<std::string>::iterator i = paths.begin();
2196 i != paths.end(); i++) {
2197 std::string mediapath = *i;
2198 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2199 for (u32 j = 0; j < dirlist.size(); j++) {
2200 if (dirlist[j].dir) // Ignode dirs
2202 std::string filename = dirlist[j].name;
2203 // If name contains illegal characters, ignore the file
2204 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2205 infostream<<"Server: ignoring illegal file name: \""
2206 << filename << "\"" << std::endl;
2209 // If name is not in a supported format, ignore it
2210 const char *supported_ext[] = {
2211 ".png", ".jpg", ".bmp", ".tga",
2212 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2214 ".x", ".b3d", ".md2", ".obj",
2217 if (removeStringEnd(filename, supported_ext) == ""){
2218 infostream << "Server: ignoring unsupported file extension: \""
2219 << filename << "\"" << std::endl;
2222 // Ok, attempt to load the file and add to cache
2223 std::string filepath = mediapath + DIR_DELIM + filename;
2225 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2227 errorstream << "Server::fillMediaCache(): Could not open \""
2228 << filename << "\" for reading" << std::endl;
2231 std::ostringstream tmp_os(std::ios_base::binary);
2235 fis.read(buf, 1024);
2236 std::streamsize len = fis.gcount();
2237 tmp_os.write(buf, len);
2246 errorstream<<"Server::fillMediaCache(): Failed to read \""
2247 << filename << "\"" << std::endl;
2250 if(tmp_os.str().length() == 0) {
2251 errorstream << "Server::fillMediaCache(): Empty file \""
2252 << filepath << "\"" << std::endl;
2257 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2259 unsigned char *digest = sha1.getDigest();
2260 std::string sha1_base64 = base64_encode(digest, 20);
2261 std::string sha1_hex = hex_encode((char*)digest, 20);
2265 m_media[filename] = MediaInfo(filepath, sha1_base64);
2266 verbosestream << "Server: " << sha1_hex << " is " << filename
2272 struct SendableMediaAnnouncement
2275 std::string sha1_digest;
2277 SendableMediaAnnouncement(const std::string &name_="",
2278 const std::string &sha1_digest_=""):
2280 sha1_digest(sha1_digest_)
2284 void Server::sendMediaAnnouncement(u16 peer_id)
2286 DSTACK(__FUNCTION_NAME);
2288 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2291 std::vector<SendableMediaAnnouncement> file_announcements;
2293 for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2294 i != m_media.end(); i++){
2296 file_announcements.push_back(
2297 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2301 std::ostringstream os(std::ios_base::binary);
2308 u16 length of sha1_digest
2313 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2314 *pkt << (u16) file_announcements.size();
2316 for (std::vector<SendableMediaAnnouncement>::iterator
2317 j = file_announcements.begin();
2318 j != file_announcements.end(); ++j) {
2319 *pkt << j->name << j->sha1_digest;
2322 *pkt << g_settings->get("remote_media");
2326 struct SendableMedia
2332 SendableMedia(const std::string &name_="", const std::string &path_="",
2333 const std::string &data_=""):
2340 void Server::sendRequestedMedia(u16 peer_id,
2341 const std::vector<std::string> &tosend)
2343 DSTACK(__FUNCTION_NAME);
2345 verbosestream<<"Server::sendRequestedMedia(): "
2346 <<"Sending files to client"<<std::endl;
2350 // Put 5kB in one bunch (this is not accurate)
2351 u32 bytes_per_bunch = 5000;
2353 std::vector< std::vector<SendableMedia> > file_bunches;
2354 file_bunches.push_back(std::vector<SendableMedia>());
2356 u32 file_size_bunch_total = 0;
2358 for(std::vector<std::string>::const_iterator i = tosend.begin();
2359 i != tosend.end(); ++i) {
2360 const std::string &name = *i;
2362 if(m_media.find(name) == m_media.end()) {
2363 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2364 <<"unknown file \""<<(name)<<"\""<<std::endl;
2368 //TODO get path + name
2369 std::string tpath = m_media[name].path;
2372 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2373 if(fis.good() == false){
2374 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2375 <<tpath<<"\" for reading"<<std::endl;
2378 std::ostringstream tmp_os(std::ios_base::binary);
2382 fis.read(buf, 1024);
2383 std::streamsize len = fis.gcount();
2384 tmp_os.write(buf, len);
2385 file_size_bunch_total += len;
2394 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2395 <<name<<"\""<<std::endl;
2398 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2399 <<tname<<"\""<<std::endl;*/
2401 file_bunches[file_bunches.size()-1].push_back(
2402 SendableMedia(name, tpath, tmp_os.str()));
2404 // Start next bunch if got enough data
2405 if(file_size_bunch_total >= bytes_per_bunch) {
2406 file_bunches.push_back(std::vector<SendableMedia>());
2407 file_size_bunch_total = 0;
2412 /* Create and send packets */
2414 u16 num_bunches = file_bunches.size();
2415 for(u16 i = 0; i < num_bunches; i++) {
2418 u16 total number of texture bunches
2419 u16 index of this bunch
2420 u32 number of files in this bunch
2429 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2430 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2432 for(std::vector<SendableMedia>::iterator
2433 j = file_bunches[i].begin();
2434 j != file_bunches[i].end(); ++j) {
2436 pkt->putLongString(j->data);
2439 verbosestream << "Server::sendRequestedMedia(): bunch "
2440 << i << "/" << num_bunches
2441 << " files=" << file_bunches[i].size()
2442 << " size=" << pkt->getSize() << std::endl;
2447 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2449 if(m_detached_inventories.count(name) == 0) {
2450 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2453 Inventory *inv = m_detached_inventories[name];
2454 std::ostringstream os(std::ios_base::binary);
2456 os << serializeString(name);
2460 std::string s = os.str();
2462 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2463 pkt->putRawString(s.c_str(), s.size());
2465 if (peer_id != PEER_ID_INEXISTENT) {
2469 m_clients.sendToAll(0, pkt, true);
2473 void Server::sendDetachedInventories(u16 peer_id)
2475 DSTACK(__FUNCTION_NAME);
2477 for(std::map<std::string, Inventory*>::iterator
2478 i = m_detached_inventories.begin();
2479 i != m_detached_inventories.end(); i++) {
2480 const std::string &name = i->first;
2481 //Inventory *inv = i->second;
2482 sendDetachedInventory(name, peer_id);
2490 void Server::DiePlayer(u16 peer_id)
2492 DSTACK(__FUNCTION_NAME);
2494 PlayerSAO *playersao = getPlayerSAO(peer_id);
2497 infostream << "Server::DiePlayer(): Player "
2498 << playersao->getPlayer()->getName()
2499 << " dies" << std::endl;
2501 playersao->setHP(0);
2503 // Trigger scripted stuff
2504 m_script->on_dieplayer(playersao);
2506 SendPlayerHP(peer_id);
2507 SendDeathscreen(peer_id, false, v3f(0,0,0));
2510 void Server::RespawnPlayer(u16 peer_id)
2512 DSTACK(__FUNCTION_NAME);
2514 PlayerSAO *playersao = getPlayerSAO(peer_id);
2517 infostream << "Server::RespawnPlayer(): Player "
2518 << playersao->getPlayer()->getName()
2519 << " respawns" << std::endl;
2521 playersao->setHP(PLAYER_MAX_HP);
2522 playersao->setBreath(PLAYER_MAX_BREATH);
2524 SendPlayerHP(peer_id);
2525 SendPlayerBreath(peer_id);
2527 bool repositioned = m_script->on_respawnplayer(playersao);
2529 v3f pos = findSpawnPos(m_env->getServerMap());
2530 // setPos will send the new position to client
2531 playersao->setPos(pos);
2535 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2537 DSTACK(__FUNCTION_NAME);
2539 SendAccessDenied(peer_id, reason);
2540 m_clients.event(peer_id, CSE_SetDenied);
2541 m_con.DisconnectPeer(peer_id);
2544 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2546 DSTACK(__FUNCTION_NAME);
2547 std::wstring message;
2550 Clear references to playing sounds
2552 for(std::map<s32, ServerPlayingSound>::iterator
2553 i = m_playing_sounds.begin();
2554 i != m_playing_sounds.end();)
2556 ServerPlayingSound &psound = i->second;
2557 psound.clients.erase(peer_id);
2558 if(psound.clients.empty())
2559 m_playing_sounds.erase(i++);
2564 Player *player = m_env->getPlayer(peer_id);
2566 // Collect information about leaving in chat
2568 if(player != NULL && reason != CDR_DENY)
2570 std::wstring name = narrow_to_wide(player->getName());
2573 message += L" left the game.";
2574 if(reason == CDR_TIMEOUT)
2575 message += L" (timed out)";
2579 /* Run scripts and remove from environment */
2583 PlayerSAO *playersao = player->getPlayerSAO();
2586 m_script->on_leaveplayer(playersao);
2588 playersao->disconnected();
2596 if(player != NULL && reason != CDR_DENY) {
2597 std::ostringstream os(std::ios_base::binary);
2598 std::vector<u16> clients = m_clients.getClientIDs();
2600 for(std::vector<u16>::iterator i = clients.begin();
2601 i != clients.end(); ++i) {
2603 Player *player = m_env->getPlayer(*i);
2607 // Get name of player
2608 os << player->getName() << " ";
2611 actionstream << player->getName() << " "
2612 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2613 << " List of players: " << os.str() << std::endl;
2617 JMutexAutoLock env_lock(m_env_mutex);
2618 m_clients.DeleteClient(peer_id);
2622 // Send leave chat message to all remaining clients
2623 if(message.length() != 0)
2624 SendChatMessage(PEER_ID_INEXISTENT,message);
2627 void Server::UpdateCrafting(Player* player)
2629 DSTACK(__FUNCTION_NAME);
2631 // Get a preview for crafting
2633 InventoryLocation loc;
2634 loc.setPlayer(player->getName());
2635 getCraftingResult(&player->inventory, preview, false, this);
2636 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2638 // Put the new preview in
2639 InventoryList *plist = player->inventory.getList("craftpreview");
2641 assert(plist->getSize() >= 1);
2642 plist->changeItem(0, preview);
2645 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2647 RemoteClient *client = getClientNoEx(peer_id,state_min);
2649 throw ClientNotFoundException("Client not found");
2653 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2655 return m_clients.getClientNoEx(peer_id, state_min);
2658 std::string Server::getPlayerName(u16 peer_id)
2660 Player *player = m_env->getPlayer(peer_id);
2662 return "[id="+itos(peer_id)+"]";
2663 return player->getName();
2666 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2668 Player *player = m_env->getPlayer(peer_id);
2671 return player->getPlayerSAO();
2674 std::wstring Server::getStatusString()
2676 std::wostringstream os(std::ios_base::binary);
2679 os<<L"version="<<narrow_to_wide(minetest_version_simple);
2681 os<<L", uptime="<<m_uptime.get();
2683 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2684 // Information about clients
2687 std::vector<u16> clients = m_clients.getClientIDs();
2688 for(std::vector<u16>::iterator i = clients.begin();
2689 i != clients.end(); ++i) {
2691 Player *player = m_env->getPlayer(*i);
2692 // Get name of player
2693 std::wstring name = L"unknown";
2695 name = narrow_to_wide(player->getName());
2696 // Add name to information string
2704 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2705 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2706 if(g_settings->get("motd") != "")
2707 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2711 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2713 std::set<std::string> privs;
2714 m_script->getAuth(name, NULL, &privs);
2718 bool Server::checkPriv(const std::string &name, const std::string &priv)
2720 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2721 return (privs.count(priv) != 0);
2724 void Server::reportPrivsModified(const std::string &name)
2727 std::vector<u16> clients = m_clients.getClientIDs();
2728 for(std::vector<u16>::iterator i = clients.begin();
2729 i != clients.end(); ++i) {
2730 Player *player = m_env->getPlayer(*i);
2731 reportPrivsModified(player->getName());
2734 Player *player = m_env->getPlayer(name.c_str());
2737 SendPlayerPrivileges(player->peer_id);
2738 PlayerSAO *sao = player->getPlayerSAO();
2741 sao->updatePrivileges(
2742 getPlayerEffectivePrivs(name),
2747 void Server::reportInventoryFormspecModified(const std::string &name)
2749 Player *player = m_env->getPlayer(name.c_str());
2752 SendPlayerInventoryFormspec(player->peer_id);
2755 void Server::setIpBanned(const std::string &ip, const std::string &name)
2757 m_banmanager->add(ip, name);
2760 void Server::unsetIpBanned(const std::string &ip_or_name)
2762 m_banmanager->remove(ip_or_name);
2765 std::string Server::getBanDescription(const std::string &ip_or_name)
2767 return m_banmanager->getBanDescription(ip_or_name);
2770 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2772 Player *player = m_env->getPlayer(name);
2776 if (player->peer_id == PEER_ID_INEXISTENT)
2779 SendChatMessage(player->peer_id, msg);
2782 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2784 Player *player = m_env->getPlayer(playername);
2788 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2792 SendShowFormspecMessage(player->peer_id, formspec, formname);
2796 u32 Server::hudAdd(Player *player, HudElement *form) {
2800 u32 id = player->addHud(form);
2802 SendHUDAdd(player->peer_id, id, form);
2807 bool Server::hudRemove(Player *player, u32 id) {
2811 HudElement* todel = player->removeHud(id);
2818 SendHUDRemove(player->peer_id, id);
2822 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2826 SendHUDChange(player->peer_id, id, stat, data);
2830 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2834 SendHUDSetFlags(player->peer_id, flags, mask);
2835 player->hud_flags = flags;
2837 PlayerSAO* playersao = player->getPlayerSAO();
2839 if (playersao == NULL)
2842 m_script->player_event(playersao, "hud_changed");
2846 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2849 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2852 std::ostringstream os(std::ios::binary);
2853 writeS32(os, hotbar_itemcount);
2854 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2858 void Server::hudSetHotbarImage(Player *player, std::string name) {
2862 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2865 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2869 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2872 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2877 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2881 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2886 SendEyeOffset(player->peer_id, first, third);
2890 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2891 const std::string &type, const std::vector<std::string> ¶ms)
2896 SendSetSky(player->peer_id, bgcolor, type, params);
2900 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2906 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2910 void Server::notifyPlayers(const std::wstring &msg)
2912 SendChatMessage(PEER_ID_INEXISTENT,msg);
2915 void Server::spawnParticle(const char *playername, v3f pos,
2916 v3f velocity, v3f acceleration,
2917 float expirationtime, float size, bool
2918 collisiondetection, bool vertical, std::string texture)
2920 Player *player = m_env->getPlayer(playername);
2923 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2924 expirationtime, size, collisiondetection, vertical, texture);
2927 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2928 float expirationtime, float size,
2929 bool collisiondetection, bool vertical, std::string texture)
2931 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2932 expirationtime, size, collisiondetection, vertical, texture);
2935 u32 Server::addParticleSpawner(const char *playername,
2936 u16 amount, float spawntime,
2937 v3f minpos, v3f maxpos,
2938 v3f minvel, v3f maxvel,
2939 v3f minacc, v3f maxacc,
2940 float minexptime, float maxexptime,
2941 float minsize, float maxsize,
2942 bool collisiondetection, bool vertical, std::string texture)
2944 Player *player = m_env->getPlayer(playername);
2949 for(;;) // look for unused particlespawner id
2952 if (std::find(m_particlespawner_ids.begin(),
2953 m_particlespawner_ids.end(), id)
2954 == m_particlespawner_ids.end())
2956 m_particlespawner_ids.push_back(id);
2961 SendAddParticleSpawner(player->peer_id, amount, spawntime,
2962 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2963 minexptime, maxexptime, minsize, maxsize,
2964 collisiondetection, vertical, texture, id);
2969 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2970 v3f minpos, v3f maxpos,
2971 v3f minvel, v3f maxvel,
2972 v3f minacc, v3f maxacc,
2973 float minexptime, float maxexptime,
2974 float minsize, float maxsize,
2975 bool collisiondetection, bool vertical, std::string texture)
2978 for(;;) // look for unused particlespawner id
2981 if (std::find(m_particlespawner_ids.begin(),
2982 m_particlespawner_ids.end(), id)
2983 == m_particlespawner_ids.end())
2985 m_particlespawner_ids.push_back(id);
2990 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2991 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2992 minexptime, maxexptime, minsize, maxsize,
2993 collisiondetection, vertical, texture, id);
2998 void Server::deleteParticleSpawner(const char *playername, u32 id)
3000 Player *player = m_env->getPlayer(playername);
3004 m_particlespawner_ids.erase(
3005 std::remove(m_particlespawner_ids.begin(),
3006 m_particlespawner_ids.end(), id),
3007 m_particlespawner_ids.end());
3008 SendDeleteParticleSpawner(player->peer_id, id);
3011 void Server::deleteParticleSpawnerAll(u32 id)
3013 m_particlespawner_ids.erase(
3014 std::remove(m_particlespawner_ids.begin(),
3015 m_particlespawner_ids.end(), id),
3016 m_particlespawner_ids.end());
3017 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3020 Inventory* Server::createDetachedInventory(const std::string &name)
3022 if(m_detached_inventories.count(name) > 0){
3023 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3024 delete m_detached_inventories[name];
3026 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3028 Inventory *inv = new Inventory(m_itemdef);
3030 m_detached_inventories[name] = inv;
3031 //TODO find a better way to do this
3032 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3039 BoolScopeSet(bool *dst, bool val):
3042 m_orig_state = *m_dst;
3047 *m_dst = m_orig_state;
3054 // actions: time-reversed list
3055 // Return value: success/failure
3056 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3057 std::list<std::string> *log)
3059 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3060 ServerMap *map = (ServerMap*)(&m_env->getMap());
3062 // Fail if no actions to handle
3063 if(actions.empty()){
3064 log->push_back("Nothing to do.");
3071 for(std::list<RollbackAction>::const_iterator
3072 i = actions.begin();
3073 i != actions.end(); i++)
3075 const RollbackAction &action = *i;
3077 bool success = action.applyRevert(map, this, this);
3080 std::ostringstream os;
3081 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3082 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3084 log->push_back(os.str());
3086 std::ostringstream os;
3087 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3088 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3090 log->push_back(os.str());
3094 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3095 <<" failed"<<std::endl;
3097 // Call it done if less than half failed
3098 return num_failed <= num_tried/2;
3101 // IGameDef interface
3103 IItemDefManager* Server::getItemDefManager()
3107 INodeDefManager* Server::getNodeDefManager()
3111 ICraftDefManager* Server::getCraftDefManager()
3115 ITextureSource* Server::getTextureSource()
3119 IShaderSource* Server::getShaderSource()
3123 scene::ISceneManager* Server::getSceneManager()
3128 u16 Server::allocateUnknownNodeId(const std::string &name)
3130 return m_nodedef->allocateDummy(name);
3132 ISoundManager* Server::getSoundManager()
3134 return &dummySoundManager;
3136 MtEventManager* Server::getEventManager()
3141 IWritableItemDefManager* Server::getWritableItemDefManager()
3145 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3149 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3154 const ModSpec* Server::getModSpec(const std::string &modname)
3156 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3157 i != m_mods.end(); i++){
3158 const ModSpec &mod = *i;
3159 if(mod.name == modname)
3164 void Server::getModNames(std::vector<std::string> &modlist)
3166 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3167 modlist.push_back(i->name);
3170 std::string Server::getBuiltinLuaPath()
3172 return porting::path_share + DIR_DELIM + "builtin";
3175 v3f findSpawnPos(ServerMap &map)
3177 //return v3f(50,50,50)*BS;
3182 nodepos = v2s16(0,0);
3187 s16 water_level = map.getWaterLevel();
3189 // Try to find a good place a few times
3190 for(s32 i=0; i<1000; i++)
3193 // We're going to try to throw the player to this position
3194 v2s16 nodepos2d = v2s16(
3195 -range + (myrand() % (range * 2)),
3196 -range + (myrand() % (range * 2)));
3198 // Get ground height at point
3199 s16 groundheight = map.findGroundLevel(nodepos2d);
3200 if (groundheight <= water_level) // Don't go underwater
3202 if (groundheight > water_level + 6) // Don't go to high places
3205 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3206 bool is_good = false;
3208 for (s32 i = 0; i < 10; i++) {
3209 v3s16 blockpos = getNodeBlockPos(nodepos);
3210 map.emergeBlock(blockpos, true);
3211 content_t c = map.getNodeNoEx(nodepos).getContent();
3212 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3214 if (air_count >= 2){
3222 // Found a good place
3223 //infostream<<"Searched through "<<i<<" places."<<std::endl;
3229 return intToFloat(nodepos, BS);
3232 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3234 bool newplayer = false;
3237 Try to get an existing player
3239 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3241 // If player is already connected, cancel
3242 if(player != NULL && player->peer_id != 0)
3244 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3249 If player with the wanted peer_id already exists, cancel.
3251 if(m_env->getPlayer(peer_id) != NULL)
3253 infostream<<"emergePlayer(): Player with wrong name but same"
3254 " peer_id already exists"<<std::endl;
3258 // Load player if it isn't already loaded
3260 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3263 // Create player if it doesn't exist
3266 player = new RemotePlayer(this, name);
3267 // Set player position
3268 infostream<<"Server: Finding spawn place for player \""
3269 <<name<<"\""<<std::endl;
3270 v3f pos = findSpawnPos(m_env->getServerMap());
3271 player->setPosition(pos);
3273 // Make sure the player is saved
3274 player->setModified(true);
3276 // Add player to environment
3277 m_env->addPlayer(player);
3280 // Create a new player active object
3281 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3282 getPlayerEffectivePrivs(player->getName()),
3285 /* Clean up old HUD elements from previous sessions */
3288 /* Add object to environment */
3289 m_env->addActiveObject(playersao);
3293 m_script->on_newplayer(playersao);
3299 void dedicated_server_loop(Server &server, bool &kill)
3301 DSTACK(__FUNCTION_NAME);
3303 verbosestream<<"dedicated_server_loop()"<<std::endl;
3305 IntervalLimiter m_profiler_interval;
3309 float steplen = g_settings->getFloat("dedicated_server_step");
3310 // This is kind of a hack but can be done like this
3311 // because server.step() is very light
3313 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3314 sleep_ms((int)(steplen*1000.0));
3316 server.step(steplen);
3318 if(server.getShutdownRequested() || kill)
3320 infostream<<"Dedicated server quitting"<<std::endl;
3322 if(g_settings->getBool("server_announce"))
3323 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3331 float profiler_print_interval =
3332 g_settings->getFloat("profiler_print_interval");
3333 if(profiler_print_interval != 0)
3335 if(m_profiler_interval.step(steplen, profiler_print_interval))
3337 infostream<<"Profiler:"<<std::endl;
3338 g_profiler->print(infostream);
3339 g_profiler->clear();