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 "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #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/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_rollback_sink_enabled(true),
185 m_enable_rollback_recording(false),
188 m_itemdef(createItemDefManager()),
189 m_nodedef(createNodeDefManager()),
190 m_craftdef(createCraftDefManager()),
191 m_event(new EventManager()),
193 m_time_of_day_send_timer(0),
196 m_shutdown_requested(false),
197 m_ignore_map_edit_events(false),
198 m_ignore_map_edit_events_peer_id(0)
201 m_liquid_transform_timer = 0.0;
202 m_liquid_transform_every = 1.0;
203 m_print_info_timer = 0.0;
204 m_masterserver_timer = 0.0;
205 m_objectdata_timer = 0.0;
206 m_emergethread_trigger_timer = 0.0;
207 m_savemap_timer = 0.0;
210 m_lag = g_settings->getFloat("dedicated_server_step");
213 throw ServerError("Supplied empty world path");
215 if(!gamespec.isValid())
216 throw ServerError("Supplied invalid gamespec");
218 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
219 if(m_simple_singleplayer_mode)
220 infostream<<" in simple singleplayer mode"<<std::endl;
222 infostream<<std::endl;
223 infostream<<"- world: "<<m_path_world<<std::endl;
224 infostream<<"- game: "<<m_gamespec.path<<std::endl;
226 // Initialize default settings and override defaults with those provided
228 set_default_settings(g_settings);
229 Settings gamedefaults;
230 getGameMinetestConfig(gamespec.path, gamedefaults);
231 override_default_settings(g_settings, &gamedefaults);
233 // Create server thread
234 m_thread = new ServerThread(this);
236 // Create emerge manager
237 m_emerge = new EmergeManager(this);
239 // Create world if it doesn't exist
240 if(!initializeWorld(m_path_world, m_gamespec.id))
241 throw ServerError("Failed to initialize world");
243 // Create ban manager
244 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
245 m_banmanager = new BanManager(ban_path);
247 // Create rollback manager
248 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
249 m_rollback = createRollbackManager(rollback_path, this);
251 ModConfiguration modconf(m_path_world);
252 m_mods = modconf.getMods();
253 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
254 // complain about mods with unsatisfied dependencies
255 if(!modconf.isConsistent())
257 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
258 it != unsatisfied_mods.end(); ++it)
261 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
262 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
263 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
264 errorstream << " \"" << *dep_it << "\"";
265 errorstream << std::endl;
269 Settings worldmt_settings;
270 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
271 worldmt_settings.readConfigFile(worldmt.c_str());
272 std::vector<std::string> names = worldmt_settings.getNames();
273 std::set<std::string> load_mod_names;
274 for(std::vector<std::string>::iterator it = names.begin();
275 it != names.end(); ++it)
277 std::string name = *it;
278 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
279 load_mod_names.insert(name.substr(9));
281 // complain about mods declared to be loaded, but not found
282 for(std::vector<ModSpec>::iterator it = m_mods.begin();
283 it != m_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
286 it != unsatisfied_mods.end(); ++it)
287 load_mod_names.erase((*it).name);
288 if(!load_mod_names.empty())
290 errorstream << "The following mods could not be found:";
291 for(std::set<std::string>::iterator it = load_mod_names.begin();
292 it != load_mod_names.end(); ++it)
293 errorstream << " \"" << (*it) << "\"";
294 errorstream << std::endl;
298 JMutexAutoLock envlock(m_env_mutex);
300 // Initialize scripting
301 infostream<<"Server: Initializing Lua"<<std::endl;
303 m_script = new GameScripting(this);
305 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
307 if (!m_script->loadScript(scriptpath)) {
308 throw ModError("Failed to load and run " + scriptpath);
313 infostream<<"Server: Loading mods: ";
314 for(std::vector<ModSpec>::iterator i = m_mods.begin();
315 i != m_mods.end(); i++){
316 const ModSpec &mod = *i;
317 infostream<<mod.name<<" ";
319 infostream<<std::endl;
320 // Load and run "mod" scripts
321 for(std::vector<ModSpec>::iterator i = m_mods.begin();
322 i != m_mods.end(); i++){
323 const ModSpec &mod = *i;
324 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
325 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
326 <<scriptpath<<"\"]"<<std::endl;
327 bool success = m_script->loadMod(scriptpath, mod.name);
329 errorstream<<"Server: Failed to load and run "
330 <<scriptpath<<std::endl;
331 throw ModError("Failed to load and run "+scriptpath);
335 // Read Textures and calculate sha1 sums
338 // Apply item aliases in the node definition manager
339 m_nodedef->updateAliases(m_itemdef);
341 // Load the mapgen params from global settings now after any
342 // initial overrides have been set by the mods
343 m_emerge->loadMapgenParams();
345 // Initialize Environment
346 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
347 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
349 m_clients.setEnv(m_env);
351 // Run some callbacks after the MG params have been set up but before activation
352 m_script->environment_OnMapgenInit(&m_emerge->params);
354 // Initialize mapgens
355 m_emerge->initMapgens();
357 // Give environment reference to scripting api
358 m_script->initializeEnvironment(m_env);
360 // Register us to receive map edit events
361 servermap->addEventReceiver(this);
363 // If file exists, load environment metadata
364 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
366 infostream<<"Server: Loading environment metadata"<<std::endl;
370 // Add some test ActiveBlockModifiers to environment
371 add_legacy_abms(m_env, m_nodedef);
373 m_liquid_transform_every = g_settings->getFloat("liquid_update");
378 infostream<<"Server destructing"<<std::endl;
380 // Send shutdown message
381 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
384 JMutexAutoLock envlock(m_env_mutex);
386 // Execute script shutdown hooks
387 m_script->on_shutdown();
389 infostream<<"Server: Saving players"<<std::endl;
390 m_env->saveLoadedPlayers();
392 infostream<<"Server: Saving environment metadata"<<std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
407 // N.B. the EmergeManager should be deleted after the Environment since Map
408 // depends on EmergeManager to write its current params to the map meta
417 // Deinitialize scripting
418 infostream<<"Server: Deinitializing scripting"<<std::endl;
421 // Delete detached inventories
422 for (std::map<std::string, Inventory*>::iterator
423 i = m_detached_inventories.begin();
424 i != m_detached_inventories.end(); i++) {
429 void Server::start(Address bind_addr)
431 DSTACK(__FUNCTION_NAME);
432 infostream<<"Starting server on "
433 << bind_addr.serializeString() <<"..."<<std::endl;
435 // Stop thread if already running
438 // Initialize connection
439 m_con.SetTimeoutMs(30);
440 m_con.Serve(bind_addr);
445 // ASCII art for the win!
447 <<" .__ __ __ "<<std::endl
448 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
449 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
450 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
451 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
452 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
453 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
454 actionstream<<"Server for gameid=\""<<m_gamespec.id
455 <<"\" listening on "<<bind_addr.serializeString()<<":"
456 <<bind_addr.getPort() << "."<<std::endl;
461 DSTACK(__FUNCTION_NAME);
463 infostream<<"Server: Stopping and waiting threads"<<std::endl;
465 // Stop threads (set run=false first so both start stopping)
467 //m_emergethread.setRun(false);
469 //m_emergethread.stop();
471 infostream<<"Server: Threads stopped"<<std::endl;
474 void Server::step(float dtime)
476 DSTACK(__FUNCTION_NAME);
481 JMutexAutoLock lock(m_step_dtime_mutex);
482 m_step_dtime += dtime;
484 // Throw if fatal error occurred in thread
485 std::string async_err = m_async_fatal_error.get();
487 throw ServerError(async_err);
491 void Server::AsyncRunStep(bool initial_step)
493 DSTACK(__FUNCTION_NAME);
495 g_profiler->add("Server::AsyncRunStep (num)", 1);
499 JMutexAutoLock lock1(m_step_dtime_mutex);
500 dtime = m_step_dtime;
504 // Send blocks to clients
508 if((dtime < 0.001) && (initial_step == false))
511 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
513 //infostream<<"Server steps "<<dtime<<std::endl;
514 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
517 JMutexAutoLock lock1(m_step_dtime_mutex);
518 m_step_dtime -= dtime;
525 m_uptime.set(m_uptime.get() + dtime);
531 Update time of day and overall game time
534 JMutexAutoLock envlock(m_env_mutex);
536 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
539 Send to clients at constant intervals
542 m_time_of_day_send_timer -= dtime;
543 if(m_time_of_day_send_timer < 0.0)
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 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 const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 JMutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"));
588 JMutexAutoLock lock(m_env_mutex);
590 std::list<u16> clientids = m_clients.getClientIDs();
592 ScopeProfiler sp(g_profiler, "Server: handle players");
594 for(std::list<u16>::iterator
595 i = clientids.begin();
596 i != clientids.end(); ++i)
598 PlayerSAO *playersao = getPlayerSAO(*i);
599 if(playersao == NULL)
603 Handle player HPs (die if hp=0)
605 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
607 if(playersao->getHP() == 0)
614 Send player breath if changed
616 if(playersao->m_breath_not_sent) {
617 SendPlayerBreath(*i);
621 Send player inventories if necessary
623 if(playersao->m_moved){
625 playersao->m_moved = false;
627 if(playersao->m_inventory_not_sent){
634 /* Transform liquids */
635 m_liquid_transform_timer += dtime;
636 if(m_liquid_transform_timer >= m_liquid_transform_every)
638 m_liquid_transform_timer -= m_liquid_transform_every;
640 JMutexAutoLock lock(m_env_mutex);
642 ScopeProfiler sp(g_profiler, "Server: liquid transform");
644 std::map<v3s16, MapBlock*> modified_blocks;
645 m_env->getMap().transformLiquids(modified_blocks);
650 core::map<v3s16, MapBlock*> lighting_modified_blocks;
651 ServerMap &map = ((ServerMap&)m_env->getMap());
652 map.updateLighting(modified_blocks, lighting_modified_blocks);
654 // Add blocks modified by lighting to modified_blocks
655 for(core::map<v3s16, MapBlock*>::Iterator
656 i = lighting_modified_blocks.getIterator();
657 i.atEnd() == false; i++)
659 MapBlock *block = i.getNode()->getValue();
660 modified_blocks.insert(block->getPos(), block);
664 Set the modified blocks unsent for all the clients
666 if(modified_blocks.size() > 0)
668 SetBlocksNotSent(modified_blocks);
671 m_clients.step(dtime);
673 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
675 // send masterserver announce
677 float &counter = m_masterserver_timer;
678 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
679 g_settings->getBool("server_announce") == true)
681 ServerList::sendAnnounce(!counter ? "start" : "update",
682 m_clients.getPlayerNames(),
684 m_env->getGameTime(),
695 Check added and deleted active objects
698 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
699 JMutexAutoLock envlock(m_env_mutex);
702 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
703 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
705 // Radius inside which objects are active
706 s16 radius = g_settings->getS16("active_object_send_range_blocks");
707 radius *= MAP_BLOCKSIZE;
709 for(std::map<u16, RemoteClient*>::iterator
711 i != clients.end(); ++i)
713 RemoteClient *client = i->second;
715 // If definitions and textures have not been sent, don't
716 // send objects either
717 if (client->getState() < CS_DefinitionsSent)
720 Player *player = m_env->getPlayer(client->peer_id);
723 // This can happen if the client timeouts somehow
724 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
726 <<" has no associated player"<<std::endl;*/
729 v3s16 pos = floatToInt(player->getPosition(), BS);
731 std::set<u16> removed_objects;
732 std::set<u16> added_objects;
733 m_env->getRemovedActiveObjects(pos, radius,
734 client->m_known_objects, removed_objects);
735 m_env->getAddedActiveObjects(pos, radius,
736 client->m_known_objects, added_objects);
738 // Ignore if nothing happened
739 if(removed_objects.size() == 0 && added_objects.size() == 0)
741 //infostream<<"active objects: none changed"<<std::endl;
745 std::string data_buffer;
749 // Handle removed objects
750 writeU16((u8*)buf, removed_objects.size());
751 data_buffer.append(buf, 2);
752 for(std::set<u16>::iterator
753 i = removed_objects.begin();
754 i != removed_objects.end(); ++i)
758 ServerActiveObject* obj = m_env->getActiveObject(id);
760 // Add to data buffer for sending
761 writeU16((u8*)buf, id);
762 data_buffer.append(buf, 2);
764 // Remove from known objects
765 client->m_known_objects.erase(id);
767 if(obj && obj->m_known_by_count > 0)
768 obj->m_known_by_count--;
771 // Handle added objects
772 writeU16((u8*)buf, added_objects.size());
773 data_buffer.append(buf, 2);
774 for(std::set<u16>::iterator
775 i = added_objects.begin();
776 i != added_objects.end(); ++i)
780 ServerActiveObject* obj = m_env->getActiveObject(id);
783 u8 type = ACTIVEOBJECT_TYPE_INVALID;
785 infostream<<"WARNING: "<<__FUNCTION_NAME
786 <<": NULL object"<<std::endl;
788 type = obj->getSendType();
790 // Add to data buffer for sending
791 writeU16((u8*)buf, id);
792 data_buffer.append(buf, 2);
793 writeU8((u8*)buf, type);
794 data_buffer.append(buf, 1);
797 data_buffer.append(serializeLongString(
798 obj->getClientInitializationData(client->net_proto_version)));
800 data_buffer.append(serializeLongString(""));
802 // Add to known objects
803 client->m_known_objects.insert(id);
806 obj->m_known_by_count++;
810 SharedBuffer<u8> reply(2 + data_buffer.size());
811 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
812 memcpy((char*)&reply[2], data_buffer.c_str(),
815 m_clients.send(client->peer_id, 0, reply, true);
817 verbosestream<<"Server: Sent object remove/add: "
818 <<removed_objects.size()<<" removed, "
819 <<added_objects.size()<<" added, "
820 <<"packet size is "<<reply.getSize()<<std::endl;
825 Collect a list of all the objects known by the clients
826 and report it back to the environment.
829 core::map<u16, bool> all_known_objects;
831 for(core::map<u16, RemoteClient*>::Iterator
832 i = m_clients.getIterator();
833 i.atEnd() == false; i++)
835 RemoteClient *client = i.getNode()->getValue();
836 // Go through all known objects of client
837 for(core::map<u16, bool>::Iterator
838 i = client->m_known_objects.getIterator();
839 i.atEnd()==false; i++)
841 u16 id = i.getNode()->getKey();
842 all_known_objects[id] = true;
846 m_env->setKnownActiveObjects(whatever);
855 JMutexAutoLock envlock(m_env_mutex);
856 ScopeProfiler sp(g_profiler, "Server: sending object messages");
859 // Value = data sent by object
860 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
862 // Get active object messages from environment
865 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
869 std::list<ActiveObjectMessage>* message_list = NULL;
870 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
871 n = buffered_messages.find(aom.id);
872 if(n == buffered_messages.end())
874 message_list = new std::list<ActiveObjectMessage>;
875 buffered_messages[aom.id] = message_list;
879 message_list = n->second;
881 message_list->push_back(aom);
885 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
886 // Route data to every client
887 for(std::map<u16, RemoteClient*>::iterator
889 i != clients.end(); ++i)
891 RemoteClient *client = i->second;
892 std::string reliable_data;
893 std::string unreliable_data;
894 // Go through all objects in message buffer
895 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
896 j = buffered_messages.begin();
897 j != buffered_messages.end(); ++j)
899 // If object is not known by client, skip it
901 if(client->m_known_objects.find(id) == client->m_known_objects.end())
903 // Get message list of object
904 std::list<ActiveObjectMessage>* list = j->second;
905 // Go through every message
906 for(std::list<ActiveObjectMessage>::iterator
907 k = list->begin(); k != list->end(); ++k)
909 // Compose the full new data with header
910 ActiveObjectMessage aom = *k;
911 std::string new_data;
914 writeU16((u8*)&buf[0], aom.id);
915 new_data.append(buf, 2);
917 new_data += serializeString(aom.datastring);
918 // Add data to buffer
920 reliable_data += new_data;
922 unreliable_data += new_data;
926 reliable_data and unreliable_data are now ready.
929 if(reliable_data.size() > 0)
931 SharedBuffer<u8> reply(2 + reliable_data.size());
932 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
933 memcpy((char*)&reply[2], reliable_data.c_str(),
934 reliable_data.size());
936 m_clients.send(client->peer_id, 0, reply, true);
938 if(unreliable_data.size() > 0)
940 SharedBuffer<u8> reply(2 + unreliable_data.size());
941 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
942 memcpy((char*)&reply[2], unreliable_data.c_str(),
943 unreliable_data.size());
944 // Send as unreliable
945 m_clients.send(client->peer_id, 1, reply, false);
948 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
950 infostream<<"Server: Size of object message data: "
951 <<"reliable: "<<reliable_data.size()
952 <<", unreliable: "<<unreliable_data.size()
958 // Clear buffered_messages
959 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
960 i = buffered_messages.begin();
961 i != buffered_messages.end(); ++i)
968 Send queued-for-sending map edit events.
971 // We will be accessing the environment
972 JMutexAutoLock lock(m_env_mutex);
974 // Don't send too many at a time
977 // Single change sending is disabled if queue size is not small
978 bool disable_single_change_sending = false;
979 if(m_unsent_map_edit_queue.size() >= 4)
980 disable_single_change_sending = true;
982 int event_count = m_unsent_map_edit_queue.size();
984 // We'll log the amount of each
987 while(m_unsent_map_edit_queue.size() != 0)
989 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
991 // Players far away from the change are stored here.
992 // Instead of sending the changes, MapBlocks are set not sent
994 std::list<u16> far_players;
996 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
998 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
999 prof.add("MEET_ADDNODE", 1);
1000 if(disable_single_change_sending)
1001 sendAddNode(event->p, event->n, event->already_known_by_peer,
1002 &far_players, 5, event->type == MEET_ADDNODE);
1004 sendAddNode(event->p, event->n, event->already_known_by_peer,
1005 &far_players, 30, event->type == MEET_ADDNODE);
1007 else if(event->type == MEET_REMOVENODE)
1009 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1010 prof.add("MEET_REMOVENODE", 1);
1011 if(disable_single_change_sending)
1012 sendRemoveNode(event->p, event->already_known_by_peer,
1015 sendRemoveNode(event->p, event->already_known_by_peer,
1018 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1020 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1021 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1022 setBlockNotSent(event->p);
1024 else if(event->type == MEET_OTHER)
1026 infostream<<"Server: MEET_OTHER"<<std::endl;
1027 prof.add("MEET_OTHER", 1);
1028 for(std::set<v3s16>::iterator
1029 i = event->modified_blocks.begin();
1030 i != event->modified_blocks.end(); ++i)
1032 setBlockNotSent(*i);
1037 prof.add("unknown", 1);
1038 infostream<<"WARNING: Server: Unknown MapEditEvent "
1039 <<((u32)event->type)<<std::endl;
1043 Set blocks not sent to far players
1045 if(far_players.size() > 0)
1047 // Convert list format to that wanted by SetBlocksNotSent
1048 std::map<v3s16, MapBlock*> modified_blocks2;
1049 for(std::set<v3s16>::iterator
1050 i = event->modified_blocks.begin();
1051 i != event->modified_blocks.end(); ++i)
1053 modified_blocks2[*i] =
1054 m_env->getMap().getBlockNoCreateNoEx(*i);
1056 // Set blocks not sent
1057 for(std::list<u16>::iterator
1058 i = far_players.begin();
1059 i != far_players.end(); ++i)
1062 RemoteClient *client = getClient(peer_id);
1065 client->SetBlocksNotSent(modified_blocks2);
1071 /*// Don't send too many at a time
1073 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1077 if(event_count >= 5){
1078 infostream<<"Server: MapEditEvents:"<<std::endl;
1079 prof.print(infostream);
1080 } else if(event_count != 0){
1081 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1082 prof.print(verbosestream);
1088 Trigger emergethread (it somehow gets to a non-triggered but
1089 bysy state sometimes)
1092 float &counter = m_emergethread_trigger_timer;
1098 m_emerge->startThreads();
1100 // Update m_enable_rollback_recording here too
1101 m_enable_rollback_recording =
1102 g_settings->getBool("enable_rollback_recording");
1106 // Save map, players and auth stuff
1108 float &counter = m_savemap_timer;
1110 if(counter >= g_settings->getFloat("server_map_save_interval"))
1113 JMutexAutoLock lock(m_env_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1118 if (m_banmanager->isModified()) {
1119 m_banmanager->save();
1122 // Save changed parts of map
1123 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1126 m_env->saveLoadedPlayers();
1128 // Save environment metadata
1134 void Server::Receive()
1136 DSTACK(__FUNCTION_NAME);
1137 SharedBuffer<u8> data;
1141 datasize = m_con.Receive(peer_id,data);
1142 ProcessData(*data, datasize, peer_id);
1144 catch(con::InvalidIncomingDataException &e)
1146 infostream<<"Server::Receive(): "
1147 "InvalidIncomingDataException: what()="
1148 <<e.what()<<std::endl;
1150 catch(SerializationError &e) {
1151 infostream<<"Server::Receive(): "
1152 "SerializationError: what()="
1153 <<e.what()<<std::endl;
1155 catch(ClientStateError &e)
1157 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1158 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1159 L"Try reconnecting or updating your client");
1161 catch(con::PeerNotFoundException &e)
1167 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1169 std::string playername = "";
1170 PlayerSAO *playersao = NULL;
1172 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1173 if (client != NULL) {
1174 playername = client->getName();
1175 playersao = emergePlayer(playername.c_str(), peer_id);
1179 RemotePlayer *player =
1180 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1182 // If failed, cancel
1183 if((playersao == NULL) || (player == NULL))
1185 if(player && player->peer_id != 0){
1186 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1187 <<" (player allocated to an another client)"<<std::endl;
1188 DenyAccess(peer_id, L"Another client is connected with this "
1189 L"name. If your client closed unexpectedly, try again in "
1192 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1194 DenyAccess(peer_id, L"Could not allocate player.");
1200 Send complete position information
1202 SendMovePlayer(peer_id);
1205 SendPlayerPrivileges(peer_id);
1207 // Send inventory formspec
1208 SendPlayerInventoryFormspec(peer_id);
1211 UpdateCrafting(peer_id);
1212 SendInventory(peer_id);
1215 if(g_settings->getBool("enable_damage"))
1216 SendPlayerHP(peer_id);
1219 SendPlayerBreath(peer_id);
1221 // Show death screen if necessary
1223 SendDeathscreen(peer_id, false, v3f(0,0,0));
1225 // Note things in chat if not in simple singleplayer mode
1226 if(!m_simple_singleplayer_mode)
1228 // Send information about server to player in chat
1229 SendChatMessage(peer_id, getStatusString());
1231 // Send information about joining in chat
1233 std::wstring name = L"unknown";
1234 Player *player = m_env->getPlayer(peer_id);
1236 name = narrow_to_wide(player->getName());
1238 std::wstring message;
1241 message += L" joined the game.";
1242 SendChatMessage(PEER_ID_INEXISTENT,message);
1245 Address addr = getPeerAddress(player->peer_id);
1246 std::string ip_str = addr.serializeString();
1247 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1252 std::vector<std::string> names = m_clients.getPlayerNames();
1254 actionstream<<player->getName() <<" joins game. List of players: ";
1256 for (std::vector<std::string>::iterator i = names.begin();
1257 i != names.end(); i++)
1259 actionstream << *i << " ";
1262 actionstream << player->getName() <<std::endl;
1267 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1269 DSTACK(__FUNCTION_NAME);
1270 // Environment is locked first.
1271 JMutexAutoLock envlock(m_env_mutex);
1273 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1277 Address address = getPeerAddress(peer_id);
1278 addr_s = address.serializeString();
1280 // drop player if is ip is banned
1281 if(m_banmanager->isIpBanned(addr_s)){
1282 std::string ban_name = m_banmanager->getBanName(addr_s);
1283 infostream<<"Server: A banned client tried to connect from "
1284 <<addr_s<<"; banned name was "
1285 <<ban_name<<std::endl;
1286 // This actually doesn't seem to transfer to the client
1287 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1288 +narrow_to_wide(ban_name));
1292 catch(con::PeerNotFoundException &e)
1295 * no peer for this packet found
1296 * most common reason is peer timeout, e.g. peer didn't
1297 * respond for some time, your server was overloaded or
1300 infostream<<"Server::ProcessData(): Cancelling: peer "
1301 <<peer_id<<" not found"<<std::endl;
1311 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1313 if(command == TOSERVER_INIT)
1315 // [0] u16 TOSERVER_INIT
1316 // [2] u8 SER_FMT_VER_HIGHEST_READ
1317 // [3] u8[20] player_name
1318 // [23] u8[28] password <--- can be sent without this, from old versions
1320 if(datasize < 2+1+PLAYERNAME_SIZE)
1323 RemoteClient* client = getClient(peer_id, CS_Created);
1325 // If net_proto_version is set, this client has already been handled
1326 if(client->getState() > CS_Created)
1328 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1329 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1333 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1334 <<peer_id<<")"<<std::endl;
1336 // Do not allow multiple players in simple singleplayer mode.
1337 // This isn't a perfect way to do it, but will suffice for now
1338 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1339 infostream<<"Server: Not allowing another client ("<<addr_s
1340 <<") to connect in simple singleplayer mode"<<std::endl;
1341 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1345 // First byte after command is maximum supported
1346 // serialization version
1347 u8 client_max = data[2];
1348 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1349 // Use the highest version supported by both
1350 u8 deployed = std::min(client_max, our_max);
1351 // If it's lower than the lowest supported, give up.
1352 if(deployed < SER_FMT_VER_LOWEST)
1353 deployed = SER_FMT_VER_INVALID;
1355 if(deployed == SER_FMT_VER_INVALID)
1357 actionstream<<"Server: A mismatched client tried to connect from "
1358 <<addr_s<<std::endl;
1359 infostream<<"Server: Cannot negotiate serialization version with "
1360 <<addr_s<<std::endl;
1361 DenyAccess(peer_id, std::wstring(
1362 L"Your client's version is not supported.\n"
1363 L"Server version is ")
1364 + narrow_to_wide(minetest_version_simple) + L"."
1369 client->setPendingSerializationVersion(deployed);
1372 Read and check network protocol version
1375 u16 min_net_proto_version = 0;
1376 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1377 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1379 // Use same version as minimum and maximum if maximum version field
1380 // doesn't exist (backwards compatibility)
1381 u16 max_net_proto_version = min_net_proto_version;
1382 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1383 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1385 // Start with client's maximum version
1386 u16 net_proto_version = max_net_proto_version;
1388 // Figure out a working version if it is possible at all
1389 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1390 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1392 // If maximum is larger than our maximum, go with our maximum
1393 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1394 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1395 // Else go with client's maximum
1397 net_proto_version = max_net_proto_version;
1400 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1401 <<min_net_proto_version<<", max: "<<max_net_proto_version
1402 <<", chosen: "<<net_proto_version<<std::endl;
1404 client->net_proto_version = net_proto_version;
1406 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1407 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1409 actionstream<<"Server: A mismatched client tried to connect from "
1410 <<addr_s<<std::endl;
1411 DenyAccess(peer_id, std::wstring(
1412 L"Your client's version is not supported.\n"
1413 L"Server version is ")
1414 + narrow_to_wide(minetest_version_simple) + L",\n"
1415 + L"server's PROTOCOL_VERSION is "
1416 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1418 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1419 + L", client's PROTOCOL_VERSION is "
1420 + narrow_to_wide(itos(min_net_proto_version))
1422 + narrow_to_wide(itos(max_net_proto_version))
1427 if(g_settings->getBool("strict_protocol_version_checking"))
1429 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1431 actionstream<<"Server: A mismatched (strict) client tried to "
1432 <<"connect from "<<addr_s<<std::endl;
1433 DenyAccess(peer_id, std::wstring(
1434 L"Your client's version is not supported.\n"
1435 L"Server version is ")
1436 + narrow_to_wide(minetest_version_simple) + L",\n"
1437 + L"server's PROTOCOL_VERSION (strict) is "
1438 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1439 + L", client's PROTOCOL_VERSION is "
1440 + narrow_to_wide(itos(min_net_proto_version))
1442 + narrow_to_wide(itos(max_net_proto_version))
1453 char playername[PLAYERNAME_SIZE];
1454 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1456 playername[i] = data[3+i];
1458 playername[PLAYERNAME_SIZE-1] = 0;
1460 if(playername[0]=='\0')
1462 actionstream<<"Server: Player with an empty name "
1463 <<"tried to connect from "<<addr_s<<std::endl;
1464 DenyAccess(peer_id, L"Empty name");
1468 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1470 actionstream<<"Server: Player with an invalid name "
1471 <<"tried to connect from "<<addr_s<<std::endl;
1472 DenyAccess(peer_id, L"Name contains unallowed characters");
1476 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1478 actionstream<<"Server: Player with the name \"singleplayer\" "
1479 <<"tried to connect from "<<addr_s<<std::endl;
1480 DenyAccess(peer_id, L"Name is not allowed");
1486 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1488 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1489 <<"tried to connect from "<<addr_s<<" "
1490 <<"but it was disallowed for the following reason: "
1491 <<reason<<std::endl;
1492 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1497 infostream<<"Server: New connection: \""<<playername<<"\" from "
1498 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1501 char given_password[PASSWORD_SIZE];
1502 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1504 // old version - assume blank password
1505 given_password[0] = 0;
1509 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1511 given_password[i] = data[23+i];
1513 given_password[PASSWORD_SIZE-1] = 0;
1516 if(!base64_is_valid(given_password)){
1517 actionstream<<"Server: "<<playername
1518 <<" supplied invalid password hash"<<std::endl;
1519 DenyAccess(peer_id, L"Invalid password hash");
1523 // Enforce user limit.
1524 // Don't enforce for users that have some admin right
1525 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1526 !checkPriv(playername, "server") &&
1527 !checkPriv(playername, "ban") &&
1528 !checkPriv(playername, "privs") &&
1529 !checkPriv(playername, "password") &&
1530 playername != g_settings->get("name"))
1532 actionstream<<"Server: "<<playername<<" tried to join, but there"
1533 <<" are already max_users="
1534 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1535 DenyAccess(peer_id, L"Too many users.");
1539 std::string checkpwd; // Password hash to check against
1540 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1542 // If no authentication info exists for user, create it
1544 if(!isSingleplayer() &&
1545 g_settings->getBool("disallow_empty_password") &&
1546 std::string(given_password) == ""){
1547 actionstream<<"Server: "<<playername
1548 <<" supplied empty password"<<std::endl;
1549 DenyAccess(peer_id, L"Empty passwords are "
1550 L"disallowed. Set a password and try again.");
1553 std::wstring raw_default_password =
1554 narrow_to_wide(g_settings->get("default_password"));
1555 std::string initial_password =
1556 translatePassword(playername, raw_default_password);
1558 // If default_password is empty, allow any initial password
1559 if (raw_default_password.length() == 0)
1560 initial_password = given_password;
1562 m_script->createAuth(playername, initial_password);
1565 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1568 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1569 <<" (auth handler does not work?)"<<std::endl;
1570 DenyAccess(peer_id, L"Not allowed to login");
1574 if(given_password != checkpwd){
1575 actionstream<<"Server: "<<playername<<" supplied wrong password"
1577 DenyAccess(peer_id, L"Wrong password");
1581 RemotePlayer *player =
1582 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1584 if(player && player->peer_id != 0){
1585 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1586 <<" (player allocated to an another client)"<<std::endl;
1587 DenyAccess(peer_id, L"Another client is connected with this "
1588 L"name. If your client closed unexpectedly, try again in "
1592 m_clients.setPlayerName(peer_id,playername);
1595 Answer with a TOCLIENT_INIT
1598 SharedBuffer<u8> reply(2+1+6+8+4);
1599 writeU16(&reply[0], TOCLIENT_INIT);
1600 writeU8(&reply[2], deployed);
1601 //send dummy pos for legacy reasons only
1602 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1603 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1604 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1607 m_clients.send(peer_id, 0, reply, true);
1608 m_clients.event(peer_id, CSE_Init);
1614 if(command == TOSERVER_INIT2)
1617 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1618 <<peer_id<<std::endl;
1620 m_clients.event(peer_id, CSE_GotInit2);
1621 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1624 ///// begin compatibility code
1625 PlayerSAO* playersao = NULL;
1626 if (protocol_version <= 22) {
1627 playersao = StageTwoClientInit(peer_id);
1629 if (playersao == NULL) {
1631 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1632 << peer_id << std::endl;
1636 ///// end compatibility code
1639 Send some initialization data
1642 infostream<<"Server: Sending content to "
1643 <<getPlayerName(peer_id)<<std::endl;
1645 // Send player movement settings
1646 SendMovement(peer_id);
1648 // Send item definitions
1649 SendItemDef(peer_id, m_itemdef, protocol_version);
1651 // Send node definitions
1652 SendNodeDef(peer_id, m_nodedef, protocol_version);
1654 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1656 // Send media announcement
1657 sendMediaAnnouncement(peer_id);
1659 // Send detached inventories
1660 sendDetachedInventories(peer_id);
1663 u16 time = m_env->getTimeOfDay();
1664 float time_speed = g_settings->getFloat("time_speed");
1665 SendTimeOfDay(peer_id, time, time_speed);
1667 ///// begin compatibility code
1668 if (protocol_version <= 22) {
1669 m_clients.event(peer_id, CSE_SetClientReady);
1670 m_script->on_joinplayer(playersao);
1672 ///// end compatibility code
1674 // Warnings about protocol version can be issued here
1675 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1677 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1678 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1684 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1685 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1687 if(peer_ser_ver == SER_FMT_VER_INVALID)
1689 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1690 " serialization format invalid or not initialized."
1691 " Skipping incoming command="<<command<<std::endl;
1695 /* Handle commands relate to client startup */
1696 if(command == TOSERVER_REQUEST_MEDIA) {
1697 std::string datastring((char*)&data[2], datasize-2);
1698 std::istringstream is(datastring, std::ios_base::binary);
1700 std::list<std::string> tosend;
1701 u16 numfiles = readU16(is);
1703 infostream<<"Sending "<<numfiles<<" files to "
1704 <<getPlayerName(peer_id)<<std::endl;
1705 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1707 for(int i = 0; i < numfiles; i++) {
1708 std::string name = deSerializeString(is);
1709 tosend.push_back(name);
1710 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1714 sendRequestedMedia(peer_id, tosend);
1717 else if(command == TOSERVER_RECEIVED_MEDIA) {
1720 else if(command == TOSERVER_CLIENT_READY) {
1721 // clients <= protocol version 22 did not send ready message,
1722 // they're already initialized
1723 if (peer_proto_ver <= 22) {
1724 infostream << "Client sent message not expected by a "
1725 << "client using protocol version <= 22,"
1726 << "disconnecing peer_id: " << peer_id << std::endl;
1727 m_con.DisconnectPeer(peer_id);
1731 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1733 if (playersao == NULL) {
1735 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1736 << peer_id << std::endl;
1744 m_clients.setClientVersion(
1746 data[2], data[3], data[4],
1747 std::string((char*) &data[8],(u16) data[6]));
1749 m_clients.event(peer_id, CSE_SetClientReady);
1750 m_script->on_joinplayer(playersao);
1753 else if(command == TOSERVER_GOTBLOCKS)
1766 u16 count = data[2];
1767 for(u16 i=0; i<count; i++)
1769 if((s16)datasize < 2+1+(i+1)*6)
1770 throw con::InvalidIncomingDataException
1771 ("GOTBLOCKS length is too short");
1772 v3s16 p = readV3S16(&data[2+1+i*6]);
1773 /*infostream<<"Server: GOTBLOCKS ("
1774 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1775 RemoteClient *client = getClient(peer_id);
1776 client->GotBlock(p);
1781 if (m_clients.getClientState(peer_id) < CS_Active)
1783 if (command == TOSERVER_PLAYERPOS) return;
1785 errorstream<<"Got packet command: " << command << " for peer id "
1786 << peer_id << " but client isn't active yet. Dropping packet "
1791 Player *player = m_env->getPlayer(peer_id);
1793 errorstream<<"Server::ProcessData(): Cancelling: "
1794 "No player for peer_id="<<peer_id
1799 PlayerSAO *playersao = player->getPlayerSAO();
1800 if(playersao == NULL){
1801 errorstream<<"Server::ProcessData(): Cancelling: "
1802 "No player object for peer_id="<<peer_id
1807 if(command == TOSERVER_PLAYERPOS)
1809 if(datasize < 2+12+12+4+4)
1813 v3s32 ps = readV3S32(&data[start+2]);
1814 v3s32 ss = readV3S32(&data[start+2+12]);
1815 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1816 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1818 if(datasize >= 2+12+12+4+4+4)
1819 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1820 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1821 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1822 pitch = wrapDegrees(pitch);
1823 yaw = wrapDegrees(yaw);
1825 player->setPosition(position);
1826 player->setSpeed(speed);
1827 player->setPitch(pitch);
1828 player->setYaw(yaw);
1829 player->keyPressed=keyPressed;
1830 player->control.up = (bool)(keyPressed&1);
1831 player->control.down = (bool)(keyPressed&2);
1832 player->control.left = (bool)(keyPressed&4);
1833 player->control.right = (bool)(keyPressed&8);
1834 player->control.jump = (bool)(keyPressed&16);
1835 player->control.aux1 = (bool)(keyPressed&32);
1836 player->control.sneak = (bool)(keyPressed&64);
1837 player->control.LMB = (bool)(keyPressed&128);
1838 player->control.RMB = (bool)(keyPressed&256);
1840 bool cheated = playersao->checkMovementCheat();
1843 m_script->on_cheat(playersao, "moved_too_fast");
1846 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1847 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1848 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1850 else if(command == TOSERVER_DELETEDBLOCKS)
1863 u16 count = data[2];
1864 for(u16 i=0; i<count; i++)
1866 if((s16)datasize < 2+1+(i+1)*6)
1867 throw con::InvalidIncomingDataException
1868 ("DELETEDBLOCKS length is too short");
1869 v3s16 p = readV3S16(&data[2+1+i*6]);
1870 /*infostream<<"Server: DELETEDBLOCKS ("
1871 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1872 RemoteClient *client = getClient(peer_id);
1873 client->SetBlockNotSent(p);
1876 else if(command == TOSERVER_CLICK_OBJECT)
1878 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1881 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1883 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1886 else if(command == TOSERVER_GROUND_ACTION)
1888 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1892 else if(command == TOSERVER_RELEASE)
1894 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1897 else if(command == TOSERVER_SIGNTEXT)
1899 infostream<<"Server: SIGNTEXT not supported anymore"
1903 else if(command == TOSERVER_SIGNNODETEXT)
1905 infostream<<"Server: SIGNNODETEXT not supported anymore"
1909 else if(command == TOSERVER_INVENTORY_ACTION)
1911 // Strip command and create a stream
1912 std::string datastring((char*)&data[2], datasize-2);
1913 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1914 std::istringstream is(datastring, std::ios_base::binary);
1916 InventoryAction *a = InventoryAction::deSerialize(is);
1919 infostream<<"TOSERVER_INVENTORY_ACTION: "
1920 <<"InventoryAction::deSerialize() returned NULL"
1925 // If something goes wrong, this player is to blame
1926 RollbackScopeActor rollback_scope(m_rollback,
1927 std::string("player:")+player->getName());
1930 Note: Always set inventory not sent, to repair cases
1931 where the client made a bad prediction.
1935 Handle restrictions and special cases of the move action
1937 if(a->getType() == IACTION_MOVE)
1939 IMoveAction *ma = (IMoveAction*)a;
1941 ma->from_inv.applyCurrentPlayer(player->getName());
1942 ma->to_inv.applyCurrentPlayer(player->getName());
1944 setInventoryModified(ma->from_inv);
1945 setInventoryModified(ma->to_inv);
1947 bool from_inv_is_current_player =
1948 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1949 (ma->from_inv.name == player->getName());
1951 bool to_inv_is_current_player =
1952 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1953 (ma->to_inv.name == player->getName());
1956 Disable moving items out of craftpreview
1958 if(ma->from_list == "craftpreview")
1960 infostream<<"Ignoring IMoveAction from "
1961 <<(ma->from_inv.dump())<<":"<<ma->from_list
1962 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1963 <<" because src is "<<ma->from_list<<std::endl;
1969 Disable moving items into craftresult and craftpreview
1971 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1973 infostream<<"Ignoring IMoveAction from "
1974 <<(ma->from_inv.dump())<<":"<<ma->from_list
1975 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1976 <<" because dst is "<<ma->to_list<<std::endl;
1981 // Disallow moving items in elsewhere than player's inventory
1982 // if not allowed to interact
1983 if(!checkPriv(player->getName(), "interact") &&
1984 (!from_inv_is_current_player ||
1985 !to_inv_is_current_player))
1987 infostream<<"Cannot move outside of player's inventory: "
1988 <<"No interact privilege"<<std::endl;
1994 Handle restrictions and special cases of the drop action
1996 else if(a->getType() == IACTION_DROP)
1998 IDropAction *da = (IDropAction*)a;
2000 da->from_inv.applyCurrentPlayer(player->getName());
2002 setInventoryModified(da->from_inv);
2005 Disable dropping items out of craftpreview
2007 if(da->from_list == "craftpreview")
2009 infostream<<"Ignoring IDropAction from "
2010 <<(da->from_inv.dump())<<":"<<da->from_list
2011 <<" because src is "<<da->from_list<<std::endl;
2016 // Disallow dropping items if not allowed to interact
2017 if(!checkPriv(player->getName(), "interact"))
2024 Handle restrictions and special cases of the craft action
2026 else if(a->getType() == IACTION_CRAFT)
2028 ICraftAction *ca = (ICraftAction*)a;
2030 ca->craft_inv.applyCurrentPlayer(player->getName());
2032 setInventoryModified(ca->craft_inv);
2034 //bool craft_inv_is_current_player =
2035 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2036 // (ca->craft_inv.name == player->getName());
2038 // Disallow crafting if not allowed to interact
2039 if(!checkPriv(player->getName(), "interact"))
2041 infostream<<"Cannot craft: "
2042 <<"No interact privilege"<<std::endl;
2049 a->apply(this, playersao, this);
2053 else if(command == TOSERVER_CHAT_MESSAGE)
2061 std::string datastring((char*)&data[2], datasize-2);
2062 std::istringstream is(datastring, std::ios_base::binary);
2065 is.read((char*)buf, 2);
2066 u16 len = readU16(buf);
2068 std::wstring message;
2069 for(u16 i=0; i<len; i++)
2071 is.read((char*)buf, 2);
2072 message += (wchar_t)readU16(buf);
2075 // If something goes wrong, this player is to blame
2076 RollbackScopeActor rollback_scope(m_rollback,
2077 std::string("player:")+player->getName());
2079 // Get player name of this client
2080 std::wstring name = narrow_to_wide(player->getName());
2083 bool ate = m_script->on_chat_message(player->getName(),
2084 wide_to_narrow(message));
2085 // If script ate the message, don't proceed
2089 // Line to send to players
2091 // Whether to send to the player that sent the line
2092 bool send_to_sender_only = false;
2094 // Commands are implemented in Lua, so only catch invalid
2095 // commands that were not "eaten" and send an error back
2096 if(message[0] == L'/')
2098 message = message.substr(1);
2099 send_to_sender_only = true;
2100 if(message.length() == 0)
2101 line += L"-!- Empty command";
2103 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2107 if(checkPriv(player->getName(), "shout")){
2113 line += L"-!- You don't have permission to shout.";
2114 send_to_sender_only = true;
2121 Send the message to sender
2123 if (send_to_sender_only)
2125 SendChatMessage(peer_id, line);
2128 Send the message to others
2132 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2134 std::list<u16> clients = m_clients.getClientIDs();
2136 for(std::list<u16>::iterator
2137 i = clients.begin();
2138 i != clients.end(); ++i)
2141 SendChatMessage(*i, line);
2146 else if(command == TOSERVER_DAMAGE)
2148 std::string datastring((char*)&data[2], datasize-2);
2149 std::istringstream is(datastring, std::ios_base::binary);
2150 u8 damage = readU8(is);
2152 if(g_settings->getBool("enable_damage"))
2154 actionstream<<player->getName()<<" damaged by "
2155 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2158 playersao->setHP(playersao->getHP() - damage);
2160 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2163 if(playersao->m_hp_not_sent)
2164 SendPlayerHP(peer_id);
2167 else if(command == TOSERVER_BREATH)
2169 std::string datastring((char*)&data[2], datasize-2);
2170 std::istringstream is(datastring, std::ios_base::binary);
2171 u16 breath = readU16(is);
2172 playersao->setBreath(breath);
2173 m_script->player_event(playersao,"breath_changed");
2175 else if(command == TOSERVER_PASSWORD)
2178 [0] u16 TOSERVER_PASSWORD
2179 [2] u8[28] old password
2180 [30] u8[28] new password
2183 if(datasize != 2+PASSWORD_SIZE*2)
2185 /*char password[PASSWORD_SIZE];
2186 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2187 password[i] = data[2+i];
2188 password[PASSWORD_SIZE-1] = 0;*/
2190 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2198 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2200 char c = data[2+PASSWORD_SIZE+i];
2206 if(!base64_is_valid(newpwd)){
2207 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2208 // Wrong old password supplied!!
2209 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2213 infostream<<"Server: Client requests a password change from "
2214 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2216 std::string playername = player->getName();
2218 std::string checkpwd;
2219 m_script->getAuth(playername, &checkpwd, NULL);
2221 if(oldpwd != checkpwd)
2223 infostream<<"Server: invalid old password"<<std::endl;
2224 // Wrong old password supplied!!
2225 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2229 bool success = m_script->setPassword(playername, newpwd);
2231 actionstream<<player->getName()<<" changes password"<<std::endl;
2232 SendChatMessage(peer_id, L"Password change successful.");
2234 actionstream<<player->getName()<<" tries to change password but "
2235 <<"it fails"<<std::endl;
2236 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2239 else if(command == TOSERVER_PLAYERITEM)
2244 u16 item = readU16(&data[2]);
2245 playersao->setWieldIndex(item);
2247 else if(command == TOSERVER_RESPAWN)
2249 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2252 RespawnPlayer(peer_id);
2254 actionstream<<player->getName()<<" respawns at "
2255 <<PP(player->getPosition()/BS)<<std::endl;
2257 // ActiveObject is added to environment in AsyncRunStep after
2258 // the previous addition has been succesfully removed
2260 else if(command == TOSERVER_INTERACT)
2262 std::string datastring((char*)&data[2], datasize-2);
2263 std::istringstream is(datastring, std::ios_base::binary);
2269 [5] u32 length of the next item
2270 [9] serialized PointedThing
2272 0: start digging (from undersurface) or use
2273 1: stop digging (all parameters ignored)
2274 2: digging completed
2275 3: place block or item (to abovesurface)
2278 u8 action = readU8(is);
2279 u16 item_i = readU16(is);
2280 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2281 PointedThing pointed;
2282 pointed.deSerialize(tmp_is);
2284 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2285 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2289 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2290 <<" tried to interact, but is dead!"<<std::endl;
2294 v3f player_pos = playersao->getLastGoodPosition();
2296 // Update wielded item
2297 playersao->setWieldIndex(item_i);
2299 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2300 v3s16 p_under = pointed.node_undersurface;
2301 v3s16 p_above = pointed.node_abovesurface;
2303 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2304 ServerActiveObject *pointed_object = NULL;
2305 if(pointed.type == POINTEDTHING_OBJECT)
2307 pointed_object = m_env->getActiveObject(pointed.object_id);
2308 if(pointed_object == NULL)
2310 verbosestream<<"TOSERVER_INTERACT: "
2311 "pointed object is NULL"<<std::endl;
2317 v3f pointed_pos_under = player_pos;
2318 v3f pointed_pos_above = player_pos;
2319 if(pointed.type == POINTEDTHING_NODE)
2321 pointed_pos_under = intToFloat(p_under, BS);
2322 pointed_pos_above = intToFloat(p_above, BS);
2324 else if(pointed.type == POINTEDTHING_OBJECT)
2326 pointed_pos_under = pointed_object->getBasePosition();
2327 pointed_pos_above = pointed_pos_under;
2331 Check that target is reasonably close
2332 (only when digging or placing things)
2334 if(action == 0 || action == 2 || action == 3)
2336 float d = player_pos.getDistanceFrom(pointed_pos_under);
2337 float max_d = BS * 14; // Just some large enough value
2339 actionstream<<"Player "<<player->getName()
2340 <<" tried to access "<<pointed.dump()
2342 <<"d="<<d<<", max_d="<<max_d
2343 <<". ignoring."<<std::endl;
2344 // Re-send block to revert change on client-side
2345 RemoteClient *client = getClient(peer_id);
2346 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2347 client->SetBlockNotSent(blockpos);
2349 m_script->on_cheat(playersao, "interacted_too_far");
2356 Make sure the player is allowed to do it
2358 if(!checkPriv(player->getName(), "interact"))
2360 actionstream<<player->getName()<<" attempted to interact with "
2361 <<pointed.dump()<<" without 'interact' privilege"
2363 // Re-send block to revert change on client-side
2364 RemoteClient *client = getClient(peer_id);
2365 // Digging completed -> under
2367 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2368 client->SetBlockNotSent(blockpos);
2370 // Placement -> above
2372 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2373 client->SetBlockNotSent(blockpos);
2379 If something goes wrong, this player is to blame
2381 RollbackScopeActor rollback_scope(m_rollback,
2382 std::string("player:")+player->getName());
2385 0: start digging or punch object
2389 if(pointed.type == POINTEDTHING_NODE)
2392 NOTE: This can be used in the future to check if
2393 somebody is cheating, by checking the timing.
2395 MapNode n(CONTENT_IGNORE);
2398 n = m_env->getMap().getNode(p_under);
2400 catch(InvalidPositionException &e)
2402 infostream<<"Server: Not punching: Node not found."
2403 <<" Adding block to emerge queue."
2405 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2407 if(n.getContent() != CONTENT_IGNORE)
2408 m_script->node_on_punch(p_under, n, playersao, pointed);
2410 playersao->noCheatDigStart(p_under);
2412 else if(pointed.type == POINTEDTHING_OBJECT)
2414 // Skip if object has been removed
2415 if(pointed_object->m_removed)
2418 actionstream<<player->getName()<<" punches object "
2419 <<pointed.object_id<<": "
2420 <<pointed_object->getDescription()<<std::endl;
2422 ItemStack punchitem = playersao->getWieldedItem();
2423 ToolCapabilities toolcap =
2424 punchitem.getToolCapabilities(m_itemdef);
2425 v3f dir = (pointed_object->getBasePosition() -
2426 (player->getPosition() + player->getEyeOffset())
2428 float time_from_last_punch =
2429 playersao->resetTimeFromLastPunch();
2430 pointed_object->punch(dir, &toolcap, playersao,
2431 time_from_last_punch);
2439 else if(action == 1)
2444 2: Digging completed
2446 else if(action == 2)
2448 // Only digging of nodes
2449 if(pointed.type == POINTEDTHING_NODE)
2451 MapNode n(CONTENT_IGNORE);
2454 n = m_env->getMap().getNode(p_under);
2456 catch(InvalidPositionException &e)
2458 infostream<<"Server: Not finishing digging: Node not found."
2459 <<" Adding block to emerge queue."
2461 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2464 /* Cheat prevention */
2465 bool is_valid_dig = true;
2466 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2468 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2469 float nocheat_t = playersao->getNoCheatDigTime();
2470 playersao->noCheatDigEnd();
2471 // If player didn't start digging this, ignore dig
2472 if(nocheat_p != p_under){
2473 infostream<<"Server: NoCheat: "<<player->getName()
2474 <<" started digging "
2475 <<PP(nocheat_p)<<" and completed digging "
2476 <<PP(p_under)<<"; not digging."<<std::endl;
2477 is_valid_dig = false;
2479 m_script->on_cheat(playersao, "finished_unknown_dig");
2481 // Get player's wielded item
2482 ItemStack playeritem;
2483 InventoryList *mlist = playersao->getInventory()->getList("main");
2485 playeritem = mlist->getItem(playersao->getWieldIndex());
2486 ToolCapabilities playeritem_toolcap =
2487 playeritem.getToolCapabilities(m_itemdef);
2488 // Get diggability and expected digging time
2489 DigParams params = getDigParams(m_nodedef->get(n).groups,
2490 &playeritem_toolcap);
2491 // If can't dig, try hand
2492 if(!params.diggable){
2493 const ItemDefinition &hand = m_itemdef->get("");
2494 const ToolCapabilities *tp = hand.tool_capabilities;
2496 params = getDigParams(m_nodedef->get(n).groups, tp);
2498 // If can't dig, ignore dig
2499 if(!params.diggable){
2500 infostream<<"Server: NoCheat: "<<player->getName()
2501 <<" completed digging "<<PP(p_under)
2502 <<", which is not diggable with tool. not digging."
2504 is_valid_dig = false;
2506 m_script->on_cheat(playersao, "dug_unbreakable");
2508 // Check digging time
2509 // If already invalidated, we don't have to
2511 // Well not our problem then
2513 // Clean and long dig
2514 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2515 // All is good, but grab time from pool; don't care if
2516 // it's actually available
2517 playersao->getDigPool().grab(params.time);
2519 // Short or laggy dig
2520 // Try getting the time from pool
2521 else if(playersao->getDigPool().grab(params.time)){
2526 infostream<<"Server: NoCheat: "<<player->getName()
2527 <<" completed digging "<<PP(p_under)
2528 <<"too fast; not digging."<<std::endl;
2529 is_valid_dig = false;
2531 m_script->on_cheat(playersao, "dug_too_fast");
2535 /* Actually dig node */
2537 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2538 m_script->node_on_dig(p_under, n, playersao);
2540 // Send unusual result (that is, node not being removed)
2541 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2543 // Re-send block to revert change on client-side
2544 RemoteClient *client = getClient(peer_id);
2545 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2546 client->SetBlockNotSent(blockpos);
2552 3: place block or right-click object
2554 else if(action == 3)
2556 ItemStack item = playersao->getWieldedItem();
2558 // Reset build time counter
2559 if(pointed.type == POINTEDTHING_NODE &&
2560 item.getDefinition(m_itemdef).type == ITEM_NODE)
2561 getClient(peer_id)->m_time_from_building = 0.0;
2563 if(pointed.type == POINTEDTHING_OBJECT)
2565 // Right click object
2567 // Skip if object has been removed
2568 if(pointed_object->m_removed)
2571 actionstream<<player->getName()<<" right-clicks object "
2572 <<pointed.object_id<<": "
2573 <<pointed_object->getDescription()<<std::endl;
2576 pointed_object->rightClick(playersao);
2578 else if(m_script->item_OnPlace(
2579 item, playersao, pointed))
2581 // Placement was handled in lua
2583 // Apply returned ItemStack
2584 playersao->setWieldedItem(item);
2587 // If item has node placement prediction, always send the
2588 // blocks to make sure the client knows what exactly happened
2589 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2590 RemoteClient *client = getClient(peer_id);
2591 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2592 client->SetBlockNotSent(blockpos);
2593 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2594 if(blockpos2 != blockpos){
2595 client->SetBlockNotSent(blockpos2);
2603 else if(action == 4)
2605 ItemStack item = playersao->getWieldedItem();
2607 actionstream<<player->getName()<<" uses "<<item.name
2608 <<", pointing at "<<pointed.dump()<<std::endl;
2610 if(m_script->item_OnUse(
2611 item, playersao, pointed))
2613 // Apply returned ItemStack
2614 playersao->setWieldedItem(item);
2621 Catch invalid actions
2625 infostream<<"WARNING: Server: Invalid action "
2626 <<action<<std::endl;
2629 else if(command == TOSERVER_REMOVED_SOUNDS)
2631 std::string datastring((char*)&data[2], datasize-2);
2632 std::istringstream is(datastring, std::ios_base::binary);
2634 int num = readU16(is);
2635 for(int k=0; k<num; k++){
2636 s32 id = readS32(is);
2637 std::map<s32, ServerPlayingSound>::iterator i =
2638 m_playing_sounds.find(id);
2639 if(i == m_playing_sounds.end())
2641 ServerPlayingSound &psound = i->second;
2642 psound.clients.erase(peer_id);
2643 if(psound.clients.size() == 0)
2644 m_playing_sounds.erase(i++);
2647 else if(command == TOSERVER_NODEMETA_FIELDS)
2649 std::string datastring((char*)&data[2], datasize-2);
2650 std::istringstream is(datastring, std::ios_base::binary);
2652 v3s16 p = readV3S16(is);
2653 std::string formname = deSerializeString(is);
2654 int num = readU16(is);
2655 std::map<std::string, std::string> fields;
2656 for(int k=0; k<num; k++){
2657 std::string fieldname = deSerializeString(is);
2658 std::string fieldvalue = deSerializeLongString(is);
2659 fields[fieldname] = fieldvalue;
2662 // If something goes wrong, this player is to blame
2663 RollbackScopeActor rollback_scope(m_rollback,
2664 std::string("player:")+player->getName());
2666 // Check the target node for rollback data; leave others unnoticed
2667 RollbackNode rn_old(&m_env->getMap(), p, this);
2669 m_script->node_on_receive_fields(p, formname, fields,playersao);
2671 // Report rollback data
2672 RollbackNode rn_new(&m_env->getMap(), p, this);
2673 if(rollback() && rn_new != rn_old){
2674 RollbackAction action;
2675 action.setSetNode(p, rn_old, rn_new);
2676 rollback()->reportAction(action);
2679 else if(command == TOSERVER_INVENTORY_FIELDS)
2681 std::string datastring((char*)&data[2], datasize-2);
2682 std::istringstream is(datastring, std::ios_base::binary);
2684 std::string formname = deSerializeString(is);
2685 int num = readU16(is);
2686 std::map<std::string, std::string> fields;
2687 for(int k=0; k<num; k++){
2688 std::string fieldname = deSerializeString(is);
2689 std::string fieldvalue = deSerializeLongString(is);
2690 fields[fieldname] = fieldvalue;
2693 m_script->on_playerReceiveFields(playersao, formname, fields);
2697 infostream<<"Server::ProcessData(): Ignoring "
2698 "unknown command "<<command<<std::endl;
2702 catch(SendFailedException &e)
2704 errorstream<<"Server::ProcessData(): SendFailedException: "
2710 void Server::setTimeOfDay(u32 time)
2712 m_env->setTimeOfDay(time);
2713 m_time_of_day_send_timer = 0;
2716 void Server::onMapEditEvent(MapEditEvent *event)
2718 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2719 if(m_ignore_map_edit_events)
2721 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2723 MapEditEvent *e = event->clone();
2724 m_unsent_map_edit_queue.push_back(e);
2727 Inventory* Server::getInventory(const InventoryLocation &loc)
2730 case InventoryLocation::UNDEFINED:
2733 case InventoryLocation::CURRENT_PLAYER:
2736 case InventoryLocation::PLAYER:
2738 Player *player = m_env->getPlayer(loc.name.c_str());
2741 PlayerSAO *playersao = player->getPlayerSAO();
2744 return playersao->getInventory();
2747 case InventoryLocation::NODEMETA:
2749 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2752 return meta->getInventory();
2755 case InventoryLocation::DETACHED:
2757 if(m_detached_inventories.count(loc.name) == 0)
2759 return m_detached_inventories[loc.name];
2767 void Server::setInventoryModified(const InventoryLocation &loc)
2770 case InventoryLocation::UNDEFINED:
2773 case InventoryLocation::PLAYER:
2775 Player *player = m_env->getPlayer(loc.name.c_str());
2778 PlayerSAO *playersao = player->getPlayerSAO();
2781 playersao->m_inventory_not_sent = true;
2782 playersao->m_wielded_item_not_sent = true;
2785 case InventoryLocation::NODEMETA:
2787 v3s16 blockpos = getNodeBlockPos(loc.p);
2789 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2791 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2793 setBlockNotSent(blockpos);
2796 case InventoryLocation::DETACHED:
2798 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2806 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2808 std::list<u16> clients = m_clients.getClientIDs();
2810 // Set the modified blocks unsent for all the clients
2811 for (std::list<u16>::iterator
2812 i = clients.begin();
2813 i != clients.end(); ++i) {
2814 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2816 client->SetBlocksNotSent(block);
2821 void Server::peerAdded(con::Peer *peer)
2823 DSTACK(__FUNCTION_NAME);
2824 verbosestream<<"Server::peerAdded(): peer->id="
2825 <<peer->id<<std::endl;
2828 c.type = con::PEER_ADDED;
2829 c.peer_id = peer->id;
2831 m_peer_change_queue.push_back(c);
2834 void Server::deletingPeer(con::Peer *peer, bool timeout)
2836 DSTACK(__FUNCTION_NAME);
2837 verbosestream<<"Server::deletingPeer(): peer->id="
2838 <<peer->id<<", timeout="<<timeout<<std::endl;
2840 m_clients.event(peer->id, CSE_Disconnect);
2842 c.type = con::PEER_REMOVED;
2843 c.peer_id = peer->id;
2844 c.timeout = timeout;
2845 m_peer_change_queue.push_back(c);
2848 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2850 *retval = m_con.getPeerStat(peer_id,type);
2851 if (*retval == -1) return false;
2855 bool Server::getClientInfo(
2864 std::string* vers_string
2867 *state = m_clients.getClientState(peer_id);
2869 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2871 if (client == NULL) {
2876 *uptime = client->uptime();
2877 *ser_vers = client->serialization_version;
2878 *prot_vers = client->net_proto_version;
2880 *major = client->getMajor();
2881 *minor = client->getMinor();
2882 *patch = client->getPatch();
2883 *vers_string = client->getPatch();
2890 void Server::handlePeerChanges()
2892 while(m_peer_change_queue.size() > 0)
2894 con::PeerChange c = m_peer_change_queue.pop_front();
2896 verbosestream<<"Server: Handling peer change: "
2897 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2902 case con::PEER_ADDED:
2903 m_clients.CreateClient(c.peer_id);
2906 case con::PEER_REMOVED:
2907 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2911 assert("Invalid peer change event received!" == 0);
2917 void Server::SendMovement(u16 peer_id)
2919 DSTACK(__FUNCTION_NAME);
2920 std::ostringstream os(std::ios_base::binary);
2922 writeU16(os, TOCLIENT_MOVEMENT);
2923 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2924 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2925 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2926 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2927 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2928 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2929 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2930 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2931 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2932 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2933 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2934 writeF1000(os, g_settings->getFloat("movement_gravity"));
2937 std::string s = os.str();
2938 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2940 m_clients.send(peer_id, 0, data, true);
2943 void Server::SendHP(u16 peer_id, u8 hp)
2945 DSTACK(__FUNCTION_NAME);
2946 std::ostringstream os(std::ios_base::binary);
2948 writeU16(os, TOCLIENT_HP);
2952 std::string s = os.str();
2953 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2955 m_clients.send(peer_id, 0, data, true);
2958 void Server::SendBreath(u16 peer_id, u16 breath)
2960 DSTACK(__FUNCTION_NAME);
2961 std::ostringstream os(std::ios_base::binary);
2963 writeU16(os, TOCLIENT_BREATH);
2964 writeU16(os, breath);
2967 std::string s = os.str();
2968 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2970 m_clients.send(peer_id, 0, data, true);
2973 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2975 DSTACK(__FUNCTION_NAME);
2976 std::ostringstream os(std::ios_base::binary);
2978 writeU16(os, TOCLIENT_ACCESS_DENIED);
2979 os<<serializeWideString(reason);
2982 std::string s = os.str();
2983 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2985 m_clients.send(peer_id, 0, data, true);
2988 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
2989 v3f camera_point_target)
2991 DSTACK(__FUNCTION_NAME);
2992 std::ostringstream os(std::ios_base::binary);
2994 writeU16(os, TOCLIENT_DEATHSCREEN);
2995 writeU8(os, set_camera_point_target);
2996 writeV3F1000(os, camera_point_target);
2999 std::string s = os.str();
3000 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3002 m_clients.send(peer_id, 0, data, true);
3005 void Server::SendItemDef(u16 peer_id,
3006 IItemDefManager *itemdef, u16 protocol_version)
3008 DSTACK(__FUNCTION_NAME);
3009 std::ostringstream os(std::ios_base::binary);
3013 u32 length of the next item
3014 zlib-compressed serialized ItemDefManager
3016 writeU16(os, TOCLIENT_ITEMDEF);
3017 std::ostringstream tmp_os(std::ios::binary);
3018 itemdef->serialize(tmp_os, protocol_version);
3019 std::ostringstream tmp_os2(std::ios::binary);
3020 compressZlib(tmp_os.str(), tmp_os2);
3021 os<<serializeLongString(tmp_os2.str());
3024 std::string s = os.str();
3025 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3026 <<"): size="<<s.size()<<std::endl;
3027 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3029 m_clients.send(peer_id, 0, data, true);
3032 void Server::SendNodeDef(u16 peer_id,
3033 INodeDefManager *nodedef, u16 protocol_version)
3035 DSTACK(__FUNCTION_NAME);
3036 std::ostringstream os(std::ios_base::binary);
3040 u32 length of the next item
3041 zlib-compressed serialized NodeDefManager
3043 writeU16(os, TOCLIENT_NODEDEF);
3044 std::ostringstream tmp_os(std::ios::binary);
3045 nodedef->serialize(tmp_os, protocol_version);
3046 std::ostringstream tmp_os2(std::ios::binary);
3047 compressZlib(tmp_os.str(), tmp_os2);
3048 os<<serializeLongString(tmp_os2.str());
3051 std::string s = os.str();
3052 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3053 <<"): size="<<s.size()<<std::endl;
3054 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3056 m_clients.send(peer_id, 0, data, true);
3060 Non-static send methods
3063 void Server::SendInventory(u16 peer_id)
3065 DSTACK(__FUNCTION_NAME);
3067 PlayerSAO *playersao = getPlayerSAO(peer_id);
3070 playersao->m_inventory_not_sent = false;
3076 std::ostringstream os;
3077 playersao->getInventory()->serialize(os);
3079 std::string s = os.str();
3081 SharedBuffer<u8> data(s.size()+2);
3082 writeU16(&data[0], TOCLIENT_INVENTORY);
3083 memcpy(&data[2], s.c_str(), s.size());
3086 m_clients.send(peer_id, 0, data, true);
3089 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3091 DSTACK(__FUNCTION_NAME);
3093 std::ostringstream os(std::ios_base::binary);
3097 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3098 os.write((char*)buf, 2);
3101 writeU16(buf, message.size());
3102 os.write((char*)buf, 2);
3105 for(u32 i=0; i<message.size(); i++)
3109 os.write((char*)buf, 2);
3113 std::string s = os.str();
3114 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3116 if (peer_id != PEER_ID_INEXISTENT)
3119 m_clients.send(peer_id, 0, data, true);
3123 m_clients.sendToAll(0,data,true);
3127 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3128 const std::string &formname)
3130 DSTACK(__FUNCTION_NAME);
3132 std::ostringstream os(std::ios_base::binary);
3137 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3138 os.write((char*)buf, 2);
3139 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3140 os<<serializeString(formname);
3143 std::string s = os.str();
3144 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3146 m_clients.send(peer_id, 0, data, true);
3149 // Spawns a particle on peer with peer_id
3150 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3151 float expirationtime, float size, bool collisiondetection,
3152 bool vertical, std::string texture)
3154 DSTACK(__FUNCTION_NAME);
3156 std::ostringstream os(std::ios_base::binary);
3157 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3158 writeV3F1000(os, pos);
3159 writeV3F1000(os, velocity);
3160 writeV3F1000(os, acceleration);
3161 writeF1000(os, expirationtime);
3162 writeF1000(os, size);
3163 writeU8(os, collisiondetection);
3164 os<<serializeLongString(texture);
3165 writeU8(os, vertical);
3168 std::string s = os.str();
3169 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3171 if (peer_id != PEER_ID_INEXISTENT)
3174 m_clients.send(peer_id, 0, data, true);
3178 m_clients.sendToAll(0,data,true);
3182 // Adds a ParticleSpawner on peer with peer_id
3183 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3184 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3185 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3187 DSTACK(__FUNCTION_NAME);
3189 std::ostringstream os(std::ios_base::binary);
3190 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3192 writeU16(os, amount);
3193 writeF1000(os, spawntime);
3194 writeV3F1000(os, minpos);
3195 writeV3F1000(os, maxpos);
3196 writeV3F1000(os, minvel);
3197 writeV3F1000(os, maxvel);
3198 writeV3F1000(os, minacc);
3199 writeV3F1000(os, maxacc);
3200 writeF1000(os, minexptime);
3201 writeF1000(os, maxexptime);
3202 writeF1000(os, minsize);
3203 writeF1000(os, maxsize);
3204 writeU8(os, collisiondetection);
3205 os<<serializeLongString(texture);
3207 writeU8(os, vertical);
3210 std::string s = os.str();
3211 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3213 if (peer_id != PEER_ID_INEXISTENT)
3216 m_clients.send(peer_id, 0, data, true);
3219 m_clients.sendToAll(0,data,true);
3223 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3225 DSTACK(__FUNCTION_NAME);
3227 std::ostringstream os(std::ios_base::binary);
3228 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3233 std::string s = os.str();
3234 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3236 if (peer_id != PEER_ID_INEXISTENT) {
3238 m_clients.send(peer_id, 0, data, true);
3241 m_clients.sendToAll(0,data,true);
3246 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3248 std::ostringstream os(std::ios_base::binary);
3251 writeU16(os, TOCLIENT_HUDADD);
3253 writeU8(os, (u8)form->type);
3254 writeV2F1000(os, form->pos);
3255 os << serializeString(form->name);
3256 writeV2F1000(os, form->scale);
3257 os << serializeString(form->text);
3258 writeU32(os, form->number);
3259 writeU32(os, form->item);
3260 writeU32(os, form->dir);
3261 writeV2F1000(os, form->align);
3262 writeV2F1000(os, form->offset);
3263 writeV3F1000(os, form->world_pos);
3264 writeV2S32(os,form->size);
3267 std::string s = os.str();
3268 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3270 m_clients.send(peer_id, 1, data, true);
3273 void Server::SendHUDRemove(u16 peer_id, u32 id)
3275 std::ostringstream os(std::ios_base::binary);
3278 writeU16(os, TOCLIENT_HUDRM);
3282 std::string s = os.str();
3283 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3286 m_clients.send(peer_id, 1, data, true);
3289 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3291 std::ostringstream os(std::ios_base::binary);
3294 writeU16(os, TOCLIENT_HUDCHANGE);
3296 writeU8(os, (u8)stat);
3299 case HUD_STAT_SCALE:
3300 case HUD_STAT_ALIGN:
3301 case HUD_STAT_OFFSET:
3302 writeV2F1000(os, *(v2f *)value);
3306 os << serializeString(*(std::string *)value);
3308 case HUD_STAT_WORLD_POS:
3309 writeV3F1000(os, *(v3f *)value);
3312 writeV2S32(os,*(v2s32 *)value);
3314 case HUD_STAT_NUMBER:
3318 writeU32(os, *(u32 *)value);
3323 std::string s = os.str();
3324 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3326 m_clients.send(peer_id, 0, data, true);
3329 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3331 std::ostringstream os(std::ios_base::binary);
3334 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3336 //////////////////////////// compatibility code to be removed //////////////
3337 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3338 ////////////////////////////////////////////////////////////////////////////
3339 writeU32(os, flags);
3343 std::string s = os.str();
3344 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3346 m_clients.send(peer_id, 0, data, true);
3349 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3351 std::ostringstream os(std::ios_base::binary);
3354 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3355 writeU16(os, param);
3356 os<<serializeString(value);
3359 std::string s = os.str();
3360 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3362 m_clients.send(peer_id, 0, data, true);
3365 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3366 const std::string &type, const std::vector<std::string> ¶ms)
3368 std::ostringstream os(std::ios_base::binary);
3371 writeU16(os, TOCLIENT_SET_SKY);
3372 writeARGB8(os, bgcolor);
3373 os<<serializeString(type);
3374 writeU16(os, params.size());
3375 for(size_t i=0; i<params.size(); i++)
3376 os<<serializeString(params[i]);
3379 std::string s = os.str();
3380 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3382 m_clients.send(peer_id, 0, data, true);
3385 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3388 std::ostringstream os(std::ios_base::binary);
3391 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3392 writeU8(os, do_override);
3393 writeU16(os, ratio*65535);
3396 std::string s = os.str();
3397 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3399 m_clients.send(peer_id, 0, data, true);
3402 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3404 DSTACK(__FUNCTION_NAME);
3407 SharedBuffer<u8> data(2+2+4);
3408 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3409 writeU16(&data[2], time);
3410 writeF1000(&data[4], time_speed);
3412 if (peer_id == PEER_ID_INEXISTENT) {
3413 m_clients.sendToAll(0,data,true);
3417 m_clients.send(peer_id, 0, data, true);
3421 void Server::SendPlayerHP(u16 peer_id)
3423 DSTACK(__FUNCTION_NAME);
3424 PlayerSAO *playersao = getPlayerSAO(peer_id);
3426 playersao->m_hp_not_sent = false;
3427 SendHP(peer_id, playersao->getHP());
3428 m_script->player_event(playersao,"health_changed");
3430 // Send to other clients
3431 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3432 ActiveObjectMessage aom(playersao->getId(), true, str);
3433 playersao->m_messages_out.push_back(aom);
3436 void Server::SendPlayerBreath(u16 peer_id)
3438 DSTACK(__FUNCTION_NAME);
3439 PlayerSAO *playersao = getPlayerSAO(peer_id);
3441 playersao->m_breath_not_sent = false;
3442 m_script->player_event(playersao,"breath_changed");
3443 SendBreath(peer_id, playersao->getBreath());
3446 void Server::SendMovePlayer(u16 peer_id)
3448 DSTACK(__FUNCTION_NAME);
3449 Player *player = m_env->getPlayer(peer_id);
3452 std::ostringstream os(std::ios_base::binary);
3453 writeU16(os, TOCLIENT_MOVE_PLAYER);
3454 writeV3F1000(os, player->getPosition());
3455 writeF1000(os, player->getPitch());
3456 writeF1000(os, player->getYaw());
3459 v3f pos = player->getPosition();
3460 f32 pitch = player->getPitch();
3461 f32 yaw = player->getYaw();
3462 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3463 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3470 std::string s = os.str();
3471 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3473 m_clients.send(peer_id, 0, data, true);
3476 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3478 std::ostringstream os(std::ios_base::binary);
3480 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3481 writeV2S32(os, animation_frames[0]);
3482 writeV2S32(os, animation_frames[1]);
3483 writeV2S32(os, animation_frames[2]);
3484 writeV2S32(os, animation_frames[3]);
3485 writeF1000(os, animation_speed);
3488 std::string s = os.str();
3489 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3491 m_clients.send(peer_id, 0, data, true);
3494 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3496 std::ostringstream os(std::ios_base::binary);
3498 writeU16(os, TOCLIENT_EYE_OFFSET);
3499 writeV3F1000(os, first);
3500 writeV3F1000(os, third);
3503 std::string s = os.str();
3504 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3506 m_clients.send(peer_id, 0, data, true);
3508 void Server::SendPlayerPrivileges(u16 peer_id)
3510 Player *player = m_env->getPlayer(peer_id);
3512 if(player->peer_id == PEER_ID_INEXISTENT)
3515 std::set<std::string> privs;
3516 m_script->getAuth(player->getName(), NULL, &privs);
3518 std::ostringstream os(std::ios_base::binary);
3519 writeU16(os, TOCLIENT_PRIVILEGES);
3520 writeU16(os, privs.size());
3521 for(std::set<std::string>::const_iterator i = privs.begin();
3522 i != privs.end(); i++){
3523 os<<serializeString(*i);
3527 std::string s = os.str();
3528 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3530 m_clients.send(peer_id, 0, data, true);
3533 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3535 Player *player = m_env->getPlayer(peer_id);
3537 if(player->peer_id == PEER_ID_INEXISTENT)
3540 std::ostringstream os(std::ios_base::binary);
3541 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3542 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3545 std::string s = os.str();
3546 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3548 m_clients.send(peer_id, 0, data, true);
3551 s32 Server::playSound(const SimpleSoundSpec &spec,
3552 const ServerSoundParams ¶ms)
3554 // Find out initial position of sound
3555 bool pos_exists = false;
3556 v3f pos = params.getPos(m_env, &pos_exists);
3557 // If position is not found while it should be, cancel sound
3558 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3561 // Filter destination clients
3562 std::list<u16> dst_clients;
3563 if(params.to_player != "")
3565 Player *player = m_env->getPlayer(params.to_player.c_str());
3567 infostream<<"Server::playSound: Player \""<<params.to_player
3568 <<"\" not found"<<std::endl;
3571 if(player->peer_id == PEER_ID_INEXISTENT){
3572 infostream<<"Server::playSound: Player \""<<params.to_player
3573 <<"\" not connected"<<std::endl;
3576 dst_clients.push_back(player->peer_id);
3580 std::list<u16> clients = m_clients.getClientIDs();
3582 for(std::list<u16>::iterator
3583 i = clients.begin(); i != clients.end(); ++i)
3585 Player *player = m_env->getPlayer(*i);
3589 if(player->getPosition().getDistanceFrom(pos) >
3590 params.max_hear_distance)
3593 dst_clients.push_back(*i);
3596 if(dst_clients.size() == 0)
3600 s32 id = m_next_sound_id++;
3601 // The sound will exist as a reference in m_playing_sounds
3602 m_playing_sounds[id] = ServerPlayingSound();
3603 ServerPlayingSound &psound = m_playing_sounds[id];
3604 psound.params = params;
3605 for(std::list<u16>::iterator i = dst_clients.begin();
3606 i != dst_clients.end(); i++)
3607 psound.clients.insert(*i);
3609 std::ostringstream os(std::ios_base::binary);
3610 writeU16(os, TOCLIENT_PLAY_SOUND);
3612 os<<serializeString(spec.name);
3613 writeF1000(os, spec.gain * params.gain);
3614 writeU8(os, params.type);
3615 writeV3F1000(os, pos);
3616 writeU16(os, params.object);
3617 writeU8(os, params.loop);
3619 std::string s = os.str();
3620 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3622 for(std::list<u16>::iterator i = dst_clients.begin();
3623 i != dst_clients.end(); i++){
3625 m_clients.send(*i, 0, data, true);
3629 void Server::stopSound(s32 handle)
3631 // Get sound reference
3632 std::map<s32, ServerPlayingSound>::iterator i =
3633 m_playing_sounds.find(handle);
3634 if(i == m_playing_sounds.end())
3636 ServerPlayingSound &psound = i->second;
3638 std::ostringstream os(std::ios_base::binary);
3639 writeU16(os, TOCLIENT_STOP_SOUND);
3640 writeS32(os, handle);
3642 std::string s = os.str();
3643 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3645 for(std::set<u16>::iterator i = psound.clients.begin();
3646 i != psound.clients.end(); i++){
3648 m_clients.send(*i, 0, data, true);
3650 // Remove sound reference
3651 m_playing_sounds.erase(i);
3654 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3655 std::list<u16> *far_players, float far_d_nodes)
3657 float maxd = far_d_nodes*BS;
3658 v3f p_f = intToFloat(p, BS);
3662 SharedBuffer<u8> reply(replysize);
3663 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3664 writeS16(&reply[2], p.X);
3665 writeS16(&reply[4], p.Y);
3666 writeS16(&reply[6], p.Z);
3668 std::list<u16> clients = m_clients.getClientIDs();
3669 for(std::list<u16>::iterator
3670 i = clients.begin();
3671 i != clients.end(); ++i)
3676 Player *player = m_env->getPlayer(*i);
3679 // If player is far away, only set modified blocks not sent
3680 v3f player_pos = player->getPosition();
3681 if(player_pos.getDistanceFrom(p_f) > maxd)
3683 far_players->push_back(*i);
3690 m_clients.send(*i, 0, reply, true);
3694 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3695 std::list<u16> *far_players, float far_d_nodes,
3696 bool remove_metadata)
3698 float maxd = far_d_nodes*BS;
3699 v3f p_f = intToFloat(p, BS);
3701 std::list<u16> clients = m_clients.getClientIDs();
3702 for(std::list<u16>::iterator
3703 i = clients.begin();
3704 i != clients.end(); ++i)
3710 Player *player = m_env->getPlayer(*i);
3713 // If player is far away, only set modified blocks not sent
3714 v3f player_pos = player->getPosition();
3715 if(player_pos.getDistanceFrom(p_f) > maxd)
3717 far_players->push_back(*i);
3722 SharedBuffer<u8> reply(0);
3724 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3728 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3729 reply = SharedBuffer<u8>(replysize);
3730 writeU16(&reply[0], TOCLIENT_ADDNODE);
3731 writeS16(&reply[2], p.X);
3732 writeS16(&reply[4], p.Y);
3733 writeS16(&reply[6], p.Z);
3734 n.serialize(&reply[8], client->serialization_version);
3735 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3736 writeU8(&reply[index], remove_metadata ? 0 : 1);
3738 if (!remove_metadata) {
3739 if (client->net_proto_version <= 21) {
3740 // Old clients always clear metadata; fix it
3741 // by sending the full block again.
3742 client->SetBlockNotSent(p);
3749 if (reply.getSize() > 0)
3750 m_clients.send(*i, 0, reply, true);
3754 void Server::setBlockNotSent(v3s16 p)
3756 std::list<u16> clients = m_clients.getClientIDs();
3758 for(std::list<u16>::iterator
3759 i = clients.begin();
3760 i != clients.end(); ++i)
3762 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3763 client->SetBlockNotSent(p);
3768 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3770 DSTACK(__FUNCTION_NAME);
3772 v3s16 p = block->getPos();
3776 bool completely_air = true;
3777 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3778 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3779 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3781 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3783 completely_air = false;
3784 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3789 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3791 infostream<<"[completely air] ";
3792 infostream<<std::endl;
3796 Create a packet with the block in the right format
3799 std::ostringstream os(std::ios_base::binary);
3800 block->serialize(os, ver, false);
3801 block->serializeNetworkSpecific(os, net_proto_version);
3802 std::string s = os.str();
3803 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3805 u32 replysize = 8 + blockdata.getSize();
3806 SharedBuffer<u8> reply(replysize);
3807 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3808 writeS16(&reply[2], p.X);
3809 writeS16(&reply[4], p.Y);
3810 writeS16(&reply[6], p.Z);
3811 memcpy(&reply[8], *blockdata, blockdata.getSize());
3813 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3814 <<": \tpacket size: "<<replysize<<std::endl;*/
3819 m_clients.send(peer_id, 2, reply, true);
3822 void Server::SendBlocks(float dtime)
3824 DSTACK(__FUNCTION_NAME);
3826 JMutexAutoLock envlock(m_env_mutex);
3827 //TODO check if one big lock could be faster then multiple small ones
3829 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3831 std::vector<PrioritySortedBlockTransfer> queue;
3833 s32 total_sending = 0;
3836 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3838 std::list<u16> clients = m_clients.getClientIDs();
3841 for(std::list<u16>::iterator
3842 i = clients.begin();
3843 i != clients.end(); ++i)
3845 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3850 total_sending += client->SendingCount();
3851 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3857 // Lowest priority number comes first.
3858 // Lowest is most important.
3859 std::sort(queue.begin(), queue.end());
3862 for(u32 i=0; i<queue.size(); i++)
3864 //TODO: Calculate limit dynamically
3865 if(total_sending >= g_settings->getS32
3866 ("max_simultaneous_block_sends_server_total"))
3869 PrioritySortedBlockTransfer q = queue[i];
3871 MapBlock *block = NULL;
3874 block = m_env->getMap().getBlockNoCreate(q.pos);
3876 catch(InvalidPositionException &e)
3881 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3886 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3888 client->SentBlock(q.pos);
3894 void Server::fillMediaCache()
3896 DSTACK(__FUNCTION_NAME);
3898 infostream<<"Server: Calculating media file checksums"<<std::endl;
3900 // Collect all media file paths
3901 std::list<std::string> paths;
3902 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3903 i != m_mods.end(); i++){
3904 const ModSpec &mod = *i;
3905 paths.push_back(mod.path + DIR_DELIM + "textures");
3906 paths.push_back(mod.path + DIR_DELIM + "sounds");
3907 paths.push_back(mod.path + DIR_DELIM + "media");
3908 paths.push_back(mod.path + DIR_DELIM + "models");
3910 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3912 // Collect media file information from paths into cache
3913 for(std::list<std::string>::iterator i = paths.begin();
3914 i != paths.end(); i++)
3916 std::string mediapath = *i;
3917 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3918 for(u32 j=0; j<dirlist.size(); j++){
3919 if(dirlist[j].dir) // Ignode dirs
3921 std::string filename = dirlist[j].name;
3922 // If name contains illegal characters, ignore the file
3923 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3924 infostream<<"Server: ignoring illegal file name: \""
3925 <<filename<<"\""<<std::endl;
3928 // If name is not in a supported format, ignore it
3929 const char *supported_ext[] = {
3930 ".png", ".jpg", ".bmp", ".tga",
3931 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3933 ".x", ".b3d", ".md2", ".obj",
3936 if(removeStringEnd(filename, supported_ext) == ""){
3937 infostream<<"Server: ignoring unsupported file extension: \""
3938 <<filename<<"\""<<std::endl;
3941 // Ok, attempt to load the file and add to cache
3942 std::string filepath = mediapath + DIR_DELIM + filename;
3944 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3945 if(fis.good() == false){
3946 errorstream<<"Server::fillMediaCache(): Could not open \""
3947 <<filename<<"\" for reading"<<std::endl;
3950 std::ostringstream tmp_os(std::ios_base::binary);
3954 fis.read(buf, 1024);
3955 std::streamsize len = fis.gcount();
3956 tmp_os.write(buf, len);
3965 errorstream<<"Server::fillMediaCache(): Failed to read \""
3966 <<filename<<"\""<<std::endl;
3969 if(tmp_os.str().length() == 0){
3970 errorstream<<"Server::fillMediaCache(): Empty file \""
3971 <<filepath<<"\""<<std::endl;
3976 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3978 unsigned char *digest = sha1.getDigest();
3979 std::string sha1_base64 = base64_encode(digest, 20);
3980 std::string sha1_hex = hex_encode((char*)digest, 20);
3984 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3985 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3990 struct SendableMediaAnnouncement
3993 std::string sha1_digest;
3995 SendableMediaAnnouncement(const std::string &name_="",
3996 const std::string &sha1_digest_=""):
3998 sha1_digest(sha1_digest_)
4002 void Server::sendMediaAnnouncement(u16 peer_id)
4004 DSTACK(__FUNCTION_NAME);
4006 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4009 std::list<SendableMediaAnnouncement> file_announcements;
4011 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4012 i != m_media.end(); i++){
4014 file_announcements.push_back(
4015 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4019 std::ostringstream os(std::ios_base::binary);
4027 u16 length of sha1_digest
4032 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4033 writeU16(os, file_announcements.size());
4035 for(std::list<SendableMediaAnnouncement>::iterator
4036 j = file_announcements.begin();
4037 j != file_announcements.end(); ++j){
4038 os<<serializeString(j->name);
4039 os<<serializeString(j->sha1_digest);
4041 os<<serializeString(g_settings->get("remote_media"));
4044 std::string s = os.str();
4045 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4048 m_clients.send(peer_id, 0, data, true);
4051 struct SendableMedia
4057 SendableMedia(const std::string &name_="", const std::string &path_="",
4058 const std::string &data_=""):
4065 void Server::sendRequestedMedia(u16 peer_id,
4066 const std::list<std::string> &tosend)
4068 DSTACK(__FUNCTION_NAME);
4070 verbosestream<<"Server::sendRequestedMedia(): "
4071 <<"Sending files to client"<<std::endl;
4075 // Put 5kB in one bunch (this is not accurate)
4076 u32 bytes_per_bunch = 5000;
4078 std::vector< std::list<SendableMedia> > file_bunches;
4079 file_bunches.push_back(std::list<SendableMedia>());
4081 u32 file_size_bunch_total = 0;
4083 for(std::list<std::string>::const_iterator i = tosend.begin();
4084 i != tosend.end(); ++i)
4086 const std::string &name = *i;
4088 if(m_media.find(name) == m_media.end()){
4089 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4090 <<"unknown file \""<<(name)<<"\""<<std::endl;
4094 //TODO get path + name
4095 std::string tpath = m_media[name].path;
4098 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4099 if(fis.good() == false){
4100 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4101 <<tpath<<"\" for reading"<<std::endl;
4104 std::ostringstream tmp_os(std::ios_base::binary);
4108 fis.read(buf, 1024);
4109 std::streamsize len = fis.gcount();
4110 tmp_os.write(buf, len);
4111 file_size_bunch_total += len;
4120 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4121 <<name<<"\""<<std::endl;
4124 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4125 <<tname<<"\""<<std::endl;*/
4127 file_bunches[file_bunches.size()-1].push_back(
4128 SendableMedia(name, tpath, tmp_os.str()));
4130 // Start next bunch if got enough data
4131 if(file_size_bunch_total >= bytes_per_bunch){
4132 file_bunches.push_back(std::list<SendableMedia>());
4133 file_size_bunch_total = 0;
4138 /* Create and send packets */
4140 u32 num_bunches = file_bunches.size();
4141 for(u32 i=0; i<num_bunches; i++)
4143 std::ostringstream os(std::ios_base::binary);
4147 u16 total number of texture bunches
4148 u16 index of this bunch
4149 u32 number of files in this bunch
4158 writeU16(os, TOCLIENT_MEDIA);
4159 writeU16(os, num_bunches);
4161 writeU32(os, file_bunches[i].size());
4163 for(std::list<SendableMedia>::iterator
4164 j = file_bunches[i].begin();
4165 j != file_bunches[i].end(); ++j){
4166 os<<serializeString(j->name);
4167 os<<serializeLongString(j->data);
4171 std::string s = os.str();
4172 verbosestream<<"Server::sendRequestedMedia(): bunch "
4173 <<i<<"/"<<num_bunches
4174 <<" files="<<file_bunches[i].size()
4175 <<" size=" <<s.size()<<std::endl;
4176 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4178 m_clients.send(peer_id, 2, data, true);
4182 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4184 if(m_detached_inventories.count(name) == 0){
4185 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4188 Inventory *inv = m_detached_inventories[name];
4190 std::ostringstream os(std::ios_base::binary);
4191 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4192 os<<serializeString(name);
4196 std::string s = os.str();
4197 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4199 if (peer_id != PEER_ID_INEXISTENT)
4202 m_clients.send(peer_id, 0, data, true);
4206 m_clients.sendToAll(0,data,true);
4210 void Server::sendDetachedInventories(u16 peer_id)
4212 DSTACK(__FUNCTION_NAME);
4214 for(std::map<std::string, Inventory*>::iterator
4215 i = m_detached_inventories.begin();
4216 i != m_detached_inventories.end(); i++){
4217 const std::string &name = i->first;
4218 //Inventory *inv = i->second;
4219 sendDetachedInventory(name, peer_id);
4227 void Server::DiePlayer(u16 peer_id)
4229 DSTACK(__FUNCTION_NAME);
4231 PlayerSAO *playersao = getPlayerSAO(peer_id);
4234 infostream<<"Server::DiePlayer(): Player "
4235 <<playersao->getPlayer()->getName()
4236 <<" dies"<<std::endl;
4238 playersao->setHP(0);
4240 // Trigger scripted stuff
4241 m_script->on_dieplayer(playersao);
4243 SendPlayerHP(peer_id);
4244 SendDeathscreen(peer_id, false, v3f(0,0,0));
4247 void Server::RespawnPlayer(u16 peer_id)
4249 DSTACK(__FUNCTION_NAME);
4251 PlayerSAO *playersao = getPlayerSAO(peer_id);
4254 infostream<<"Server::RespawnPlayer(): Player "
4255 <<playersao->getPlayer()->getName()
4256 <<" respawns"<<std::endl;
4258 playersao->setHP(PLAYER_MAX_HP);
4260 bool repositioned = m_script->on_respawnplayer(playersao);
4262 v3f pos = findSpawnPos(m_env->getServerMap());
4263 playersao->setPos(pos);
4267 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4269 DSTACK(__FUNCTION_NAME);
4271 SendAccessDenied(peer_id, reason);
4272 m_clients.event(peer_id, CSE_SetDenied);
4273 m_con.DisconnectPeer(peer_id);
4276 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4278 DSTACK(__FUNCTION_NAME);
4279 std::wstring message;
4282 Clear references to playing sounds
4284 for(std::map<s32, ServerPlayingSound>::iterator
4285 i = m_playing_sounds.begin();
4286 i != m_playing_sounds.end();)
4288 ServerPlayingSound &psound = i->second;
4289 psound.clients.erase(peer_id);
4290 if(psound.clients.size() == 0)
4291 m_playing_sounds.erase(i++);
4296 Player *player = m_env->getPlayer(peer_id);
4298 // Collect information about leaving in chat
4300 if(player != NULL && reason != CDR_DENY)
4302 std::wstring name = narrow_to_wide(player->getName());
4305 message += L" left the game.";
4306 if(reason == CDR_TIMEOUT)
4307 message += L" (timed out)";
4311 /* Run scripts and remove from environment */
4315 PlayerSAO *playersao = player->getPlayerSAO();
4318 m_script->on_leaveplayer(playersao);
4320 playersao->disconnected();
4328 if(player != NULL && reason != CDR_DENY)
4330 std::ostringstream os(std::ios_base::binary);
4331 std::list<u16> clients = m_clients.getClientIDs();
4333 for(std::list<u16>::iterator
4334 i = clients.begin();
4335 i != clients.end(); ++i)
4338 Player *player = m_env->getPlayer(*i);
4341 // Get name of player
4342 os<<player->getName()<<" ";
4345 actionstream<<player->getName()<<" "
4346 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4347 <<" List of players: "<<os.str()<<std::endl;
4351 JMutexAutoLock env_lock(m_env_mutex);
4352 m_clients.DeleteClient(peer_id);
4356 // Send leave chat message to all remaining clients
4357 if(message.length() != 0)
4358 SendChatMessage(PEER_ID_INEXISTENT,message);
4361 void Server::UpdateCrafting(u16 peer_id)
4363 DSTACK(__FUNCTION_NAME);
4365 Player* player = m_env->getPlayer(peer_id);
4368 // Get a preview for crafting
4370 InventoryLocation loc;
4371 loc.setPlayer(player->getName());
4372 getCraftingResult(&player->inventory, preview, false, this);
4373 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4375 // Put the new preview in
4376 InventoryList *plist = player->inventory.getList("craftpreview");
4378 assert(plist->getSize() >= 1);
4379 plist->changeItem(0, preview);
4382 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4384 RemoteClient *client = getClientNoEx(peer_id,state_min);
4386 throw ClientNotFoundException("Client not found");
4390 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4392 return m_clients.getClientNoEx(peer_id, state_min);
4395 std::string Server::getPlayerName(u16 peer_id)
4397 Player *player = m_env->getPlayer(peer_id);
4399 return "[id="+itos(peer_id)+"]";
4400 return player->getName();
4403 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4405 Player *player = m_env->getPlayer(peer_id);
4408 return player->getPlayerSAO();
4411 std::wstring Server::getStatusString()
4413 std::wostringstream os(std::ios_base::binary);
4416 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4418 os<<L", uptime="<<m_uptime.get();
4420 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4421 // Information about clients
4424 std::list<u16> clients = m_clients.getClientIDs();
4425 for(std::list<u16>::iterator i = clients.begin();
4426 i != clients.end(); ++i)
4429 Player *player = m_env->getPlayer(*i);
4430 // Get name of player
4431 std::wstring name = L"unknown";
4433 name = narrow_to_wide(player->getName());
4434 // Add name to information string
4442 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4443 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4444 if(g_settings->get("motd") != "")
4445 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4449 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4451 std::set<std::string> privs;
4452 m_script->getAuth(name, NULL, &privs);
4456 bool Server::checkPriv(const std::string &name, const std::string &priv)
4458 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4459 return (privs.count(priv) != 0);
4462 void Server::reportPrivsModified(const std::string &name)
4465 std::list<u16> clients = m_clients.getClientIDs();
4466 for(std::list<u16>::iterator
4467 i = clients.begin();
4468 i != clients.end(); ++i){
4469 Player *player = m_env->getPlayer(*i);
4470 reportPrivsModified(player->getName());
4473 Player *player = m_env->getPlayer(name.c_str());
4476 SendPlayerPrivileges(player->peer_id);
4477 PlayerSAO *sao = player->getPlayerSAO();
4480 sao->updatePrivileges(
4481 getPlayerEffectivePrivs(name),
4486 void Server::reportInventoryFormspecModified(const std::string &name)
4488 Player *player = m_env->getPlayer(name.c_str());
4491 SendPlayerInventoryFormspec(player->peer_id);
4494 void Server::setIpBanned(const std::string &ip, const std::string &name)
4496 m_banmanager->add(ip, name);
4499 void Server::unsetIpBanned(const std::string &ip_or_name)
4501 m_banmanager->remove(ip_or_name);
4504 std::string Server::getBanDescription(const std::string &ip_or_name)
4506 return m_banmanager->getBanDescription(ip_or_name);
4509 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4511 Player *player = m_env->getPlayer(name);
4515 if (player->peer_id == PEER_ID_INEXISTENT)
4518 SendChatMessage(player->peer_id, msg);
4521 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4523 Player *player = m_env->getPlayer(playername);
4527 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4531 SendShowFormspecMessage(player->peer_id, formspec, formname);
4535 u32 Server::hudAdd(Player *player, HudElement *form) {
4539 u32 id = player->addHud(form);
4541 SendHUDAdd(player->peer_id, id, form);
4546 bool Server::hudRemove(Player *player, u32 id) {
4550 HudElement* todel = player->removeHud(id);
4557 SendHUDRemove(player->peer_id, id);
4561 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4565 SendHUDChange(player->peer_id, id, stat, data);
4569 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4573 SendHUDSetFlags(player->peer_id, flags, mask);
4574 player->hud_flags = flags;
4576 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4580 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4583 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4586 std::ostringstream os(std::ios::binary);
4587 writeS32(os, hotbar_itemcount);
4588 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4592 void Server::hudSetHotbarImage(Player *player, std::string name) {
4596 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4599 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4603 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4606 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4611 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4615 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4620 SendEyeOffset(player->peer_id, first, third);
4624 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4625 const std::string &type, const std::vector<std::string> ¶ms)
4630 SendSetSky(player->peer_id, bgcolor, type, params);
4634 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4640 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4644 void Server::notifyPlayers(const std::wstring &msg)
4646 SendChatMessage(PEER_ID_INEXISTENT,msg);
4649 void Server::spawnParticle(const char *playername, v3f pos,
4650 v3f velocity, v3f acceleration,
4651 float expirationtime, float size, bool
4652 collisiondetection, bool vertical, std::string texture)
4654 Player *player = m_env->getPlayer(playername);
4657 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4658 expirationtime, size, collisiondetection, vertical, texture);
4661 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4662 float expirationtime, float size,
4663 bool collisiondetection, bool vertical, std::string texture)
4665 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4666 expirationtime, size, collisiondetection, vertical, texture);
4669 u32 Server::addParticleSpawner(const char *playername,
4670 u16 amount, float spawntime,
4671 v3f minpos, v3f maxpos,
4672 v3f minvel, v3f maxvel,
4673 v3f minacc, v3f maxacc,
4674 float minexptime, float maxexptime,
4675 float minsize, float maxsize,
4676 bool collisiondetection, bool vertical, std::string texture)
4678 Player *player = m_env->getPlayer(playername);
4683 for(;;) // look for unused particlespawner id
4686 if (std::find(m_particlespawner_ids.begin(),
4687 m_particlespawner_ids.end(), id)
4688 == m_particlespawner_ids.end())
4690 m_particlespawner_ids.push_back(id);
4695 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4696 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4697 minexptime, maxexptime, minsize, maxsize,
4698 collisiondetection, vertical, texture, id);
4703 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4704 v3f minpos, v3f maxpos,
4705 v3f minvel, v3f maxvel,
4706 v3f minacc, v3f maxacc,
4707 float minexptime, float maxexptime,
4708 float minsize, float maxsize,
4709 bool collisiondetection, bool vertical, std::string texture)
4712 for(;;) // look for unused particlespawner id
4715 if (std::find(m_particlespawner_ids.begin(),
4716 m_particlespawner_ids.end(), id)
4717 == m_particlespawner_ids.end())
4719 m_particlespawner_ids.push_back(id);
4724 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4725 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4726 minexptime, maxexptime, minsize, maxsize,
4727 collisiondetection, vertical, texture, id);
4732 void Server::deleteParticleSpawner(const char *playername, u32 id)
4734 Player *player = m_env->getPlayer(playername);
4738 m_particlespawner_ids.erase(
4739 std::remove(m_particlespawner_ids.begin(),
4740 m_particlespawner_ids.end(), id),
4741 m_particlespawner_ids.end());
4742 SendDeleteParticleSpawner(player->peer_id, id);
4745 void Server::deleteParticleSpawnerAll(u32 id)
4747 m_particlespawner_ids.erase(
4748 std::remove(m_particlespawner_ids.begin(),
4749 m_particlespawner_ids.end(), id),
4750 m_particlespawner_ids.end());
4751 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4754 Inventory* Server::createDetachedInventory(const std::string &name)
4756 if(m_detached_inventories.count(name) > 0){
4757 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4758 delete m_detached_inventories[name];
4760 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4762 Inventory *inv = new Inventory(m_itemdef);
4764 m_detached_inventories[name] = inv;
4765 //TODO find a better way to do this
4766 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4773 BoolScopeSet(bool *dst, bool val):
4776 m_orig_state = *m_dst;
4781 *m_dst = m_orig_state;
4788 // actions: time-reversed list
4789 // Return value: success/failure
4790 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4791 std::list<std::string> *log)
4793 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4794 ServerMap *map = (ServerMap*)(&m_env->getMap());
4795 // Disable rollback report sink while reverting
4796 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4798 // Fail if no actions to handle
4799 if(actions.empty()){
4800 log->push_back("Nothing to do.");
4807 for(std::list<RollbackAction>::const_iterator
4808 i = actions.begin();
4809 i != actions.end(); i++)
4811 const RollbackAction &action = *i;
4813 bool success = action.applyRevert(map, this, this);
4816 std::ostringstream os;
4817 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4818 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4820 log->push_back(os.str());
4822 std::ostringstream os;
4823 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4824 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4826 log->push_back(os.str());
4830 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4831 <<" failed"<<std::endl;
4833 // Call it done if less than half failed
4834 return num_failed <= num_tried/2;
4837 // IGameDef interface
4839 IItemDefManager* Server::getItemDefManager()
4843 INodeDefManager* Server::getNodeDefManager()
4847 ICraftDefManager* Server::getCraftDefManager()
4851 ITextureSource* Server::getTextureSource()
4855 IShaderSource* Server::getShaderSource()
4859 u16 Server::allocateUnknownNodeId(const std::string &name)
4861 return m_nodedef->allocateDummy(name);
4863 ISoundManager* Server::getSoundManager()
4865 return &dummySoundManager;
4867 MtEventManager* Server::getEventManager()
4871 IRollbackReportSink* Server::getRollbackReportSink()
4873 if(!m_enable_rollback_recording)
4875 if(!m_rollback_sink_enabled)
4880 IWritableItemDefManager* Server::getWritableItemDefManager()
4884 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4888 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4893 const ModSpec* Server::getModSpec(const std::string &modname)
4895 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4896 i != m_mods.end(); i++){
4897 const ModSpec &mod = *i;
4898 if(mod.name == modname)
4903 void Server::getModNames(std::list<std::string> &modlist)
4905 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4907 modlist.push_back(i->name);
4910 std::string Server::getBuiltinLuaPath()
4912 return porting::path_share + DIR_DELIM + "builtin";
4915 v3f findSpawnPos(ServerMap &map)
4917 //return v3f(50,50,50)*BS;
4922 nodepos = v2s16(0,0);
4927 s16 water_level = map.getWaterLevel();
4929 // Try to find a good place a few times
4930 for(s32 i=0; i<1000; i++)
4933 // We're going to try to throw the player to this position
4934 v2s16 nodepos2d = v2s16(
4935 -range + (myrand() % (range * 2)),
4936 -range + (myrand() % (range * 2)));
4938 // Get ground height at point
4939 s16 groundheight = map.findGroundLevel(nodepos2d);
4940 if (groundheight <= water_level) // Don't go underwater
4942 if (groundheight > water_level + 6) // Don't go to high places
4945 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4946 bool is_good = false;
4948 for (s32 i = 0; i < 10; i++) {
4949 v3s16 blockpos = getNodeBlockPos(nodepos);
4950 map.emergeBlock(blockpos, true);
4951 content_t c = map.getNodeNoEx(nodepos).getContent();
4952 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4954 if (air_count >= 2){
4962 // Found a good place
4963 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4969 return intToFloat(nodepos, BS);
4972 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4974 RemotePlayer *player = NULL;
4975 bool newplayer = false;
4978 Try to get an existing player
4980 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4982 // If player is already connected, cancel
4983 if(player != NULL && player->peer_id != 0)
4985 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4990 If player with the wanted peer_id already exists, cancel.
4992 if(m_env->getPlayer(peer_id) != NULL)
4994 infostream<<"emergePlayer(): Player with wrong name but same"
4995 " peer_id already exists"<<std::endl;
4999 // Load player if it isn't already loaded
5001 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5004 // Create player if it doesn't exist
5007 player = new RemotePlayer(this);
5008 player->updateName(name);
5009 /* Set player position */
5010 infostream<<"Server: Finding spawn place for player \""
5011 <<name<<"\""<<std::endl;
5012 v3f pos = findSpawnPos(m_env->getServerMap());
5013 player->setPosition(pos);
5015 /* Add player to environment */
5016 m_env->addPlayer(player);
5019 // Create a new player active object
5020 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5021 getPlayerEffectivePrivs(player->getName()),
5024 /* Clean up old HUD elements from previous sessions */
5027 /* Add object to environment */
5028 m_env->addActiveObject(playersao);
5032 m_script->on_newplayer(playersao);
5038 void dedicated_server_loop(Server &server, bool &kill)
5040 DSTACK(__FUNCTION_NAME);
5042 verbosestream<<"dedicated_server_loop()"<<std::endl;
5044 IntervalLimiter m_profiler_interval;
5048 float steplen = g_settings->getFloat("dedicated_server_step");
5049 // This is kind of a hack but can be done like this
5050 // because server.step() is very light
5052 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5053 sleep_ms((int)(steplen*1000.0));
5055 server.step(steplen);
5057 if(server.getShutdownRequested() || kill)
5059 infostream<<"Dedicated server quitting"<<std::endl;
5061 if(g_settings->getBool("server_announce") == true)
5062 ServerList::sendAnnounce("delete");
5070 float profiler_print_interval =
5071 g_settings->getFloat("profiler_print_interval");
5072 if(profiler_print_interval != 0)
5074 if(m_profiler_interval.step(steplen, profiler_print_interval))
5076 infostream<<"Profiler:"<<std::endl;
5077 g_profiler->print(infostream);
5078 g_profiler->clear();