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() < 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,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,Created);
1325 // If net_proto_version is set, this client has already been handled
1326 if(client->getState() > 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(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, Init);
1614 if(command == TOSERVER_INIT2)
1617 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1618 <<peer_id<<std::endl;
1620 m_clients.event(peer_id, 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, 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, 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,InitDone)->serialization_version;
1685 u16 peer_proto_ver = getClient(peer_id,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, 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) < 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,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,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);
3136 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3137 os.write((char*)buf, 2);
3138 os<<serializeLongString(formspec);
3139 os<<serializeString(formname);
3142 std::string s = os.str();
3143 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3145 m_clients.send(peer_id, 0, data, true);
3148 // Spawns a particle on peer with peer_id
3149 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3150 float expirationtime, float size, bool collisiondetection,
3151 bool vertical, std::string texture)
3153 DSTACK(__FUNCTION_NAME);
3155 std::ostringstream os(std::ios_base::binary);
3156 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3157 writeV3F1000(os, pos);
3158 writeV3F1000(os, velocity);
3159 writeV3F1000(os, acceleration);
3160 writeF1000(os, expirationtime);
3161 writeF1000(os, size);
3162 writeU8(os, collisiondetection);
3163 os<<serializeLongString(texture);
3164 writeU8(os, vertical);
3167 std::string s = os.str();
3168 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3170 if (peer_id != PEER_ID_INEXISTENT)
3173 m_clients.send(peer_id, 0, data, true);
3177 m_clients.sendToAll(0,data,true);
3181 // Adds a ParticleSpawner on peer with peer_id
3182 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3183 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3184 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3186 DSTACK(__FUNCTION_NAME);
3188 std::ostringstream os(std::ios_base::binary);
3189 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3191 writeU16(os, amount);
3192 writeF1000(os, spawntime);
3193 writeV3F1000(os, minpos);
3194 writeV3F1000(os, maxpos);
3195 writeV3F1000(os, minvel);
3196 writeV3F1000(os, maxvel);
3197 writeV3F1000(os, minacc);
3198 writeV3F1000(os, maxacc);
3199 writeF1000(os, minexptime);
3200 writeF1000(os, maxexptime);
3201 writeF1000(os, minsize);
3202 writeF1000(os, maxsize);
3203 writeU8(os, collisiondetection);
3204 os<<serializeLongString(texture);
3206 writeU8(os, vertical);
3209 std::string s = os.str();
3210 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3212 if (peer_id != PEER_ID_INEXISTENT)
3215 m_clients.send(peer_id, 0, data, true);
3218 m_clients.sendToAll(0,data,true);
3222 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3224 DSTACK(__FUNCTION_NAME);
3226 std::ostringstream os(std::ios_base::binary);
3227 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3232 std::string s = os.str();
3233 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3235 if (peer_id != PEER_ID_INEXISTENT) {
3237 m_clients.send(peer_id, 0, data, true);
3240 m_clients.sendToAll(0,data,true);
3245 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3247 std::ostringstream os(std::ios_base::binary);
3250 writeU16(os, TOCLIENT_HUDADD);
3252 writeU8(os, (u8)form->type);
3253 writeV2F1000(os, form->pos);
3254 os << serializeString(form->name);
3255 writeV2F1000(os, form->scale);
3256 os << serializeString(form->text);
3257 writeU32(os, form->number);
3258 writeU32(os, form->item);
3259 writeU32(os, form->dir);
3260 writeV2F1000(os, form->align);
3261 writeV2F1000(os, form->offset);
3262 writeV3F1000(os, form->world_pos);
3263 writeV2S32(os,form->size);
3266 std::string s = os.str();
3267 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3269 m_clients.send(peer_id, 1, data, true);
3272 void Server::SendHUDRemove(u16 peer_id, u32 id)
3274 std::ostringstream os(std::ios_base::binary);
3277 writeU16(os, TOCLIENT_HUDRM);
3281 std::string s = os.str();
3282 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3285 m_clients.send(peer_id, 1, data, true);
3288 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3290 std::ostringstream os(std::ios_base::binary);
3293 writeU16(os, TOCLIENT_HUDCHANGE);
3295 writeU8(os, (u8)stat);
3298 case HUD_STAT_SCALE:
3299 case HUD_STAT_ALIGN:
3300 case HUD_STAT_OFFSET:
3301 writeV2F1000(os, *(v2f *)value);
3305 os << serializeString(*(std::string *)value);
3307 case HUD_STAT_WORLD_POS:
3308 writeV3F1000(os, *(v3f *)value);
3311 writeV2S32(os,*(v2s32 *)value);
3313 case HUD_STAT_NUMBER:
3317 writeU32(os, *(u32 *)value);
3322 std::string s = os.str();
3323 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3325 m_clients.send(peer_id, 0, data, true);
3328 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3330 std::ostringstream os(std::ios_base::binary);
3333 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3335 //////////////////////////// compatibility code to be removed //////////////
3336 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3337 ////////////////////////////////////////////////////////////////////////////
3338 writeU32(os, flags);
3342 std::string s = os.str();
3343 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3345 m_clients.send(peer_id, 0, data, true);
3348 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3350 std::ostringstream os(std::ios_base::binary);
3353 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3354 writeU16(os, param);
3355 os<<serializeString(value);
3358 std::string s = os.str();
3359 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3361 m_clients.send(peer_id, 0, data, true);
3364 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3365 const std::string &type, const std::vector<std::string> ¶ms)
3367 std::ostringstream os(std::ios_base::binary);
3370 writeU16(os, TOCLIENT_SET_SKY);
3371 writeARGB8(os, bgcolor);
3372 os<<serializeString(type);
3373 writeU16(os, params.size());
3374 for(size_t i=0; i<params.size(); i++)
3375 os<<serializeString(params[i]);
3378 std::string s = os.str();
3379 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3381 m_clients.send(peer_id, 0, data, true);
3384 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3387 std::ostringstream os(std::ios_base::binary);
3390 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3391 writeU8(os, do_override);
3392 writeU16(os, ratio*65535);
3395 std::string s = os.str();
3396 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3398 m_clients.send(peer_id, 0, data, true);
3401 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3403 DSTACK(__FUNCTION_NAME);
3406 SharedBuffer<u8> data(2+2+4);
3407 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3408 writeU16(&data[2], time);
3409 writeF1000(&data[4], time_speed);
3411 if (peer_id == PEER_ID_INEXISTENT) {
3412 m_clients.sendToAll(0,data,true);
3416 m_clients.send(peer_id, 0, data, true);
3420 void Server::SendPlayerHP(u16 peer_id)
3422 DSTACK(__FUNCTION_NAME);
3423 PlayerSAO *playersao = getPlayerSAO(peer_id);
3425 playersao->m_hp_not_sent = false;
3426 SendHP(peer_id, playersao->getHP());
3427 m_script->player_event(playersao,"health_changed");
3429 // Send to other clients
3430 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3431 ActiveObjectMessage aom(playersao->getId(), true, str);
3432 playersao->m_messages_out.push_back(aom);
3435 void Server::SendPlayerBreath(u16 peer_id)
3437 DSTACK(__FUNCTION_NAME);
3438 PlayerSAO *playersao = getPlayerSAO(peer_id);
3440 playersao->m_breath_not_sent = false;
3441 m_script->player_event(playersao,"breath_changed");
3442 SendBreath(peer_id, playersao->getBreath());
3445 void Server::SendMovePlayer(u16 peer_id)
3447 DSTACK(__FUNCTION_NAME);
3448 Player *player = m_env->getPlayer(peer_id);
3451 std::ostringstream os(std::ios_base::binary);
3452 writeU16(os, TOCLIENT_MOVE_PLAYER);
3453 writeV3F1000(os, player->getPosition());
3454 writeF1000(os, player->getPitch());
3455 writeF1000(os, player->getYaw());
3458 v3f pos = player->getPosition();
3459 f32 pitch = player->getPitch();
3460 f32 yaw = player->getYaw();
3461 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3462 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3469 std::string s = os.str();
3470 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3472 m_clients.send(peer_id, 0, data, true);
3475 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3477 std::ostringstream os(std::ios_base::binary);
3479 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3480 writeV2S32(os, animation_frames[0]);
3481 writeV2S32(os, animation_frames[1]);
3482 writeV2S32(os, animation_frames[2]);
3483 writeV2S32(os, animation_frames[3]);
3484 writeF1000(os, animation_speed);
3487 std::string s = os.str();
3488 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3490 m_clients.send(peer_id, 0, data, true);
3493 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3495 std::ostringstream os(std::ios_base::binary);
3497 writeU16(os, TOCLIENT_EYE_OFFSET);
3498 writeV3F1000(os, first);
3499 writeV3F1000(os, third);
3502 std::string s = os.str();
3503 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3505 m_clients.send(peer_id, 0, data, true);
3507 void Server::SendPlayerPrivileges(u16 peer_id)
3509 Player *player = m_env->getPlayer(peer_id);
3511 if(player->peer_id == PEER_ID_INEXISTENT)
3514 std::set<std::string> privs;
3515 m_script->getAuth(player->getName(), NULL, &privs);
3517 std::ostringstream os(std::ios_base::binary);
3518 writeU16(os, TOCLIENT_PRIVILEGES);
3519 writeU16(os, privs.size());
3520 for(std::set<std::string>::const_iterator i = privs.begin();
3521 i != privs.end(); i++){
3522 os<<serializeString(*i);
3526 std::string s = os.str();
3527 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3529 m_clients.send(peer_id, 0, data, true);
3532 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3534 Player *player = m_env->getPlayer(peer_id);
3536 if(player->peer_id == PEER_ID_INEXISTENT)
3539 std::ostringstream os(std::ios_base::binary);
3540 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3541 os<<serializeLongString(player->inventory_formspec);
3544 std::string s = os.str();
3545 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547 m_clients.send(peer_id, 0, data, true);
3550 s32 Server::playSound(const SimpleSoundSpec &spec,
3551 const ServerSoundParams ¶ms)
3553 // Find out initial position of sound
3554 bool pos_exists = false;
3555 v3f pos = params.getPos(m_env, &pos_exists);
3556 // If position is not found while it should be, cancel sound
3557 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3560 // Filter destination clients
3561 std::list<u16> dst_clients;
3562 if(params.to_player != "")
3564 Player *player = m_env->getPlayer(params.to_player.c_str());
3566 infostream<<"Server::playSound: Player \""<<params.to_player
3567 <<"\" not found"<<std::endl;
3570 if(player->peer_id == PEER_ID_INEXISTENT){
3571 infostream<<"Server::playSound: Player \""<<params.to_player
3572 <<"\" not connected"<<std::endl;
3575 dst_clients.push_back(player->peer_id);
3579 std::list<u16> clients = m_clients.getClientIDs();
3581 for(std::list<u16>::iterator
3582 i = clients.begin(); i != clients.end(); ++i)
3584 Player *player = m_env->getPlayer(*i);
3588 if(player->getPosition().getDistanceFrom(pos) >
3589 params.max_hear_distance)
3592 dst_clients.push_back(*i);
3595 if(dst_clients.size() == 0)
3599 s32 id = m_next_sound_id++;
3600 // The sound will exist as a reference in m_playing_sounds
3601 m_playing_sounds[id] = ServerPlayingSound();
3602 ServerPlayingSound &psound = m_playing_sounds[id];
3603 psound.params = params;
3604 for(std::list<u16>::iterator i = dst_clients.begin();
3605 i != dst_clients.end(); i++)
3606 psound.clients.insert(*i);
3608 std::ostringstream os(std::ios_base::binary);
3609 writeU16(os, TOCLIENT_PLAY_SOUND);
3611 os<<serializeString(spec.name);
3612 writeF1000(os, spec.gain * params.gain);
3613 writeU8(os, params.type);
3614 writeV3F1000(os, pos);
3615 writeU16(os, params.object);
3616 writeU8(os, params.loop);
3618 std::string s = os.str();
3619 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3621 for(std::list<u16>::iterator i = dst_clients.begin();
3622 i != dst_clients.end(); i++){
3624 m_clients.send(*i, 0, data, true);
3628 void Server::stopSound(s32 handle)
3630 // Get sound reference
3631 std::map<s32, ServerPlayingSound>::iterator i =
3632 m_playing_sounds.find(handle);
3633 if(i == m_playing_sounds.end())
3635 ServerPlayingSound &psound = i->second;
3637 std::ostringstream os(std::ios_base::binary);
3638 writeU16(os, TOCLIENT_STOP_SOUND);
3639 writeS32(os, handle);
3641 std::string s = os.str();
3642 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3644 for(std::set<u16>::iterator i = psound.clients.begin();
3645 i != psound.clients.end(); i++){
3647 m_clients.send(*i, 0, data, true);
3649 // Remove sound reference
3650 m_playing_sounds.erase(i);
3653 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3654 std::list<u16> *far_players, float far_d_nodes)
3656 float maxd = far_d_nodes*BS;
3657 v3f p_f = intToFloat(p, BS);
3661 SharedBuffer<u8> reply(replysize);
3662 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3663 writeS16(&reply[2], p.X);
3664 writeS16(&reply[4], p.Y);
3665 writeS16(&reply[6], p.Z);
3667 std::list<u16> clients = m_clients.getClientIDs();
3668 for(std::list<u16>::iterator
3669 i = clients.begin();
3670 i != clients.end(); ++i)
3675 Player *player = m_env->getPlayer(*i);
3678 // If player is far away, only set modified blocks not sent
3679 v3f player_pos = player->getPosition();
3680 if(player_pos.getDistanceFrom(p_f) > maxd)
3682 far_players->push_back(*i);
3689 m_clients.send(*i, 0, reply, true);
3693 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3694 std::list<u16> *far_players, float far_d_nodes,
3695 bool remove_metadata)
3697 float maxd = far_d_nodes*BS;
3698 v3f p_f = intToFloat(p, BS);
3700 std::list<u16> clients = m_clients.getClientIDs();
3701 for(std::list<u16>::iterator
3702 i = clients.begin();
3703 i != clients.end(); ++i)
3709 Player *player = m_env->getPlayer(*i);
3712 // If player is far away, only set modified blocks not sent
3713 v3f player_pos = player->getPosition();
3714 if(player_pos.getDistanceFrom(p_f) > maxd)
3716 far_players->push_back(*i);
3721 SharedBuffer<u8> reply(0);
3723 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3727 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3728 reply = SharedBuffer<u8>(replysize);
3729 writeU16(&reply[0], TOCLIENT_ADDNODE);
3730 writeS16(&reply[2], p.X);
3731 writeS16(&reply[4], p.Y);
3732 writeS16(&reply[6], p.Z);
3733 n.serialize(&reply[8], client->serialization_version);
3734 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3735 writeU8(&reply[index], remove_metadata ? 0 : 1);
3737 if (!remove_metadata) {
3738 if (client->net_proto_version <= 21) {
3739 // Old clients always clear metadata; fix it
3740 // by sending the full block again.
3741 client->SetBlockNotSent(p);
3748 if (reply.getSize() > 0)
3749 m_clients.send(*i, 0, reply, true);
3753 void Server::setBlockNotSent(v3s16 p)
3755 std::list<u16> clients = m_clients.getClientIDs();
3757 for(std::list<u16>::iterator
3758 i = clients.begin();
3759 i != clients.end(); ++i)
3761 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3762 client->SetBlockNotSent(p);
3767 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3769 DSTACK(__FUNCTION_NAME);
3771 v3s16 p = block->getPos();
3775 bool completely_air = true;
3776 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3777 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3778 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3780 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3782 completely_air = false;
3783 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3788 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3790 infostream<<"[completely air] ";
3791 infostream<<std::endl;
3795 Create a packet with the block in the right format
3798 std::ostringstream os(std::ios_base::binary);
3799 block->serialize(os, ver, false);
3800 block->serializeNetworkSpecific(os, net_proto_version);
3801 std::string s = os.str();
3802 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3804 u32 replysize = 8 + blockdata.getSize();
3805 SharedBuffer<u8> reply(replysize);
3806 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3807 writeS16(&reply[2], p.X);
3808 writeS16(&reply[4], p.Y);
3809 writeS16(&reply[6], p.Z);
3810 memcpy(&reply[8], *blockdata, blockdata.getSize());
3812 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3813 <<": \tpacket size: "<<replysize<<std::endl;*/
3818 m_clients.send(peer_id, 2, reply, true);
3821 void Server::SendBlocks(float dtime)
3823 DSTACK(__FUNCTION_NAME);
3825 JMutexAutoLock envlock(m_env_mutex);
3826 //TODO check if one big lock could be faster then multiple small ones
3828 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3830 std::vector<PrioritySortedBlockTransfer> queue;
3832 s32 total_sending = 0;
3835 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3837 std::list<u16> clients = m_clients.getClientIDs();
3840 for(std::list<u16>::iterator
3841 i = clients.begin();
3842 i != clients.end(); ++i)
3844 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3849 total_sending += client->SendingCount();
3850 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3856 // Lowest priority number comes first.
3857 // Lowest is most important.
3858 std::sort(queue.begin(), queue.end());
3861 for(u32 i=0; i<queue.size(); i++)
3863 //TODO: Calculate limit dynamically
3864 if(total_sending >= g_settings->getS32
3865 ("max_simultaneous_block_sends_server_total"))
3868 PrioritySortedBlockTransfer q = queue[i];
3870 MapBlock *block = NULL;
3873 block = m_env->getMap().getBlockNoCreate(q.pos);
3875 catch(InvalidPositionException &e)
3880 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3885 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3887 client->SentBlock(q.pos);
3893 void Server::fillMediaCache()
3895 DSTACK(__FUNCTION_NAME);
3897 infostream<<"Server: Calculating media file checksums"<<std::endl;
3899 // Collect all media file paths
3900 std::list<std::string> paths;
3901 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3902 i != m_mods.end(); i++){
3903 const ModSpec &mod = *i;
3904 paths.push_back(mod.path + DIR_DELIM + "textures");
3905 paths.push_back(mod.path + DIR_DELIM + "sounds");
3906 paths.push_back(mod.path + DIR_DELIM + "media");
3907 paths.push_back(mod.path + DIR_DELIM + "models");
3909 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3911 // Collect media file information from paths into cache
3912 for(std::list<std::string>::iterator i = paths.begin();
3913 i != paths.end(); i++)
3915 std::string mediapath = *i;
3916 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3917 for(u32 j=0; j<dirlist.size(); j++){
3918 if(dirlist[j].dir) // Ignode dirs
3920 std::string filename = dirlist[j].name;
3921 // If name contains illegal characters, ignore the file
3922 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3923 infostream<<"Server: ignoring illegal file name: \""
3924 <<filename<<"\""<<std::endl;
3927 // If name is not in a supported format, ignore it
3928 const char *supported_ext[] = {
3929 ".png", ".jpg", ".bmp", ".tga",
3930 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3932 ".x", ".b3d", ".md2", ".obj",
3935 if(removeStringEnd(filename, supported_ext) == ""){
3936 infostream<<"Server: ignoring unsupported file extension: \""
3937 <<filename<<"\""<<std::endl;
3940 // Ok, attempt to load the file and add to cache
3941 std::string filepath = mediapath + DIR_DELIM + filename;
3943 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3944 if(fis.good() == false){
3945 errorstream<<"Server::fillMediaCache(): Could not open \""
3946 <<filename<<"\" for reading"<<std::endl;
3949 std::ostringstream tmp_os(std::ios_base::binary);
3953 fis.read(buf, 1024);
3954 std::streamsize len = fis.gcount();
3955 tmp_os.write(buf, len);
3964 errorstream<<"Server::fillMediaCache(): Failed to read \""
3965 <<filename<<"\""<<std::endl;
3968 if(tmp_os.str().length() == 0){
3969 errorstream<<"Server::fillMediaCache(): Empty file \""
3970 <<filepath<<"\""<<std::endl;
3975 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3977 unsigned char *digest = sha1.getDigest();
3978 std::string sha1_base64 = base64_encode(digest, 20);
3979 std::string sha1_hex = hex_encode((char*)digest, 20);
3983 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3984 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3989 struct SendableMediaAnnouncement
3992 std::string sha1_digest;
3994 SendableMediaAnnouncement(const std::string &name_="",
3995 const std::string &sha1_digest_=""):
3997 sha1_digest(sha1_digest_)
4001 void Server::sendMediaAnnouncement(u16 peer_id)
4003 DSTACK(__FUNCTION_NAME);
4005 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4008 std::list<SendableMediaAnnouncement> file_announcements;
4010 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4011 i != m_media.end(); i++){
4013 file_announcements.push_back(
4014 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4018 std::ostringstream os(std::ios_base::binary);
4026 u16 length of sha1_digest
4031 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4032 writeU16(os, file_announcements.size());
4034 for(std::list<SendableMediaAnnouncement>::iterator
4035 j = file_announcements.begin();
4036 j != file_announcements.end(); ++j){
4037 os<<serializeString(j->name);
4038 os<<serializeString(j->sha1_digest);
4040 os<<serializeString(g_settings->get("remote_media"));
4043 std::string s = os.str();
4044 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4047 m_clients.send(peer_id, 0, data, true);
4050 struct SendableMedia
4056 SendableMedia(const std::string &name_="", const std::string &path_="",
4057 const std::string &data_=""):
4064 void Server::sendRequestedMedia(u16 peer_id,
4065 const std::list<std::string> &tosend)
4067 DSTACK(__FUNCTION_NAME);
4069 verbosestream<<"Server::sendRequestedMedia(): "
4070 <<"Sending files to client"<<std::endl;
4074 // Put 5kB in one bunch (this is not accurate)
4075 u32 bytes_per_bunch = 5000;
4077 std::vector< std::list<SendableMedia> > file_bunches;
4078 file_bunches.push_back(std::list<SendableMedia>());
4080 u32 file_size_bunch_total = 0;
4082 for(std::list<std::string>::const_iterator i = tosend.begin();
4083 i != tosend.end(); ++i)
4085 const std::string &name = *i;
4087 if(m_media.find(name) == m_media.end()){
4088 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4089 <<"unknown file \""<<(name)<<"\""<<std::endl;
4093 //TODO get path + name
4094 std::string tpath = m_media[name].path;
4097 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4098 if(fis.good() == false){
4099 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4100 <<tpath<<"\" for reading"<<std::endl;
4103 std::ostringstream tmp_os(std::ios_base::binary);
4107 fis.read(buf, 1024);
4108 std::streamsize len = fis.gcount();
4109 tmp_os.write(buf, len);
4110 file_size_bunch_total += len;
4119 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4120 <<name<<"\""<<std::endl;
4123 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4124 <<tname<<"\""<<std::endl;*/
4126 file_bunches[file_bunches.size()-1].push_back(
4127 SendableMedia(name, tpath, tmp_os.str()));
4129 // Start next bunch if got enough data
4130 if(file_size_bunch_total >= bytes_per_bunch){
4131 file_bunches.push_back(std::list<SendableMedia>());
4132 file_size_bunch_total = 0;
4137 /* Create and send packets */
4139 u32 num_bunches = file_bunches.size();
4140 for(u32 i=0; i<num_bunches; i++)
4142 std::ostringstream os(std::ios_base::binary);
4146 u16 total number of texture bunches
4147 u16 index of this bunch
4148 u32 number of files in this bunch
4157 writeU16(os, TOCLIENT_MEDIA);
4158 writeU16(os, num_bunches);
4160 writeU32(os, file_bunches[i].size());
4162 for(std::list<SendableMedia>::iterator
4163 j = file_bunches[i].begin();
4164 j != file_bunches[i].end(); ++j){
4165 os<<serializeString(j->name);
4166 os<<serializeLongString(j->data);
4170 std::string s = os.str();
4171 verbosestream<<"Server::sendRequestedMedia(): bunch "
4172 <<i<<"/"<<num_bunches
4173 <<" files="<<file_bunches[i].size()
4174 <<" size=" <<s.size()<<std::endl;
4175 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4177 m_clients.send(peer_id, 2, data, true);
4181 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4183 if(m_detached_inventories.count(name) == 0){
4184 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4187 Inventory *inv = m_detached_inventories[name];
4189 std::ostringstream os(std::ios_base::binary);
4190 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4191 os<<serializeString(name);
4195 std::string s = os.str();
4196 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4198 if (peer_id != PEER_ID_INEXISTENT)
4201 m_clients.send(peer_id, 0, data, true);
4205 m_clients.sendToAll(0,data,true);
4209 void Server::sendDetachedInventories(u16 peer_id)
4211 DSTACK(__FUNCTION_NAME);
4213 for(std::map<std::string, Inventory*>::iterator
4214 i = m_detached_inventories.begin();
4215 i != m_detached_inventories.end(); i++){
4216 const std::string &name = i->first;
4217 //Inventory *inv = i->second;
4218 sendDetachedInventory(name, peer_id);
4226 void Server::DiePlayer(u16 peer_id)
4228 DSTACK(__FUNCTION_NAME);
4230 PlayerSAO *playersao = getPlayerSAO(peer_id);
4233 infostream<<"Server::DiePlayer(): Player "
4234 <<playersao->getPlayer()->getName()
4235 <<" dies"<<std::endl;
4237 playersao->setHP(0);
4239 // Trigger scripted stuff
4240 m_script->on_dieplayer(playersao);
4242 SendPlayerHP(peer_id);
4243 SendDeathscreen(peer_id, false, v3f(0,0,0));
4246 void Server::RespawnPlayer(u16 peer_id)
4248 DSTACK(__FUNCTION_NAME);
4250 PlayerSAO *playersao = getPlayerSAO(peer_id);
4253 infostream<<"Server::RespawnPlayer(): Player "
4254 <<playersao->getPlayer()->getName()
4255 <<" respawns"<<std::endl;
4257 playersao->setHP(PLAYER_MAX_HP);
4259 bool repositioned = m_script->on_respawnplayer(playersao);
4261 v3f pos = findSpawnPos(m_env->getServerMap());
4262 playersao->setPos(pos);
4266 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4268 DSTACK(__FUNCTION_NAME);
4270 SendAccessDenied(peer_id, reason);
4271 m_clients.event(peer_id,SetDenied);
4272 m_con.DisconnectPeer(peer_id);
4275 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4277 DSTACK(__FUNCTION_NAME);
4278 std::wstring message;
4281 Clear references to playing sounds
4283 for(std::map<s32, ServerPlayingSound>::iterator
4284 i = m_playing_sounds.begin();
4285 i != m_playing_sounds.end();)
4287 ServerPlayingSound &psound = i->second;
4288 psound.clients.erase(peer_id);
4289 if(psound.clients.size() == 0)
4290 m_playing_sounds.erase(i++);
4295 Player *player = m_env->getPlayer(peer_id);
4297 // Collect information about leaving in chat
4299 if(player != NULL && reason != CDR_DENY)
4301 std::wstring name = narrow_to_wide(player->getName());
4304 message += L" left the game.";
4305 if(reason == CDR_TIMEOUT)
4306 message += L" (timed out)";
4310 /* Run scripts and remove from environment */
4314 PlayerSAO *playersao = player->getPlayerSAO();
4317 m_script->on_leaveplayer(playersao);
4319 playersao->disconnected();
4327 if(player != NULL && reason != CDR_DENY)
4329 std::ostringstream os(std::ios_base::binary);
4330 std::list<u16> clients = m_clients.getClientIDs();
4332 for(std::list<u16>::iterator
4333 i = clients.begin();
4334 i != clients.end(); ++i)
4337 Player *player = m_env->getPlayer(*i);
4340 // Get name of player
4341 os<<player->getName()<<" ";
4344 actionstream<<player->getName()<<" "
4345 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4346 <<" List of players: "<<os.str()<<std::endl;
4350 JMutexAutoLock env_lock(m_env_mutex);
4351 m_clients.DeleteClient(peer_id);
4355 // Send leave chat message to all remaining clients
4356 if(message.length() != 0)
4357 SendChatMessage(PEER_ID_INEXISTENT,message);
4360 void Server::UpdateCrafting(u16 peer_id)
4362 DSTACK(__FUNCTION_NAME);
4364 Player* player = m_env->getPlayer(peer_id);
4367 // Get a preview for crafting
4369 InventoryLocation loc;
4370 loc.setPlayer(player->getName());
4371 getCraftingResult(&player->inventory, preview, false, this);
4372 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4374 // Put the new preview in
4375 InventoryList *plist = player->inventory.getList("craftpreview");
4377 assert(plist->getSize() >= 1);
4378 plist->changeItem(0, preview);
4381 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4383 RemoteClient *client = getClientNoEx(peer_id,state_min);
4385 throw ClientNotFoundException("Client not found");
4389 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4391 return m_clients.getClientNoEx(peer_id, state_min);
4394 std::string Server::getPlayerName(u16 peer_id)
4396 Player *player = m_env->getPlayer(peer_id);
4398 return "[id="+itos(peer_id)+"]";
4399 return player->getName();
4402 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4404 Player *player = m_env->getPlayer(peer_id);
4407 return player->getPlayerSAO();
4410 std::wstring Server::getStatusString()
4412 std::wostringstream os(std::ios_base::binary);
4415 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4417 os<<L", uptime="<<m_uptime.get();
4419 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4420 // Information about clients
4423 std::list<u16> clients = m_clients.getClientIDs();
4424 for(std::list<u16>::iterator i = clients.begin();
4425 i != clients.end(); ++i)
4428 Player *player = m_env->getPlayer(*i);
4429 // Get name of player
4430 std::wstring name = L"unknown";
4432 name = narrow_to_wide(player->getName());
4433 // Add name to information string
4441 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4442 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4443 if(g_settings->get("motd") != "")
4444 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4448 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4450 std::set<std::string> privs;
4451 m_script->getAuth(name, NULL, &privs);
4455 bool Server::checkPriv(const std::string &name, const std::string &priv)
4457 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4458 return (privs.count(priv) != 0);
4461 void Server::reportPrivsModified(const std::string &name)
4464 std::list<u16> clients = m_clients.getClientIDs();
4465 for(std::list<u16>::iterator
4466 i = clients.begin();
4467 i != clients.end(); ++i){
4468 Player *player = m_env->getPlayer(*i);
4469 reportPrivsModified(player->getName());
4472 Player *player = m_env->getPlayer(name.c_str());
4475 SendPlayerPrivileges(player->peer_id);
4476 PlayerSAO *sao = player->getPlayerSAO();
4479 sao->updatePrivileges(
4480 getPlayerEffectivePrivs(name),
4485 void Server::reportInventoryFormspecModified(const std::string &name)
4487 Player *player = m_env->getPlayer(name.c_str());
4490 SendPlayerInventoryFormspec(player->peer_id);
4493 void Server::setIpBanned(const std::string &ip, const std::string &name)
4495 m_banmanager->add(ip, name);
4498 void Server::unsetIpBanned(const std::string &ip_or_name)
4500 m_banmanager->remove(ip_or_name);
4503 std::string Server::getBanDescription(const std::string &ip_or_name)
4505 return m_banmanager->getBanDescription(ip_or_name);
4508 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4510 Player *player = m_env->getPlayer(name);
4514 if (player->peer_id == PEER_ID_INEXISTENT)
4517 SendChatMessage(player->peer_id, msg);
4520 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4522 Player *player = m_env->getPlayer(playername);
4526 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4530 SendShowFormspecMessage(player->peer_id, formspec, formname);
4534 u32 Server::hudAdd(Player *player, HudElement *form) {
4538 u32 id = player->addHud(form);
4540 SendHUDAdd(player->peer_id, id, form);
4545 bool Server::hudRemove(Player *player, u32 id) {
4549 HudElement* todel = player->removeHud(id);
4556 SendHUDRemove(player->peer_id, id);
4560 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4564 SendHUDChange(player->peer_id, id, stat, data);
4568 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4572 SendHUDSetFlags(player->peer_id, flags, mask);
4573 player->hud_flags = flags;
4575 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4579 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4582 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4585 std::ostringstream os(std::ios::binary);
4586 writeS32(os, hotbar_itemcount);
4587 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4591 void Server::hudSetHotbarImage(Player *player, std::string name) {
4595 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4598 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4602 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4605 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4610 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4614 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4619 SendEyeOffset(player->peer_id, first, third);
4623 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4624 const std::string &type, const std::vector<std::string> ¶ms)
4629 SendSetSky(player->peer_id, bgcolor, type, params);
4633 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4639 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4643 void Server::notifyPlayers(const std::wstring &msg)
4645 SendChatMessage(PEER_ID_INEXISTENT,msg);
4648 void Server::spawnParticle(const char *playername, v3f pos,
4649 v3f velocity, v3f acceleration,
4650 float expirationtime, float size, bool
4651 collisiondetection, bool vertical, std::string texture)
4653 Player *player = m_env->getPlayer(playername);
4656 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4657 expirationtime, size, collisiondetection, vertical, texture);
4660 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4661 float expirationtime, float size,
4662 bool collisiondetection, bool vertical, std::string texture)
4664 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4665 expirationtime, size, collisiondetection, vertical, texture);
4668 u32 Server::addParticleSpawner(const char *playername,
4669 u16 amount, float spawntime,
4670 v3f minpos, v3f maxpos,
4671 v3f minvel, v3f maxvel,
4672 v3f minacc, v3f maxacc,
4673 float minexptime, float maxexptime,
4674 float minsize, float maxsize,
4675 bool collisiondetection, bool vertical, std::string texture)
4677 Player *player = m_env->getPlayer(playername);
4682 for(;;) // look for unused particlespawner id
4685 if (std::find(m_particlespawner_ids.begin(),
4686 m_particlespawner_ids.end(), id)
4687 == m_particlespawner_ids.end())
4689 m_particlespawner_ids.push_back(id);
4694 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4695 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4696 minexptime, maxexptime, minsize, maxsize,
4697 collisiondetection, vertical, texture, id);
4702 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4703 v3f minpos, v3f maxpos,
4704 v3f minvel, v3f maxvel,
4705 v3f minacc, v3f maxacc,
4706 float minexptime, float maxexptime,
4707 float minsize, float maxsize,
4708 bool collisiondetection, bool vertical, std::string texture)
4711 for(;;) // look for unused particlespawner id
4714 if (std::find(m_particlespawner_ids.begin(),
4715 m_particlespawner_ids.end(), id)
4716 == m_particlespawner_ids.end())
4718 m_particlespawner_ids.push_back(id);
4723 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4724 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4725 minexptime, maxexptime, minsize, maxsize,
4726 collisiondetection, vertical, texture, id);
4731 void Server::deleteParticleSpawner(const char *playername, u32 id)
4733 Player *player = m_env->getPlayer(playername);
4737 m_particlespawner_ids.erase(
4738 std::remove(m_particlespawner_ids.begin(),
4739 m_particlespawner_ids.end(), id),
4740 m_particlespawner_ids.end());
4741 SendDeleteParticleSpawner(player->peer_id, id);
4744 void Server::deleteParticleSpawnerAll(u32 id)
4746 m_particlespawner_ids.erase(
4747 std::remove(m_particlespawner_ids.begin(),
4748 m_particlespawner_ids.end(), id),
4749 m_particlespawner_ids.end());
4750 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4753 Inventory* Server::createDetachedInventory(const std::string &name)
4755 if(m_detached_inventories.count(name) > 0){
4756 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4757 delete m_detached_inventories[name];
4759 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4761 Inventory *inv = new Inventory(m_itemdef);
4763 m_detached_inventories[name] = inv;
4764 //TODO find a better way to do this
4765 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4772 BoolScopeSet(bool *dst, bool val):
4775 m_orig_state = *m_dst;
4780 *m_dst = m_orig_state;
4787 // actions: time-reversed list
4788 // Return value: success/failure
4789 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4790 std::list<std::string> *log)
4792 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4793 ServerMap *map = (ServerMap*)(&m_env->getMap());
4794 // Disable rollback report sink while reverting
4795 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4797 // Fail if no actions to handle
4798 if(actions.empty()){
4799 log->push_back("Nothing to do.");
4806 for(std::list<RollbackAction>::const_iterator
4807 i = actions.begin();
4808 i != actions.end(); i++)
4810 const RollbackAction &action = *i;
4812 bool success = action.applyRevert(map, this, this);
4815 std::ostringstream os;
4816 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4817 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4819 log->push_back(os.str());
4821 std::ostringstream os;
4822 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4823 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4825 log->push_back(os.str());
4829 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4830 <<" failed"<<std::endl;
4832 // Call it done if less than half failed
4833 return num_failed <= num_tried/2;
4836 // IGameDef interface
4838 IItemDefManager* Server::getItemDefManager()
4842 INodeDefManager* Server::getNodeDefManager()
4846 ICraftDefManager* Server::getCraftDefManager()
4850 ITextureSource* Server::getTextureSource()
4854 IShaderSource* Server::getShaderSource()
4858 u16 Server::allocateUnknownNodeId(const std::string &name)
4860 return m_nodedef->allocateDummy(name);
4862 ISoundManager* Server::getSoundManager()
4864 return &dummySoundManager;
4866 MtEventManager* Server::getEventManager()
4870 IRollbackReportSink* Server::getRollbackReportSink()
4872 if(!m_enable_rollback_recording)
4874 if(!m_rollback_sink_enabled)
4879 IWritableItemDefManager* Server::getWritableItemDefManager()
4883 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4887 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4892 const ModSpec* Server::getModSpec(const std::string &modname)
4894 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4895 i != m_mods.end(); i++){
4896 const ModSpec &mod = *i;
4897 if(mod.name == modname)
4902 void Server::getModNames(std::list<std::string> &modlist)
4904 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4906 modlist.push_back(i->name);
4909 std::string Server::getBuiltinLuaPath()
4911 return porting::path_share + DIR_DELIM + "builtin";
4914 v3f findSpawnPos(ServerMap &map)
4916 //return v3f(50,50,50)*BS;
4921 nodepos = v2s16(0,0);
4926 s16 water_level = map.getWaterLevel();
4928 // Try to find a good place a few times
4929 for(s32 i=0; i<1000; i++)
4932 // We're going to try to throw the player to this position
4933 v2s16 nodepos2d = v2s16(
4934 -range + (myrand() % (range * 2)),
4935 -range + (myrand() % (range * 2)));
4937 // Get ground height at point
4938 s16 groundheight = map.findGroundLevel(nodepos2d);
4939 if (groundheight <= water_level) // Don't go underwater
4941 if (groundheight > water_level + 6) // Don't go to high places
4944 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4945 bool is_good = false;
4947 for (s32 i = 0; i < 10; i++) {
4948 v3s16 blockpos = getNodeBlockPos(nodepos);
4949 map.emergeBlock(blockpos, true);
4950 content_t c = map.getNodeNoEx(nodepos).getContent();
4951 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4953 if (air_count >= 2){
4961 // Found a good place
4962 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4968 return intToFloat(nodepos, BS);
4971 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4973 RemotePlayer *player = NULL;
4974 bool newplayer = false;
4977 Try to get an existing player
4979 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4981 // If player is already connected, cancel
4982 if(player != NULL && player->peer_id != 0)
4984 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4989 If player with the wanted peer_id already exists, cancel.
4991 if(m_env->getPlayer(peer_id) != NULL)
4993 infostream<<"emergePlayer(): Player with wrong name but same"
4994 " peer_id already exists"<<std::endl;
4998 // Load player if it isn't already loaded
5000 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5003 // Create player if it doesn't exist
5006 player = new RemotePlayer(this);
5007 player->updateName(name);
5008 /* Set player position */
5009 infostream<<"Server: Finding spawn place for player \""
5010 <<name<<"\""<<std::endl;
5011 v3f pos = findSpawnPos(m_env->getServerMap());
5012 player->setPosition(pos);
5014 /* Add player to environment */
5015 m_env->addPlayer(player);
5018 // Create a new player active object
5019 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5020 getPlayerEffectivePrivs(player->getName()),
5023 /* Clean up old HUD elements from previous sessions */
5026 /* Add object to environment */
5027 m_env->addActiveObject(playersao);
5031 m_script->on_newplayer(playersao);
5037 void dedicated_server_loop(Server &server, bool &kill)
5039 DSTACK(__FUNCTION_NAME);
5041 verbosestream<<"dedicated_server_loop()"<<std::endl;
5043 IntervalLimiter m_profiler_interval;
5047 float steplen = g_settings->getFloat("dedicated_server_step");
5048 // This is kind of a hack but can be done like this
5049 // because server.step() is very light
5051 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5052 sleep_ms((int)(steplen*1000.0));
5054 server.step(steplen);
5056 if(server.getShutdownRequested() || kill)
5058 infostream<<"Dedicated server quitting"<<std::endl;
5060 if(g_settings->getBool("server_announce") == true)
5061 ServerList::sendAnnounce("delete");
5069 float profiler_print_interval =
5070 g_settings->getFloat("profiler_print_interval");
5071 if(profiler_print_interval != 0)
5073 if(m_profiler_interval.step(steplen, profiler_print_interval))
5075 infostream<<"Profiler:"<<std::endl;
5076 g_profiler->print(infostream);
5077 g_profiler->clear();