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"))
681 ServerList::sendAnnounce(counter ? "update" : "start",
682 m_clients.getPlayerNames(),
684 m_env->getGameTime(),
695 Check added and deleted active objects
698 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
699 JMutexAutoLock envlock(m_env_mutex);
702 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
703 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
705 // Radius inside which objects are active
706 s16 radius = g_settings->getS16("active_object_send_range_blocks");
707 radius *= MAP_BLOCKSIZE;
709 for(std::map<u16, RemoteClient*>::iterator
711 i != clients.end(); ++i)
713 RemoteClient *client = i->second;
715 // If definitions and textures have not been sent, don't
716 // send objects either
717 if (client->getState() < CS_DefinitionsSent)
720 Player *player = m_env->getPlayer(client->peer_id);
723 // This can happen if the client timeouts somehow
724 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
726 <<" has no associated player"<<std::endl;*/
729 v3s16 pos = floatToInt(player->getPosition(), BS);
731 std::set<u16> removed_objects;
732 std::set<u16> added_objects;
733 m_env->getRemovedActiveObjects(pos, radius,
734 client->m_known_objects, removed_objects);
735 m_env->getAddedActiveObjects(pos, radius,
736 client->m_known_objects, added_objects);
738 // Ignore if nothing happened
739 if(removed_objects.size() == 0 && added_objects.size() == 0)
741 //infostream<<"active objects: none changed"<<std::endl;
745 std::string data_buffer;
749 // Handle removed objects
750 writeU16((u8*)buf, removed_objects.size());
751 data_buffer.append(buf, 2);
752 for(std::set<u16>::iterator
753 i = removed_objects.begin();
754 i != removed_objects.end(); ++i)
758 ServerActiveObject* obj = m_env->getActiveObject(id);
760 // Add to data buffer for sending
761 writeU16((u8*)buf, id);
762 data_buffer.append(buf, 2);
764 // Remove from known objects
765 client->m_known_objects.erase(id);
767 if(obj && obj->m_known_by_count > 0)
768 obj->m_known_by_count--;
771 // Handle added objects
772 writeU16((u8*)buf, added_objects.size());
773 data_buffer.append(buf, 2);
774 for(std::set<u16>::iterator
775 i = added_objects.begin();
776 i != added_objects.end(); ++i)
780 ServerActiveObject* obj = m_env->getActiveObject(id);
783 u8 type = ACTIVEOBJECT_TYPE_INVALID;
785 infostream<<"WARNING: "<<__FUNCTION_NAME
786 <<": NULL object"<<std::endl;
788 type = obj->getSendType();
790 // Add to data buffer for sending
791 writeU16((u8*)buf, id);
792 data_buffer.append(buf, 2);
793 writeU8((u8*)buf, type);
794 data_buffer.append(buf, 1);
797 data_buffer.append(serializeLongString(
798 obj->getClientInitializationData(client->net_proto_version)));
800 data_buffer.append(serializeLongString(""));
802 // Add to known objects
803 client->m_known_objects.insert(id);
806 obj->m_known_by_count++;
810 SharedBuffer<u8> reply(2 + data_buffer.size());
811 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
812 memcpy((char*)&reply[2], data_buffer.c_str(),
815 m_clients.send(client->peer_id, 0, reply, true);
817 verbosestream<<"Server: Sent object remove/add: "
818 <<removed_objects.size()<<" removed, "
819 <<added_objects.size()<<" added, "
820 <<"packet size is "<<reply.getSize()<<std::endl;
825 Collect a list of all the objects known by the clients
826 and report it back to the environment.
829 core::map<u16, bool> all_known_objects;
831 for(core::map<u16, RemoteClient*>::Iterator
832 i = m_clients.getIterator();
833 i.atEnd() == false; i++)
835 RemoteClient *client = i.getNode()->getValue();
836 // Go through all known objects of client
837 for(core::map<u16, bool>::Iterator
838 i = client->m_known_objects.getIterator();
839 i.atEnd()==false; i++)
841 u16 id = i.getNode()->getKey();
842 all_known_objects[id] = true;
846 m_env->setKnownActiveObjects(whatever);
855 JMutexAutoLock envlock(m_env_mutex);
856 ScopeProfiler sp(g_profiler, "Server: sending object messages");
859 // Value = data sent by object
860 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
862 // Get active object messages from environment
865 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
869 std::list<ActiveObjectMessage>* message_list = NULL;
870 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
871 n = buffered_messages.find(aom.id);
872 if(n == buffered_messages.end())
874 message_list = new std::list<ActiveObjectMessage>;
875 buffered_messages[aom.id] = message_list;
879 message_list = n->second;
881 message_list->push_back(aom);
885 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
886 // Route data to every client
887 for(std::map<u16, RemoteClient*>::iterator
889 i != clients.end(); ++i)
891 RemoteClient *client = i->second;
892 std::string reliable_data;
893 std::string unreliable_data;
894 // Go through all objects in message buffer
895 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
896 j = buffered_messages.begin();
897 j != buffered_messages.end(); ++j)
899 // If object is not known by client, skip it
901 if(client->m_known_objects.find(id) == client->m_known_objects.end())
903 // Get message list of object
904 std::list<ActiveObjectMessage>* list = j->second;
905 // Go through every message
906 for(std::list<ActiveObjectMessage>::iterator
907 k = list->begin(); k != list->end(); ++k)
909 // Compose the full new data with header
910 ActiveObjectMessage aom = *k;
911 std::string new_data;
914 writeU16((u8*)&buf[0], aom.id);
915 new_data.append(buf, 2);
917 new_data += serializeString(aom.datastring);
918 // Add data to buffer
920 reliable_data += new_data;
922 unreliable_data += new_data;
926 reliable_data and unreliable_data are now ready.
929 if(reliable_data.size() > 0)
931 SharedBuffer<u8> reply(2 + reliable_data.size());
932 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
933 memcpy((char*)&reply[2], reliable_data.c_str(),
934 reliable_data.size());
936 m_clients.send(client->peer_id, 0, reply, true);
938 if(unreliable_data.size() > 0)
940 SharedBuffer<u8> reply(2 + unreliable_data.size());
941 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
942 memcpy((char*)&reply[2], unreliable_data.c_str(),
943 unreliable_data.size());
944 // Send as unreliable
945 m_clients.send(client->peer_id, 1, reply, false);
948 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
950 infostream<<"Server: Size of object message data: "
951 <<"reliable: "<<reliable_data.size()
952 <<", unreliable: "<<unreliable_data.size()
958 // Clear buffered_messages
959 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
960 i = buffered_messages.begin();
961 i != buffered_messages.end(); ++i)
968 Send queued-for-sending map edit events.
971 // We will be accessing the environment
972 JMutexAutoLock lock(m_env_mutex);
974 // Don't send too many at a time
977 // Single change sending is disabled if queue size is not small
978 bool disable_single_change_sending = false;
979 if(m_unsent_map_edit_queue.size() >= 4)
980 disable_single_change_sending = true;
982 int event_count = m_unsent_map_edit_queue.size();
984 // We'll log the amount of each
987 while(m_unsent_map_edit_queue.size() != 0)
989 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
991 // Players far away from the change are stored here.
992 // Instead of sending the changes, MapBlocks are set not sent
994 std::list<u16> far_players;
996 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
998 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
999 prof.add("MEET_ADDNODE", 1);
1000 if(disable_single_change_sending)
1001 sendAddNode(event->p, event->n, event->already_known_by_peer,
1002 &far_players, 5, event->type == MEET_ADDNODE);
1004 sendAddNode(event->p, event->n, event->already_known_by_peer,
1005 &far_players, 30, event->type == MEET_ADDNODE);
1007 else if(event->type == MEET_REMOVENODE)
1009 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1010 prof.add("MEET_REMOVENODE", 1);
1011 if(disable_single_change_sending)
1012 sendRemoveNode(event->p, event->already_known_by_peer,
1015 sendRemoveNode(event->p, event->already_known_by_peer,
1018 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1020 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1021 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1022 setBlockNotSent(event->p);
1024 else if(event->type == MEET_OTHER)
1026 infostream<<"Server: MEET_OTHER"<<std::endl;
1027 prof.add("MEET_OTHER", 1);
1028 for(std::set<v3s16>::iterator
1029 i = event->modified_blocks.begin();
1030 i != event->modified_blocks.end(); ++i)
1032 setBlockNotSent(*i);
1037 prof.add("unknown", 1);
1038 infostream<<"WARNING: Server: Unknown MapEditEvent "
1039 <<((u32)event->type)<<std::endl;
1043 Set blocks not sent to far players
1045 if(far_players.size() > 0)
1047 // Convert list format to that wanted by SetBlocksNotSent
1048 std::map<v3s16, MapBlock*> modified_blocks2;
1049 for(std::set<v3s16>::iterator
1050 i = event->modified_blocks.begin();
1051 i != event->modified_blocks.end(); ++i)
1053 modified_blocks2[*i] =
1054 m_env->getMap().getBlockNoCreateNoEx(*i);
1056 // Set blocks not sent
1057 for(std::list<u16>::iterator
1058 i = far_players.begin();
1059 i != far_players.end(); ++i)
1062 RemoteClient *client = getClient(peer_id);
1065 client->SetBlocksNotSent(modified_blocks2);
1071 /*// Don't send too many at a time
1073 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1077 if(event_count >= 5){
1078 infostream<<"Server: MapEditEvents:"<<std::endl;
1079 prof.print(infostream);
1080 } else if(event_count != 0){
1081 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1082 prof.print(verbosestream);
1088 Trigger emergethread (it somehow gets to a non-triggered but
1089 bysy state sometimes)
1092 float &counter = m_emergethread_trigger_timer;
1098 m_emerge->startThreads();
1100 // Update m_enable_rollback_recording here too
1101 m_enable_rollback_recording =
1102 g_settings->getBool("enable_rollback_recording");
1106 // Save map, players and auth stuff
1108 float &counter = m_savemap_timer;
1110 if(counter >= g_settings->getFloat("server_map_save_interval"))
1113 JMutexAutoLock lock(m_env_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1118 if (m_banmanager->isModified()) {
1119 m_banmanager->save();
1122 // Save changed parts of map
1123 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1126 m_env->saveLoadedPlayers();
1128 // Save environment metadata
1134 void Server::Receive()
1136 DSTACK(__FUNCTION_NAME);
1137 SharedBuffer<u8> data;
1141 datasize = m_con.Receive(peer_id,data);
1142 ProcessData(*data, datasize, peer_id);
1144 catch(con::InvalidIncomingDataException &e)
1146 infostream<<"Server::Receive(): "
1147 "InvalidIncomingDataException: what()="
1148 <<e.what()<<std::endl;
1150 catch(SerializationError &e) {
1151 infostream<<"Server::Receive(): "
1152 "SerializationError: what()="
1153 <<e.what()<<std::endl;
1155 catch(ClientStateError &e)
1157 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1158 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1159 L"Try reconnecting or updating your client");
1161 catch(con::PeerNotFoundException &e)
1167 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1169 std::string playername = "";
1170 PlayerSAO *playersao = NULL;
1172 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1173 if (client != NULL) {
1174 playername = client->getName();
1175 playersao = emergePlayer(playername.c_str(), peer_id);
1179 RemotePlayer *player =
1180 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1182 // If failed, cancel
1183 if((playersao == NULL) || (player == NULL))
1185 if(player && player->peer_id != 0){
1186 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1187 <<" (player allocated to an another client)"<<std::endl;
1188 DenyAccess(peer_id, L"Another client is connected with this "
1189 L"name. If your client closed unexpectedly, try again in "
1192 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1194 DenyAccess(peer_id, L"Could not allocate player.");
1200 Send complete position information
1202 SendMovePlayer(peer_id);
1205 SendPlayerPrivileges(peer_id);
1207 // Send inventory formspec
1208 SendPlayerInventoryFormspec(peer_id);
1211 UpdateCrafting(peer_id);
1212 SendInventory(peer_id);
1215 if(g_settings->getBool("enable_damage"))
1216 SendPlayerHP(peer_id);
1219 SendPlayerBreath(peer_id);
1221 // Show death screen if necessary
1223 SendDeathscreen(peer_id, false, v3f(0,0,0));
1225 // Note things in chat if not in simple singleplayer mode
1226 if(!m_simple_singleplayer_mode)
1228 // Send information about server to player in chat
1229 SendChatMessage(peer_id, getStatusString());
1231 // Send information about joining in chat
1233 std::wstring name = L"unknown";
1234 Player *player = m_env->getPlayer(peer_id);
1236 name = narrow_to_wide(player->getName());
1238 std::wstring message;
1241 message += L" joined the game.";
1242 SendChatMessage(PEER_ID_INEXISTENT,message);
1245 Address addr = getPeerAddress(player->peer_id);
1246 std::string ip_str = addr.serializeString();
1247 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1252 std::vector<std::string> names = m_clients.getPlayerNames();
1254 actionstream<<player->getName() <<" joins game. List of players: ";
1256 for (std::vector<std::string>::iterator i = names.begin();
1257 i != names.end(); i++)
1259 actionstream << *i << " ";
1262 actionstream << player->getName() <<std::endl;
1267 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1269 DSTACK(__FUNCTION_NAME);
1270 // Environment is locked first.
1271 JMutexAutoLock envlock(m_env_mutex);
1273 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1277 Address address = getPeerAddress(peer_id);
1278 addr_s = address.serializeString();
1280 // drop player if is ip is banned
1281 if(m_banmanager->isIpBanned(addr_s)){
1282 std::string ban_name = m_banmanager->getBanName(addr_s);
1283 infostream<<"Server: A banned client tried to connect from "
1284 <<addr_s<<"; banned name was "
1285 <<ban_name<<std::endl;
1286 // This actually doesn't seem to transfer to the client
1287 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1288 +narrow_to_wide(ban_name));
1292 catch(con::PeerNotFoundException &e)
1295 * no peer for this packet found
1296 * most common reason is peer timeout, e.g. peer didn't
1297 * respond for some time, your server was overloaded or
1300 infostream<<"Server::ProcessData(): Cancelling: peer "
1301 <<peer_id<<" not found"<<std::endl;
1311 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1313 if(command == TOSERVER_INIT)
1315 // [0] u16 TOSERVER_INIT
1316 // [2] u8 SER_FMT_VER_HIGHEST_READ
1317 // [3] u8[20] player_name
1318 // [23] u8[28] password <--- can be sent without this, from old versions
1320 if(datasize < 2+1+PLAYERNAME_SIZE)
1323 RemoteClient* client = getClient(peer_id, CS_Created);
1325 // If net_proto_version is set, this client has already been handled
1326 if(client->getState() > CS_Created)
1328 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1329 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1333 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1334 <<peer_id<<")"<<std::endl;
1336 // Do not allow multiple players in simple singleplayer mode.
1337 // This isn't a perfect way to do it, but will suffice for now
1338 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1339 infostream<<"Server: Not allowing another client ("<<addr_s
1340 <<") to connect in simple singleplayer mode"<<std::endl;
1341 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1345 // First byte after command is maximum supported
1346 // serialization version
1347 u8 client_max = data[2];
1348 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1349 // Use the highest version supported by both
1350 u8 deployed = std::min(client_max, our_max);
1351 // If it's lower than the lowest supported, give up.
1352 if(deployed < SER_FMT_VER_LOWEST)
1353 deployed = SER_FMT_VER_INVALID;
1355 if(deployed == SER_FMT_VER_INVALID)
1357 actionstream<<"Server: A mismatched client tried to connect from "
1358 <<addr_s<<std::endl;
1359 infostream<<"Server: Cannot negotiate serialization version with "
1360 <<addr_s<<std::endl;
1361 DenyAccess(peer_id, std::wstring(
1362 L"Your client's version is not supported.\n"
1363 L"Server version is ")
1364 + narrow_to_wide(minetest_version_simple) + L"."
1369 client->setPendingSerializationVersion(deployed);
1372 Read and check network protocol version
1375 u16 min_net_proto_version = 0;
1376 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1377 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1379 // Use same version as minimum and maximum if maximum version field
1380 // doesn't exist (backwards compatibility)
1381 u16 max_net_proto_version = min_net_proto_version;
1382 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1383 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1385 // Start with client's maximum version
1386 u16 net_proto_version = max_net_proto_version;
1388 // Figure out a working version if it is possible at all
1389 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1390 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1392 // If maximum is larger than our maximum, go with our maximum
1393 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1394 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1395 // Else go with client's maximum
1397 net_proto_version = max_net_proto_version;
1400 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1401 <<min_net_proto_version<<", max: "<<max_net_proto_version
1402 <<", chosen: "<<net_proto_version<<std::endl;
1404 client->net_proto_version = net_proto_version;
1406 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1407 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1409 actionstream<<"Server: A mismatched client tried to connect from "
1410 <<addr_s<<std::endl;
1411 DenyAccess(peer_id, std::wstring(
1412 L"Your client's version is not supported.\n"
1413 L"Server version is ")
1414 + narrow_to_wide(minetest_version_simple) + L",\n"
1415 + L"server's PROTOCOL_VERSION is "
1416 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1418 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1419 + L", client's PROTOCOL_VERSION is "
1420 + narrow_to_wide(itos(min_net_proto_version))
1422 + narrow_to_wide(itos(max_net_proto_version))
1427 if(g_settings->getBool("strict_protocol_version_checking"))
1429 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1431 actionstream<<"Server: A mismatched (strict) client tried to "
1432 <<"connect from "<<addr_s<<std::endl;
1433 DenyAccess(peer_id, std::wstring(
1434 L"Your client's version is not supported.\n"
1435 L"Server version is ")
1436 + narrow_to_wide(minetest_version_simple) + L",\n"
1437 + L"server's PROTOCOL_VERSION (strict) is "
1438 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1439 + L", client's PROTOCOL_VERSION is "
1440 + narrow_to_wide(itos(min_net_proto_version))
1442 + narrow_to_wide(itos(max_net_proto_version))
1453 char playername[PLAYERNAME_SIZE];
1454 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1456 playername[i] = data[3+i];
1458 playername[PLAYERNAME_SIZE-1] = 0;
1460 if(playername[0]=='\0')
1462 actionstream<<"Server: Player with an empty name "
1463 <<"tried to connect from "<<addr_s<<std::endl;
1464 DenyAccess(peer_id, L"Empty name");
1468 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1470 actionstream<<"Server: Player with an invalid name "
1471 <<"tried to connect from "<<addr_s<<std::endl;
1472 DenyAccess(peer_id, L"Name contains unallowed characters");
1476 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1478 actionstream<<"Server: Player with the name \"singleplayer\" "
1479 <<"tried to connect from "<<addr_s<<std::endl;
1480 DenyAccess(peer_id, L"Name is not allowed");
1486 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1488 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1489 <<"tried to connect from "<<addr_s<<" "
1490 <<"but it was disallowed for the following reason: "
1491 <<reason<<std::endl;
1492 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1497 infostream<<"Server: New connection: \""<<playername<<"\" from "
1498 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1501 char given_password[PASSWORD_SIZE];
1502 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1504 // old version - assume blank password
1505 given_password[0] = 0;
1509 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1511 given_password[i] = data[23+i];
1513 given_password[PASSWORD_SIZE-1] = 0;
1516 if(!base64_is_valid(given_password)){
1517 actionstream<<"Server: "<<playername
1518 <<" supplied invalid password hash"<<std::endl;
1519 DenyAccess(peer_id, L"Invalid password hash");
1523 // Enforce user limit.
1524 // Don't enforce for users that have some admin right
1525 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1526 !checkPriv(playername, "server") &&
1527 !checkPriv(playername, "ban") &&
1528 !checkPriv(playername, "privs") &&
1529 !checkPriv(playername, "password") &&
1530 playername != g_settings->get("name"))
1532 actionstream<<"Server: "<<playername<<" tried to join, but there"
1533 <<" are already max_users="
1534 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1535 DenyAccess(peer_id, L"Too many users.");
1539 std::string checkpwd; // Password hash to check against
1540 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1542 // If no authentication info exists for user, create it
1544 if(!isSingleplayer() &&
1545 g_settings->getBool("disallow_empty_password") &&
1546 std::string(given_password) == ""){
1547 actionstream<<"Server: "<<playername
1548 <<" supplied empty password"<<std::endl;
1549 DenyAccess(peer_id, L"Empty passwords are "
1550 L"disallowed. Set a password and try again.");
1553 std::wstring raw_default_password =
1554 narrow_to_wide(g_settings->get("default_password"));
1555 std::string initial_password =
1556 translatePassword(playername, raw_default_password);
1558 // If default_password is empty, allow any initial password
1559 if (raw_default_password.length() == 0)
1560 initial_password = given_password;
1562 m_script->createAuth(playername, initial_password);
1565 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1568 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1569 <<" (auth handler does not work?)"<<std::endl;
1570 DenyAccess(peer_id, L"Not allowed to login");
1574 if(given_password != checkpwd){
1575 actionstream<<"Server: "<<playername<<" supplied wrong password"
1577 DenyAccess(peer_id, L"Wrong password");
1581 RemotePlayer *player =
1582 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1584 if(player && player->peer_id != 0){
1585 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1586 <<" (player allocated to an another client)"<<std::endl;
1587 DenyAccess(peer_id, L"Another client is connected with this "
1588 L"name. If your client closed unexpectedly, try again in "
1592 m_clients.setPlayerName(peer_id,playername);
1595 Answer with a TOCLIENT_INIT
1598 SharedBuffer<u8> reply(2+1+6+8+4);
1599 writeU16(&reply[0], TOCLIENT_INIT);
1600 writeU8(&reply[2], deployed);
1601 //send dummy pos for legacy reasons only
1602 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1603 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1604 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1607 m_clients.send(peer_id, 0, reply, true);
1608 m_clients.event(peer_id, CSE_Init);
1614 if(command == TOSERVER_INIT2)
1617 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1618 <<peer_id<<std::endl;
1620 m_clients.event(peer_id, CSE_GotInit2);
1621 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1624 ///// begin compatibility code
1625 PlayerSAO* playersao = NULL;
1626 if (protocol_version <= 22) {
1627 playersao = StageTwoClientInit(peer_id);
1629 if (playersao == NULL) {
1631 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1632 << peer_id << std::endl;
1636 ///// end compatibility code
1639 Send some initialization data
1642 infostream<<"Server: Sending content to "
1643 <<getPlayerName(peer_id)<<std::endl;
1645 // Send player movement settings
1646 SendMovement(peer_id);
1648 // Send item definitions
1649 SendItemDef(peer_id, m_itemdef, protocol_version);
1651 // Send node definitions
1652 SendNodeDef(peer_id, m_nodedef, protocol_version);
1654 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1656 // Send media announcement
1657 sendMediaAnnouncement(peer_id);
1659 // Send detached inventories
1660 sendDetachedInventories(peer_id);
1663 u16 time = m_env->getTimeOfDay();
1664 float time_speed = g_settings->getFloat("time_speed");
1665 SendTimeOfDay(peer_id, time, time_speed);
1667 ///// begin compatibility code
1668 if (protocol_version <= 22) {
1669 m_clients.event(peer_id, CSE_SetClientReady);
1670 m_script->on_joinplayer(playersao);
1672 ///// end compatibility code
1674 // Warnings about protocol version can be issued here
1675 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1677 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1678 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1684 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1685 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1687 if(peer_ser_ver == SER_FMT_VER_INVALID)
1689 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1690 " serialization format invalid or not initialized."
1691 " Skipping incoming command="<<command<<std::endl;
1695 /* Handle commands relate to client startup */
1696 if(command == TOSERVER_REQUEST_MEDIA) {
1697 std::string datastring((char*)&data[2], datasize-2);
1698 std::istringstream is(datastring, std::ios_base::binary);
1700 std::list<std::string> tosend;
1701 u16 numfiles = readU16(is);
1703 infostream<<"Sending "<<numfiles<<" files to "
1704 <<getPlayerName(peer_id)<<std::endl;
1705 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1707 for(int i = 0; i < numfiles; i++) {
1708 std::string name = deSerializeString(is);
1709 tosend.push_back(name);
1710 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1714 sendRequestedMedia(peer_id, tosend);
1717 else if(command == TOSERVER_RECEIVED_MEDIA) {
1720 else if(command == TOSERVER_CLIENT_READY) {
1721 // clients <= protocol version 22 did not send ready message,
1722 // they're already initialized
1723 if (peer_proto_ver <= 22) {
1724 infostream << "Client sent message not expected by a "
1725 << "client using protocol version <= 22,"
1726 << "disconnecing peer_id: " << peer_id << std::endl;
1727 m_con.DisconnectPeer(peer_id);
1731 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1733 if (playersao == NULL) {
1735 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1736 << peer_id << std::endl;
1744 m_clients.setClientVersion(
1746 data[2], data[3], data[4],
1747 std::string((char*) &data[8],(u16) data[6]));
1749 m_clients.event(peer_id, CSE_SetClientReady);
1750 m_script->on_joinplayer(playersao);
1753 else if(command == TOSERVER_GOTBLOCKS)
1766 u16 count = data[2];
1767 for(u16 i=0; i<count; i++)
1769 if((s16)datasize < 2+1+(i+1)*6)
1770 throw con::InvalidIncomingDataException
1771 ("GOTBLOCKS length is too short");
1772 v3s16 p = readV3S16(&data[2+1+i*6]);
1773 /*infostream<<"Server: GOTBLOCKS ("
1774 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1775 RemoteClient *client = getClient(peer_id);
1776 client->GotBlock(p);
1781 if (m_clients.getClientState(peer_id) < CS_Active)
1783 if (command == TOSERVER_PLAYERPOS) return;
1785 errorstream<<"Got packet command: " << command << " for peer id "
1786 << peer_id << " but client isn't active yet. Dropping packet "
1791 Player *player = m_env->getPlayer(peer_id);
1792 if(player == NULL) {
1793 errorstream<<"Server::ProcessData(): Cancelling: "
1794 "No player for peer_id="<<peer_id
1795 << " disconnecting peer!" <<std::endl;
1796 m_con.DisconnectPeer(peer_id);
1800 PlayerSAO *playersao = player->getPlayerSAO();
1801 if(playersao == NULL) {
1802 errorstream<<"Server::ProcessData(): Cancelling: "
1803 "No player object for peer_id="<<peer_id
1804 << " disconnecting peer!" <<std::endl;
1805 m_con.DisconnectPeer(peer_id);
1809 if(command == TOSERVER_PLAYERPOS)
1811 if(datasize < 2+12+12+4+4)
1815 v3s32 ps = readV3S32(&data[start+2]);
1816 v3s32 ss = readV3S32(&data[start+2+12]);
1817 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1818 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1820 if(datasize >= 2+12+12+4+4+4)
1821 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1822 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1823 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1824 pitch = wrapDegrees(pitch);
1825 yaw = wrapDegrees(yaw);
1827 player->setPosition(position);
1828 player->setSpeed(speed);
1829 player->setPitch(pitch);
1830 player->setYaw(yaw);
1831 player->keyPressed=keyPressed;
1832 player->control.up = (bool)(keyPressed&1);
1833 player->control.down = (bool)(keyPressed&2);
1834 player->control.left = (bool)(keyPressed&4);
1835 player->control.right = (bool)(keyPressed&8);
1836 player->control.jump = (bool)(keyPressed&16);
1837 player->control.aux1 = (bool)(keyPressed&32);
1838 player->control.sneak = (bool)(keyPressed&64);
1839 player->control.LMB = (bool)(keyPressed&128);
1840 player->control.RMB = (bool)(keyPressed&256);
1842 bool cheated = playersao->checkMovementCheat();
1845 m_script->on_cheat(playersao, "moved_too_fast");
1848 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1849 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1850 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1852 else if(command == TOSERVER_DELETEDBLOCKS)
1865 u16 count = data[2];
1866 for(u16 i=0; i<count; i++)
1868 if((s16)datasize < 2+1+(i+1)*6)
1869 throw con::InvalidIncomingDataException
1870 ("DELETEDBLOCKS length is too short");
1871 v3s16 p = readV3S16(&data[2+1+i*6]);
1872 /*infostream<<"Server: DELETEDBLOCKS ("
1873 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1874 RemoteClient *client = getClient(peer_id);
1875 client->SetBlockNotSent(p);
1878 else if(command == TOSERVER_CLICK_OBJECT)
1880 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1883 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1885 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1888 else if(command == TOSERVER_GROUND_ACTION)
1890 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1894 else if(command == TOSERVER_RELEASE)
1896 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1899 else if(command == TOSERVER_SIGNTEXT)
1901 infostream<<"Server: SIGNTEXT not supported anymore"
1905 else if(command == TOSERVER_SIGNNODETEXT)
1907 infostream<<"Server: SIGNNODETEXT not supported anymore"
1911 else if(command == TOSERVER_INVENTORY_ACTION)
1913 // Strip command and create a stream
1914 std::string datastring((char*)&data[2], datasize-2);
1915 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1916 std::istringstream is(datastring, std::ios_base::binary);
1918 InventoryAction *a = InventoryAction::deSerialize(is);
1921 infostream<<"TOSERVER_INVENTORY_ACTION: "
1922 <<"InventoryAction::deSerialize() returned NULL"
1927 // If something goes wrong, this player is to blame
1928 RollbackScopeActor rollback_scope(m_rollback,
1929 std::string("player:")+player->getName());
1932 Note: Always set inventory not sent, to repair cases
1933 where the client made a bad prediction.
1937 Handle restrictions and special cases of the move action
1939 if(a->getType() == IACTION_MOVE)
1941 IMoveAction *ma = (IMoveAction*)a;
1943 ma->from_inv.applyCurrentPlayer(player->getName());
1944 ma->to_inv.applyCurrentPlayer(player->getName());
1946 setInventoryModified(ma->from_inv);
1947 setInventoryModified(ma->to_inv);
1949 bool from_inv_is_current_player =
1950 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1951 (ma->from_inv.name == player->getName());
1953 bool to_inv_is_current_player =
1954 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1955 (ma->to_inv.name == player->getName());
1958 Disable moving items out of craftpreview
1960 if(ma->from_list == "craftpreview")
1962 infostream<<"Ignoring IMoveAction from "
1963 <<(ma->from_inv.dump())<<":"<<ma->from_list
1964 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1965 <<" because src is "<<ma->from_list<<std::endl;
1971 Disable moving items into craftresult and craftpreview
1973 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1975 infostream<<"Ignoring IMoveAction from "
1976 <<(ma->from_inv.dump())<<":"<<ma->from_list
1977 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1978 <<" because dst is "<<ma->to_list<<std::endl;
1983 // Disallow moving items in elsewhere than player's inventory
1984 // if not allowed to interact
1985 if(!checkPriv(player->getName(), "interact") &&
1986 (!from_inv_is_current_player ||
1987 !to_inv_is_current_player))
1989 infostream<<"Cannot move outside of player's inventory: "
1990 <<"No interact privilege"<<std::endl;
1996 Handle restrictions and special cases of the drop action
1998 else if(a->getType() == IACTION_DROP)
2000 IDropAction *da = (IDropAction*)a;
2002 da->from_inv.applyCurrentPlayer(player->getName());
2004 setInventoryModified(da->from_inv);
2007 Disable dropping items out of craftpreview
2009 if(da->from_list == "craftpreview")
2011 infostream<<"Ignoring IDropAction from "
2012 <<(da->from_inv.dump())<<":"<<da->from_list
2013 <<" because src is "<<da->from_list<<std::endl;
2018 // Disallow dropping items if not allowed to interact
2019 if(!checkPriv(player->getName(), "interact"))
2026 Handle restrictions and special cases of the craft action
2028 else if(a->getType() == IACTION_CRAFT)
2030 ICraftAction *ca = (ICraftAction*)a;
2032 ca->craft_inv.applyCurrentPlayer(player->getName());
2034 setInventoryModified(ca->craft_inv);
2036 //bool craft_inv_is_current_player =
2037 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2038 // (ca->craft_inv.name == player->getName());
2040 // Disallow crafting if not allowed to interact
2041 if(!checkPriv(player->getName(), "interact"))
2043 infostream<<"Cannot craft: "
2044 <<"No interact privilege"<<std::endl;
2051 a->apply(this, playersao, this);
2055 else if(command == TOSERVER_CHAT_MESSAGE)
2063 std::string datastring((char*)&data[2], datasize-2);
2064 std::istringstream is(datastring, std::ios_base::binary);
2067 is.read((char*)buf, 2);
2068 u16 len = readU16(buf);
2070 std::wstring message;
2071 for(u16 i=0; i<len; i++)
2073 is.read((char*)buf, 2);
2074 message += (wchar_t)readU16(buf);
2077 // If something goes wrong, this player is to blame
2078 RollbackScopeActor rollback_scope(m_rollback,
2079 std::string("player:")+player->getName());
2081 // Get player name of this client
2082 std::wstring name = narrow_to_wide(player->getName());
2085 bool ate = m_script->on_chat_message(player->getName(),
2086 wide_to_narrow(message));
2087 // If script ate the message, don't proceed
2091 // Line to send to players
2093 // Whether to send to the player that sent the line
2094 bool send_to_sender_only = false;
2096 // Commands are implemented in Lua, so only catch invalid
2097 // commands that were not "eaten" and send an error back
2098 if(message[0] == L'/')
2100 message = message.substr(1);
2101 send_to_sender_only = true;
2102 if(message.length() == 0)
2103 line += L"-!- Empty command";
2105 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2109 if(checkPriv(player->getName(), "shout")){
2115 line += L"-!- You don't have permission to shout.";
2116 send_to_sender_only = true;
2123 Send the message to sender
2125 if (send_to_sender_only)
2127 SendChatMessage(peer_id, line);
2130 Send the message to others
2134 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2136 std::list<u16> clients = m_clients.getClientIDs();
2138 for(std::list<u16>::iterator
2139 i = clients.begin();
2140 i != clients.end(); ++i)
2143 SendChatMessage(*i, line);
2148 else if(command == TOSERVER_DAMAGE)
2150 std::string datastring((char*)&data[2], datasize-2);
2151 std::istringstream is(datastring, std::ios_base::binary);
2152 u8 damage = readU8(is);
2154 if(g_settings->getBool("enable_damage"))
2156 actionstream<<player->getName()<<" damaged by "
2157 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2160 playersao->setHP(playersao->getHP() - damage);
2162 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2165 if(playersao->m_hp_not_sent)
2166 SendPlayerHP(peer_id);
2169 else if(command == TOSERVER_BREATH)
2171 std::string datastring((char*)&data[2], datasize-2);
2172 std::istringstream is(datastring, std::ios_base::binary);
2173 u16 breath = readU16(is);
2174 playersao->setBreath(breath);
2175 m_script->player_event(playersao,"breath_changed");
2177 else if(command == TOSERVER_PASSWORD)
2180 [0] u16 TOSERVER_PASSWORD
2181 [2] u8[28] old password
2182 [30] u8[28] new password
2185 if(datasize != 2+PASSWORD_SIZE*2)
2187 /*char password[PASSWORD_SIZE];
2188 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2189 password[i] = data[2+i];
2190 password[PASSWORD_SIZE-1] = 0;*/
2192 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2200 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2202 char c = data[2+PASSWORD_SIZE+i];
2208 if(!base64_is_valid(newpwd)){
2209 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2210 // Wrong old password supplied!!
2211 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2215 infostream<<"Server: Client requests a password change from "
2216 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2218 std::string playername = player->getName();
2220 std::string checkpwd;
2221 m_script->getAuth(playername, &checkpwd, NULL);
2223 if(oldpwd != checkpwd)
2225 infostream<<"Server: invalid old password"<<std::endl;
2226 // Wrong old password supplied!!
2227 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2231 bool success = m_script->setPassword(playername, newpwd);
2233 actionstream<<player->getName()<<" changes password"<<std::endl;
2234 SendChatMessage(peer_id, L"Password change successful.");
2236 actionstream<<player->getName()<<" tries to change password but "
2237 <<"it fails"<<std::endl;
2238 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2241 else if(command == TOSERVER_PLAYERITEM)
2246 u16 item = readU16(&data[2]);
2247 playersao->setWieldIndex(item);
2249 else if(command == TOSERVER_RESPAWN)
2251 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2254 RespawnPlayer(peer_id);
2256 actionstream<<player->getName()<<" respawns at "
2257 <<PP(player->getPosition()/BS)<<std::endl;
2259 // ActiveObject is added to environment in AsyncRunStep after
2260 // the previous addition has been succesfully removed
2262 else if(command == TOSERVER_INTERACT)
2264 std::string datastring((char*)&data[2], datasize-2);
2265 std::istringstream is(datastring, std::ios_base::binary);
2271 [5] u32 length of the next item
2272 [9] serialized PointedThing
2274 0: start digging (from undersurface) or use
2275 1: stop digging (all parameters ignored)
2276 2: digging completed
2277 3: place block or item (to abovesurface)
2280 u8 action = readU8(is);
2281 u16 item_i = readU16(is);
2282 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2283 PointedThing pointed;
2284 pointed.deSerialize(tmp_is);
2286 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2287 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2291 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2292 <<" tried to interact, but is dead!"<<std::endl;
2296 v3f player_pos = playersao->getLastGoodPosition();
2298 // Update wielded item
2299 playersao->setWieldIndex(item_i);
2301 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2302 v3s16 p_under = pointed.node_undersurface;
2303 v3s16 p_above = pointed.node_abovesurface;
2305 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2306 ServerActiveObject *pointed_object = NULL;
2307 if(pointed.type == POINTEDTHING_OBJECT)
2309 pointed_object = m_env->getActiveObject(pointed.object_id);
2310 if(pointed_object == NULL)
2312 verbosestream<<"TOSERVER_INTERACT: "
2313 "pointed object is NULL"<<std::endl;
2319 v3f pointed_pos_under = player_pos;
2320 v3f pointed_pos_above = player_pos;
2321 if(pointed.type == POINTEDTHING_NODE)
2323 pointed_pos_under = intToFloat(p_under, BS);
2324 pointed_pos_above = intToFloat(p_above, BS);
2326 else if(pointed.type == POINTEDTHING_OBJECT)
2328 pointed_pos_under = pointed_object->getBasePosition();
2329 pointed_pos_above = pointed_pos_under;
2333 Check that target is reasonably close
2334 (only when digging or placing things)
2336 if(action == 0 || action == 2 || action == 3)
2338 float d = player_pos.getDistanceFrom(pointed_pos_under);
2339 float max_d = BS * 14; // Just some large enough value
2341 actionstream<<"Player "<<player->getName()
2342 <<" tried to access "<<pointed.dump()
2344 <<"d="<<d<<", max_d="<<max_d
2345 <<". ignoring."<<std::endl;
2346 // Re-send block to revert change on client-side
2347 RemoteClient *client = getClient(peer_id);
2348 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2349 client->SetBlockNotSent(blockpos);
2351 m_script->on_cheat(playersao, "interacted_too_far");
2358 Make sure the player is allowed to do it
2360 if(!checkPriv(player->getName(), "interact"))
2362 actionstream<<player->getName()<<" attempted to interact with "
2363 <<pointed.dump()<<" without 'interact' privilege"
2365 // Re-send block to revert change on client-side
2366 RemoteClient *client = getClient(peer_id);
2367 // Digging completed -> under
2369 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2370 client->SetBlockNotSent(blockpos);
2372 // Placement -> above
2374 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2375 client->SetBlockNotSent(blockpos);
2381 If something goes wrong, this player is to blame
2383 RollbackScopeActor rollback_scope(m_rollback,
2384 std::string("player:")+player->getName());
2387 0: start digging or punch object
2391 if(pointed.type == POINTEDTHING_NODE)
2394 NOTE: This can be used in the future to check if
2395 somebody is cheating, by checking the timing.
2397 MapNode n(CONTENT_IGNORE);
2400 n = m_env->getMap().getNode(p_under);
2402 catch(InvalidPositionException &e)
2404 infostream<<"Server: Not punching: Node not found."
2405 <<" Adding block to emerge queue."
2407 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2409 if(n.getContent() != CONTENT_IGNORE)
2410 m_script->node_on_punch(p_under, n, playersao, pointed);
2412 playersao->noCheatDigStart(p_under);
2414 else if(pointed.type == POINTEDTHING_OBJECT)
2416 // Skip if object has been removed
2417 if(pointed_object->m_removed)
2420 actionstream<<player->getName()<<" punches object "
2421 <<pointed.object_id<<": "
2422 <<pointed_object->getDescription()<<std::endl;
2424 ItemStack punchitem = playersao->getWieldedItem();
2425 ToolCapabilities toolcap =
2426 punchitem.getToolCapabilities(m_itemdef);
2427 v3f dir = (pointed_object->getBasePosition() -
2428 (player->getPosition() + player->getEyeOffset())
2430 float time_from_last_punch =
2431 playersao->resetTimeFromLastPunch();
2432 pointed_object->punch(dir, &toolcap, playersao,
2433 time_from_last_punch);
2441 else if(action == 1)
2446 2: Digging completed
2448 else if(action == 2)
2450 // Only digging of nodes
2451 if(pointed.type == POINTEDTHING_NODE)
2453 MapNode n(CONTENT_IGNORE);
2456 n = m_env->getMap().getNode(p_under);
2458 catch(InvalidPositionException &e)
2460 infostream<<"Server: Not finishing digging: Node not found."
2461 <<" Adding block to emerge queue."
2463 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2466 /* Cheat prevention */
2467 bool is_valid_dig = true;
2468 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2470 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2471 float nocheat_t = playersao->getNoCheatDigTime();
2472 playersao->noCheatDigEnd();
2473 // If player didn't start digging this, ignore dig
2474 if(nocheat_p != p_under){
2475 infostream<<"Server: NoCheat: "<<player->getName()
2476 <<" started digging "
2477 <<PP(nocheat_p)<<" and completed digging "
2478 <<PP(p_under)<<"; not digging."<<std::endl;
2479 is_valid_dig = false;
2481 m_script->on_cheat(playersao, "finished_unknown_dig");
2483 // Get player's wielded item
2484 ItemStack playeritem;
2485 InventoryList *mlist = playersao->getInventory()->getList("main");
2487 playeritem = mlist->getItem(playersao->getWieldIndex());
2488 ToolCapabilities playeritem_toolcap =
2489 playeritem.getToolCapabilities(m_itemdef);
2490 // Get diggability and expected digging time
2491 DigParams params = getDigParams(m_nodedef->get(n).groups,
2492 &playeritem_toolcap);
2493 // If can't dig, try hand
2494 if(!params.diggable){
2495 const ItemDefinition &hand = m_itemdef->get("");
2496 const ToolCapabilities *tp = hand.tool_capabilities;
2498 params = getDigParams(m_nodedef->get(n).groups, tp);
2500 // If can't dig, ignore dig
2501 if(!params.diggable){
2502 infostream<<"Server: NoCheat: "<<player->getName()
2503 <<" completed digging "<<PP(p_under)
2504 <<", which is not diggable with tool. not digging."
2506 is_valid_dig = false;
2508 m_script->on_cheat(playersao, "dug_unbreakable");
2510 // Check digging time
2511 // If already invalidated, we don't have to
2513 // Well not our problem then
2515 // Clean and long dig
2516 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2517 // All is good, but grab time from pool; don't care if
2518 // it's actually available
2519 playersao->getDigPool().grab(params.time);
2521 // Short or laggy dig
2522 // Try getting the time from pool
2523 else if(playersao->getDigPool().grab(params.time)){
2528 infostream<<"Server: NoCheat: "<<player->getName()
2529 <<" completed digging "<<PP(p_under)
2530 <<"too fast; not digging."<<std::endl;
2531 is_valid_dig = false;
2533 m_script->on_cheat(playersao, "dug_too_fast");
2537 /* Actually dig node */
2539 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2540 m_script->node_on_dig(p_under, n, playersao);
2542 // Send unusual result (that is, node not being removed)
2543 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2545 // Re-send block to revert change on client-side
2546 RemoteClient *client = getClient(peer_id);
2547 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2548 client->SetBlockNotSent(blockpos);
2554 3: place block or right-click object
2556 else if(action == 3)
2558 ItemStack item = playersao->getWieldedItem();
2560 // Reset build time counter
2561 if(pointed.type == POINTEDTHING_NODE &&
2562 item.getDefinition(m_itemdef).type == ITEM_NODE)
2563 getClient(peer_id)->m_time_from_building = 0.0;
2565 if(pointed.type == POINTEDTHING_OBJECT)
2567 // Right click object
2569 // Skip if object has been removed
2570 if(pointed_object->m_removed)
2573 actionstream<<player->getName()<<" right-clicks object "
2574 <<pointed.object_id<<": "
2575 <<pointed_object->getDescription()<<std::endl;
2578 pointed_object->rightClick(playersao);
2580 else if(m_script->item_OnPlace(
2581 item, playersao, pointed))
2583 // Placement was handled in lua
2585 // Apply returned ItemStack
2586 playersao->setWieldedItem(item);
2589 // If item has node placement prediction, always send the
2590 // blocks to make sure the client knows what exactly happened
2591 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2592 RemoteClient *client = getClient(peer_id);
2593 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2594 client->SetBlockNotSent(blockpos);
2595 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2596 if(blockpos2 != blockpos){
2597 client->SetBlockNotSent(blockpos2);
2605 else if(action == 4)
2607 ItemStack item = playersao->getWieldedItem();
2609 actionstream<<player->getName()<<" uses "<<item.name
2610 <<", pointing at "<<pointed.dump()<<std::endl;
2612 if(m_script->item_OnUse(
2613 item, playersao, pointed))
2615 // Apply returned ItemStack
2616 playersao->setWieldedItem(item);
2623 Catch invalid actions
2627 infostream<<"WARNING: Server: Invalid action "
2628 <<action<<std::endl;
2631 else if(command == TOSERVER_REMOVED_SOUNDS)
2633 std::string datastring((char*)&data[2], datasize-2);
2634 std::istringstream is(datastring, std::ios_base::binary);
2636 int num = readU16(is);
2637 for(int k=0; k<num; k++){
2638 s32 id = readS32(is);
2639 std::map<s32, ServerPlayingSound>::iterator i =
2640 m_playing_sounds.find(id);
2641 if(i == m_playing_sounds.end())
2643 ServerPlayingSound &psound = i->second;
2644 psound.clients.erase(peer_id);
2645 if(psound.clients.size() == 0)
2646 m_playing_sounds.erase(i++);
2649 else if(command == TOSERVER_NODEMETA_FIELDS)
2651 std::string datastring((char*)&data[2], datasize-2);
2652 std::istringstream is(datastring, std::ios_base::binary);
2654 v3s16 p = readV3S16(is);
2655 std::string formname = deSerializeString(is);
2656 int num = readU16(is);
2657 std::map<std::string, std::string> fields;
2658 for(int k=0; k<num; k++){
2659 std::string fieldname = deSerializeString(is);
2660 std::string fieldvalue = deSerializeLongString(is);
2661 fields[fieldname] = fieldvalue;
2664 // If something goes wrong, this player is to blame
2665 RollbackScopeActor rollback_scope(m_rollback,
2666 std::string("player:")+player->getName());
2668 // Check the target node for rollback data; leave others unnoticed
2669 RollbackNode rn_old(&m_env->getMap(), p, this);
2671 m_script->node_on_receive_fields(p, formname, fields,playersao);
2673 // Report rollback data
2674 RollbackNode rn_new(&m_env->getMap(), p, this);
2675 if(rollback() && rn_new != rn_old){
2676 RollbackAction action;
2677 action.setSetNode(p, rn_old, rn_new);
2678 rollback()->reportAction(action);
2681 else if(command == TOSERVER_INVENTORY_FIELDS)
2683 std::string datastring((char*)&data[2], datasize-2);
2684 std::istringstream is(datastring, std::ios_base::binary);
2686 std::string formname = deSerializeString(is);
2687 int num = readU16(is);
2688 std::map<std::string, std::string> fields;
2689 for(int k=0; k<num; k++){
2690 std::string fieldname = deSerializeString(is);
2691 std::string fieldvalue = deSerializeLongString(is);
2692 fields[fieldname] = fieldvalue;
2695 m_script->on_playerReceiveFields(playersao, formname, fields);
2699 infostream<<"Server::ProcessData(): Ignoring "
2700 "unknown command "<<command<<std::endl;
2704 catch(SendFailedException &e)
2706 errorstream<<"Server::ProcessData(): SendFailedException: "
2712 void Server::setTimeOfDay(u32 time)
2714 m_env->setTimeOfDay(time);
2715 m_time_of_day_send_timer = 0;
2718 void Server::onMapEditEvent(MapEditEvent *event)
2720 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2721 if(m_ignore_map_edit_events)
2723 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2725 MapEditEvent *e = event->clone();
2726 m_unsent_map_edit_queue.push_back(e);
2729 Inventory* Server::getInventory(const InventoryLocation &loc)
2732 case InventoryLocation::UNDEFINED:
2735 case InventoryLocation::CURRENT_PLAYER:
2738 case InventoryLocation::PLAYER:
2740 Player *player = m_env->getPlayer(loc.name.c_str());
2743 PlayerSAO *playersao = player->getPlayerSAO();
2746 return playersao->getInventory();
2749 case InventoryLocation::NODEMETA:
2751 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2754 return meta->getInventory();
2757 case InventoryLocation::DETACHED:
2759 if(m_detached_inventories.count(loc.name) == 0)
2761 return m_detached_inventories[loc.name];
2769 void Server::setInventoryModified(const InventoryLocation &loc)
2772 case InventoryLocation::UNDEFINED:
2775 case InventoryLocation::PLAYER:
2777 Player *player = m_env->getPlayer(loc.name.c_str());
2780 PlayerSAO *playersao = player->getPlayerSAO();
2783 playersao->m_inventory_not_sent = true;
2784 playersao->m_wielded_item_not_sent = true;
2787 case InventoryLocation::NODEMETA:
2789 v3s16 blockpos = getNodeBlockPos(loc.p);
2791 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2793 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2795 setBlockNotSent(blockpos);
2798 case InventoryLocation::DETACHED:
2800 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2808 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2810 std::list<u16> clients = m_clients.getClientIDs();
2812 // Set the modified blocks unsent for all the clients
2813 for (std::list<u16>::iterator
2814 i = clients.begin();
2815 i != clients.end(); ++i) {
2816 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2818 client->SetBlocksNotSent(block);
2823 void Server::peerAdded(con::Peer *peer)
2825 DSTACK(__FUNCTION_NAME);
2826 verbosestream<<"Server::peerAdded(): peer->id="
2827 <<peer->id<<std::endl;
2830 c.type = con::PEER_ADDED;
2831 c.peer_id = peer->id;
2833 m_peer_change_queue.push_back(c);
2836 void Server::deletingPeer(con::Peer *peer, bool timeout)
2838 DSTACK(__FUNCTION_NAME);
2839 verbosestream<<"Server::deletingPeer(): peer->id="
2840 <<peer->id<<", timeout="<<timeout<<std::endl;
2842 m_clients.event(peer->id, CSE_Disconnect);
2844 c.type = con::PEER_REMOVED;
2845 c.peer_id = peer->id;
2846 c.timeout = timeout;
2847 m_peer_change_queue.push_back(c);
2850 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2852 *retval = m_con.getPeerStat(peer_id,type);
2853 if (*retval == -1) return false;
2857 bool Server::getClientInfo(
2866 std::string* vers_string
2869 *state = m_clients.getClientState(peer_id);
2871 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2873 if (client == NULL) {
2878 *uptime = client->uptime();
2879 *ser_vers = client->serialization_version;
2880 *prot_vers = client->net_proto_version;
2882 *major = client->getMajor();
2883 *minor = client->getMinor();
2884 *patch = client->getPatch();
2885 *vers_string = client->getPatch();
2892 void Server::handlePeerChanges()
2894 while(m_peer_change_queue.size() > 0)
2896 con::PeerChange c = m_peer_change_queue.pop_front();
2898 verbosestream<<"Server: Handling peer change: "
2899 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2904 case con::PEER_ADDED:
2905 m_clients.CreateClient(c.peer_id);
2908 case con::PEER_REMOVED:
2909 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2913 assert("Invalid peer change event received!" == 0);
2919 void Server::SendMovement(u16 peer_id)
2921 DSTACK(__FUNCTION_NAME);
2922 std::ostringstream os(std::ios_base::binary);
2924 writeU16(os, TOCLIENT_MOVEMENT);
2925 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2926 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2927 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2928 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2929 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2930 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2931 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2932 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2933 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2934 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2935 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2936 writeF1000(os, g_settings->getFloat("movement_gravity"));
2939 std::string s = os.str();
2940 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2942 m_clients.send(peer_id, 0, data, true);
2945 void Server::SendHP(u16 peer_id, u8 hp)
2947 DSTACK(__FUNCTION_NAME);
2948 std::ostringstream os(std::ios_base::binary);
2950 writeU16(os, TOCLIENT_HP);
2954 std::string s = os.str();
2955 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2957 m_clients.send(peer_id, 0, data, true);
2960 void Server::SendBreath(u16 peer_id, u16 breath)
2962 DSTACK(__FUNCTION_NAME);
2963 std::ostringstream os(std::ios_base::binary);
2965 writeU16(os, TOCLIENT_BREATH);
2966 writeU16(os, breath);
2969 std::string s = os.str();
2970 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2972 m_clients.send(peer_id, 0, data, true);
2975 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2977 DSTACK(__FUNCTION_NAME);
2978 std::ostringstream os(std::ios_base::binary);
2980 writeU16(os, TOCLIENT_ACCESS_DENIED);
2981 os<<serializeWideString(reason);
2984 std::string s = os.str();
2985 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2987 m_clients.send(peer_id, 0, data, true);
2990 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
2991 v3f camera_point_target)
2993 DSTACK(__FUNCTION_NAME);
2994 std::ostringstream os(std::ios_base::binary);
2996 writeU16(os, TOCLIENT_DEATHSCREEN);
2997 writeU8(os, set_camera_point_target);
2998 writeV3F1000(os, camera_point_target);
3001 std::string s = os.str();
3002 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3004 m_clients.send(peer_id, 0, data, true);
3007 void Server::SendItemDef(u16 peer_id,
3008 IItemDefManager *itemdef, u16 protocol_version)
3010 DSTACK(__FUNCTION_NAME);
3011 std::ostringstream os(std::ios_base::binary);
3015 u32 length of the next item
3016 zlib-compressed serialized ItemDefManager
3018 writeU16(os, TOCLIENT_ITEMDEF);
3019 std::ostringstream tmp_os(std::ios::binary);
3020 itemdef->serialize(tmp_os, protocol_version);
3021 std::ostringstream tmp_os2(std::ios::binary);
3022 compressZlib(tmp_os.str(), tmp_os2);
3023 os<<serializeLongString(tmp_os2.str());
3026 std::string s = os.str();
3027 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3028 <<"): size="<<s.size()<<std::endl;
3029 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3031 m_clients.send(peer_id, 0, data, true);
3034 void Server::SendNodeDef(u16 peer_id,
3035 INodeDefManager *nodedef, u16 protocol_version)
3037 DSTACK(__FUNCTION_NAME);
3038 std::ostringstream os(std::ios_base::binary);
3042 u32 length of the next item
3043 zlib-compressed serialized NodeDefManager
3045 writeU16(os, TOCLIENT_NODEDEF);
3046 std::ostringstream tmp_os(std::ios::binary);
3047 nodedef->serialize(tmp_os, protocol_version);
3048 std::ostringstream tmp_os2(std::ios::binary);
3049 compressZlib(tmp_os.str(), tmp_os2);
3050 os<<serializeLongString(tmp_os2.str());
3053 std::string s = os.str();
3054 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3055 <<"): size="<<s.size()<<std::endl;
3056 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3058 m_clients.send(peer_id, 0, data, true);
3062 Non-static send methods
3065 void Server::SendInventory(u16 peer_id)
3067 DSTACK(__FUNCTION_NAME);
3069 PlayerSAO *playersao = getPlayerSAO(peer_id);
3072 playersao->m_inventory_not_sent = false;
3078 std::ostringstream os;
3079 playersao->getInventory()->serialize(os);
3081 std::string s = os.str();
3083 SharedBuffer<u8> data(s.size()+2);
3084 writeU16(&data[0], TOCLIENT_INVENTORY);
3085 memcpy(&data[2], s.c_str(), s.size());
3088 m_clients.send(peer_id, 0, data, true);
3091 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3093 DSTACK(__FUNCTION_NAME);
3095 std::ostringstream os(std::ios_base::binary);
3099 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3100 os.write((char*)buf, 2);
3103 writeU16(buf, message.size());
3104 os.write((char*)buf, 2);
3107 for(u32 i=0; i<message.size(); i++)
3111 os.write((char*)buf, 2);
3115 std::string s = os.str();
3116 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3118 if (peer_id != PEER_ID_INEXISTENT)
3121 m_clients.send(peer_id, 0, data, true);
3125 m_clients.sendToAll(0,data,true);
3129 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3130 const std::string &formname)
3132 DSTACK(__FUNCTION_NAME);
3134 std::ostringstream os(std::ios_base::binary);
3139 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3140 os.write((char*)buf, 2);
3141 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3142 os<<serializeString(formname);
3145 std::string s = os.str();
3146 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3148 m_clients.send(peer_id, 0, data, true);
3151 // Spawns a particle on peer with peer_id
3152 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3153 float expirationtime, float size, bool collisiondetection,
3154 bool vertical, std::string texture)
3156 DSTACK(__FUNCTION_NAME);
3158 std::ostringstream os(std::ios_base::binary);
3159 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3160 writeV3F1000(os, pos);
3161 writeV3F1000(os, velocity);
3162 writeV3F1000(os, acceleration);
3163 writeF1000(os, expirationtime);
3164 writeF1000(os, size);
3165 writeU8(os, collisiondetection);
3166 os<<serializeLongString(texture);
3167 writeU8(os, vertical);
3170 std::string s = os.str();
3171 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3173 if (peer_id != PEER_ID_INEXISTENT)
3176 m_clients.send(peer_id, 0, data, true);
3180 m_clients.sendToAll(0,data,true);
3184 // Adds a ParticleSpawner on peer with peer_id
3185 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3186 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3187 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3189 DSTACK(__FUNCTION_NAME);
3191 std::ostringstream os(std::ios_base::binary);
3192 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3194 writeU16(os, amount);
3195 writeF1000(os, spawntime);
3196 writeV3F1000(os, minpos);
3197 writeV3F1000(os, maxpos);
3198 writeV3F1000(os, minvel);
3199 writeV3F1000(os, maxvel);
3200 writeV3F1000(os, minacc);
3201 writeV3F1000(os, maxacc);
3202 writeF1000(os, minexptime);
3203 writeF1000(os, maxexptime);
3204 writeF1000(os, minsize);
3205 writeF1000(os, maxsize);
3206 writeU8(os, collisiondetection);
3207 os<<serializeLongString(texture);
3209 writeU8(os, vertical);
3212 std::string s = os.str();
3213 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3215 if (peer_id != PEER_ID_INEXISTENT)
3218 m_clients.send(peer_id, 0, data, true);
3221 m_clients.sendToAll(0,data,true);
3225 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3227 DSTACK(__FUNCTION_NAME);
3229 std::ostringstream os(std::ios_base::binary);
3230 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3235 std::string s = os.str();
3236 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3238 if (peer_id != PEER_ID_INEXISTENT) {
3240 m_clients.send(peer_id, 0, data, true);
3243 m_clients.sendToAll(0,data,true);
3248 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3250 std::ostringstream os(std::ios_base::binary);
3253 writeU16(os, TOCLIENT_HUDADD);
3255 writeU8(os, (u8)form->type);
3256 writeV2F1000(os, form->pos);
3257 os << serializeString(form->name);
3258 writeV2F1000(os, form->scale);
3259 os << serializeString(form->text);
3260 writeU32(os, form->number);
3261 writeU32(os, form->item);
3262 writeU32(os, form->dir);
3263 writeV2F1000(os, form->align);
3264 writeV2F1000(os, form->offset);
3265 writeV3F1000(os, form->world_pos);
3266 writeV2S32(os,form->size);
3269 std::string s = os.str();
3270 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3272 m_clients.send(peer_id, 1, data, true);
3275 void Server::SendHUDRemove(u16 peer_id, u32 id)
3277 std::ostringstream os(std::ios_base::binary);
3280 writeU16(os, TOCLIENT_HUDRM);
3284 std::string s = os.str();
3285 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3288 m_clients.send(peer_id, 1, data, true);
3291 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3293 std::ostringstream os(std::ios_base::binary);
3296 writeU16(os, TOCLIENT_HUDCHANGE);
3298 writeU8(os, (u8)stat);
3301 case HUD_STAT_SCALE:
3302 case HUD_STAT_ALIGN:
3303 case HUD_STAT_OFFSET:
3304 writeV2F1000(os, *(v2f *)value);
3308 os << serializeString(*(std::string *)value);
3310 case HUD_STAT_WORLD_POS:
3311 writeV3F1000(os, *(v3f *)value);
3314 writeV2S32(os,*(v2s32 *)value);
3316 case HUD_STAT_NUMBER:
3320 writeU32(os, *(u32 *)value);
3325 std::string s = os.str();
3326 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3328 m_clients.send(peer_id, 0, data, true);
3331 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3333 std::ostringstream os(std::ios_base::binary);
3336 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3338 //////////////////////////// compatibility code to be removed //////////////
3339 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3340 ////////////////////////////////////////////////////////////////////////////
3341 writeU32(os, flags);
3345 std::string s = os.str();
3346 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3348 m_clients.send(peer_id, 0, data, true);
3351 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3353 std::ostringstream os(std::ios_base::binary);
3356 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3357 writeU16(os, param);
3358 os<<serializeString(value);
3361 std::string s = os.str();
3362 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3364 m_clients.send(peer_id, 0, data, true);
3367 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3368 const std::string &type, const std::vector<std::string> ¶ms)
3370 std::ostringstream os(std::ios_base::binary);
3373 writeU16(os, TOCLIENT_SET_SKY);
3374 writeARGB8(os, bgcolor);
3375 os<<serializeString(type);
3376 writeU16(os, params.size());
3377 for(size_t i=0; i<params.size(); i++)
3378 os<<serializeString(params[i]);
3381 std::string s = os.str();
3382 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3384 m_clients.send(peer_id, 0, data, true);
3387 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3390 std::ostringstream os(std::ios_base::binary);
3393 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3394 writeU8(os, do_override);
3395 writeU16(os, ratio*65535);
3398 std::string s = os.str();
3399 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3401 m_clients.send(peer_id, 0, data, true);
3404 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3406 DSTACK(__FUNCTION_NAME);
3409 SharedBuffer<u8> data(2+2+4);
3410 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3411 writeU16(&data[2], time);
3412 writeF1000(&data[4], time_speed);
3414 if (peer_id == PEER_ID_INEXISTENT) {
3415 m_clients.sendToAll(0,data,true);
3419 m_clients.send(peer_id, 0, data, true);
3423 void Server::SendPlayerHP(u16 peer_id)
3425 DSTACK(__FUNCTION_NAME);
3426 PlayerSAO *playersao = getPlayerSAO(peer_id);
3428 playersao->m_hp_not_sent = false;
3429 SendHP(peer_id, playersao->getHP());
3430 m_script->player_event(playersao,"health_changed");
3432 // Send to other clients
3433 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3434 ActiveObjectMessage aom(playersao->getId(), true, str);
3435 playersao->m_messages_out.push_back(aom);
3438 void Server::SendPlayerBreath(u16 peer_id)
3440 DSTACK(__FUNCTION_NAME);
3441 PlayerSAO *playersao = getPlayerSAO(peer_id);
3443 playersao->m_breath_not_sent = false;
3444 m_script->player_event(playersao,"breath_changed");
3445 SendBreath(peer_id, playersao->getBreath());
3448 void Server::SendMovePlayer(u16 peer_id)
3450 DSTACK(__FUNCTION_NAME);
3451 Player *player = m_env->getPlayer(peer_id);
3454 std::ostringstream os(std::ios_base::binary);
3455 writeU16(os, TOCLIENT_MOVE_PLAYER);
3456 writeV3F1000(os, player->getPosition());
3457 writeF1000(os, player->getPitch());
3458 writeF1000(os, player->getYaw());
3461 v3f pos = player->getPosition();
3462 f32 pitch = player->getPitch();
3463 f32 yaw = player->getYaw();
3464 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3465 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3472 std::string s = os.str();
3473 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3475 m_clients.send(peer_id, 0, data, true);
3478 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3480 std::ostringstream os(std::ios_base::binary);
3482 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3483 writeV2S32(os, animation_frames[0]);
3484 writeV2S32(os, animation_frames[1]);
3485 writeV2S32(os, animation_frames[2]);
3486 writeV2S32(os, animation_frames[3]);
3487 writeF1000(os, animation_speed);
3490 std::string s = os.str();
3491 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3493 m_clients.send(peer_id, 0, data, true);
3496 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3498 std::ostringstream os(std::ios_base::binary);
3500 writeU16(os, TOCLIENT_EYE_OFFSET);
3501 writeV3F1000(os, first);
3502 writeV3F1000(os, third);
3505 std::string s = os.str();
3506 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3508 m_clients.send(peer_id, 0, data, true);
3510 void Server::SendPlayerPrivileges(u16 peer_id)
3512 Player *player = m_env->getPlayer(peer_id);
3514 if(player->peer_id == PEER_ID_INEXISTENT)
3517 std::set<std::string> privs;
3518 m_script->getAuth(player->getName(), NULL, &privs);
3520 std::ostringstream os(std::ios_base::binary);
3521 writeU16(os, TOCLIENT_PRIVILEGES);
3522 writeU16(os, privs.size());
3523 for(std::set<std::string>::const_iterator i = privs.begin();
3524 i != privs.end(); i++){
3525 os<<serializeString(*i);
3529 std::string s = os.str();
3530 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3532 m_clients.send(peer_id, 0, data, true);
3535 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3537 Player *player = m_env->getPlayer(peer_id);
3539 if(player->peer_id == PEER_ID_INEXISTENT)
3542 std::ostringstream os(std::ios_base::binary);
3543 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3544 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3547 std::string s = os.str();
3548 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3550 m_clients.send(peer_id, 0, data, true);
3553 s32 Server::playSound(const SimpleSoundSpec &spec,
3554 const ServerSoundParams ¶ms)
3556 // Find out initial position of sound
3557 bool pos_exists = false;
3558 v3f pos = params.getPos(m_env, &pos_exists);
3559 // If position is not found while it should be, cancel sound
3560 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3563 // Filter destination clients
3564 std::list<u16> dst_clients;
3565 if(params.to_player != "")
3567 Player *player = m_env->getPlayer(params.to_player.c_str());
3569 infostream<<"Server::playSound: Player \""<<params.to_player
3570 <<"\" not found"<<std::endl;
3573 if(player->peer_id == PEER_ID_INEXISTENT){
3574 infostream<<"Server::playSound: Player \""<<params.to_player
3575 <<"\" not connected"<<std::endl;
3578 dst_clients.push_back(player->peer_id);
3582 std::list<u16> clients = m_clients.getClientIDs();
3584 for(std::list<u16>::iterator
3585 i = clients.begin(); i != clients.end(); ++i)
3587 Player *player = m_env->getPlayer(*i);
3591 if(player->getPosition().getDistanceFrom(pos) >
3592 params.max_hear_distance)
3595 dst_clients.push_back(*i);
3598 if(dst_clients.size() == 0)
3602 s32 id = m_next_sound_id++;
3603 // The sound will exist as a reference in m_playing_sounds
3604 m_playing_sounds[id] = ServerPlayingSound();
3605 ServerPlayingSound &psound = m_playing_sounds[id];
3606 psound.params = params;
3607 for(std::list<u16>::iterator i = dst_clients.begin();
3608 i != dst_clients.end(); i++)
3609 psound.clients.insert(*i);
3611 std::ostringstream os(std::ios_base::binary);
3612 writeU16(os, TOCLIENT_PLAY_SOUND);
3614 os<<serializeString(spec.name);
3615 writeF1000(os, spec.gain * params.gain);
3616 writeU8(os, params.type);
3617 writeV3F1000(os, pos);
3618 writeU16(os, params.object);
3619 writeU8(os, params.loop);
3621 std::string s = os.str();
3622 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3624 for(std::list<u16>::iterator i = dst_clients.begin();
3625 i != dst_clients.end(); i++){
3627 m_clients.send(*i, 0, data, true);
3631 void Server::stopSound(s32 handle)
3633 // Get sound reference
3634 std::map<s32, ServerPlayingSound>::iterator i =
3635 m_playing_sounds.find(handle);
3636 if(i == m_playing_sounds.end())
3638 ServerPlayingSound &psound = i->second;
3640 std::ostringstream os(std::ios_base::binary);
3641 writeU16(os, TOCLIENT_STOP_SOUND);
3642 writeS32(os, handle);
3644 std::string s = os.str();
3645 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3647 for(std::set<u16>::iterator i = psound.clients.begin();
3648 i != psound.clients.end(); i++){
3650 m_clients.send(*i, 0, data, true);
3652 // Remove sound reference
3653 m_playing_sounds.erase(i);
3656 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3657 std::list<u16> *far_players, float far_d_nodes)
3659 float maxd = far_d_nodes*BS;
3660 v3f p_f = intToFloat(p, BS);
3664 SharedBuffer<u8> reply(replysize);
3665 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3666 writeS16(&reply[2], p.X);
3667 writeS16(&reply[4], p.Y);
3668 writeS16(&reply[6], p.Z);
3670 std::list<u16> clients = m_clients.getClientIDs();
3671 for(std::list<u16>::iterator
3672 i = clients.begin();
3673 i != clients.end(); ++i)
3678 Player *player = m_env->getPlayer(*i);
3681 // If player is far away, only set modified blocks not sent
3682 v3f player_pos = player->getPosition();
3683 if(player_pos.getDistanceFrom(p_f) > maxd)
3685 far_players->push_back(*i);
3692 m_clients.send(*i, 0, reply, true);
3696 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3697 std::list<u16> *far_players, float far_d_nodes,
3698 bool remove_metadata)
3700 float maxd = far_d_nodes*BS;
3701 v3f p_f = intToFloat(p, BS);
3703 std::list<u16> clients = m_clients.getClientIDs();
3704 for(std::list<u16>::iterator
3705 i = clients.begin();
3706 i != clients.end(); ++i)
3712 Player *player = m_env->getPlayer(*i);
3715 // If player is far away, only set modified blocks not sent
3716 v3f player_pos = player->getPosition();
3717 if(player_pos.getDistanceFrom(p_f) > maxd)
3719 far_players->push_back(*i);
3724 SharedBuffer<u8> reply(0);
3726 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3730 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3731 reply = SharedBuffer<u8>(replysize);
3732 writeU16(&reply[0], TOCLIENT_ADDNODE);
3733 writeS16(&reply[2], p.X);
3734 writeS16(&reply[4], p.Y);
3735 writeS16(&reply[6], p.Z);
3736 n.serialize(&reply[8], client->serialization_version);
3737 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3738 writeU8(&reply[index], remove_metadata ? 0 : 1);
3740 if (!remove_metadata) {
3741 if (client->net_proto_version <= 21) {
3742 // Old clients always clear metadata; fix it
3743 // by sending the full block again.
3744 client->SetBlockNotSent(p);
3751 if (reply.getSize() > 0)
3752 m_clients.send(*i, 0, reply, true);
3756 void Server::setBlockNotSent(v3s16 p)
3758 std::list<u16> clients = m_clients.getClientIDs();
3760 for(std::list<u16>::iterator
3761 i = clients.begin();
3762 i != clients.end(); ++i)
3764 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3765 client->SetBlockNotSent(p);
3770 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3772 DSTACK(__FUNCTION_NAME);
3774 v3s16 p = block->getPos();
3778 bool completely_air = true;
3779 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3780 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3781 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3783 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3785 completely_air = false;
3786 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3791 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3793 infostream<<"[completely air] ";
3794 infostream<<std::endl;
3798 Create a packet with the block in the right format
3801 std::ostringstream os(std::ios_base::binary);
3802 block->serialize(os, ver, false);
3803 block->serializeNetworkSpecific(os, net_proto_version);
3804 std::string s = os.str();
3805 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3807 u32 replysize = 8 + blockdata.getSize();
3808 SharedBuffer<u8> reply(replysize);
3809 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3810 writeS16(&reply[2], p.X);
3811 writeS16(&reply[4], p.Y);
3812 writeS16(&reply[6], p.Z);
3813 memcpy(&reply[8], *blockdata, blockdata.getSize());
3815 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3816 <<": \tpacket size: "<<replysize<<std::endl;*/
3821 m_clients.send(peer_id, 2, reply, true);
3824 void Server::SendBlocks(float dtime)
3826 DSTACK(__FUNCTION_NAME);
3828 JMutexAutoLock envlock(m_env_mutex);
3829 //TODO check if one big lock could be faster then multiple small ones
3831 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3833 std::vector<PrioritySortedBlockTransfer> queue;
3835 s32 total_sending = 0;
3838 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3840 std::list<u16> clients = m_clients.getClientIDs();
3843 for(std::list<u16>::iterator
3844 i = clients.begin();
3845 i != clients.end(); ++i)
3847 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3852 total_sending += client->SendingCount();
3853 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3859 // Lowest priority number comes first.
3860 // Lowest is most important.
3861 std::sort(queue.begin(), queue.end());
3864 for(u32 i=0; i<queue.size(); i++)
3866 //TODO: Calculate limit dynamically
3867 if(total_sending >= g_settings->getS32
3868 ("max_simultaneous_block_sends_server_total"))
3871 PrioritySortedBlockTransfer q = queue[i];
3873 MapBlock *block = NULL;
3876 block = m_env->getMap().getBlockNoCreate(q.pos);
3878 catch(InvalidPositionException &e)
3883 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3888 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3890 client->SentBlock(q.pos);
3896 void Server::fillMediaCache()
3898 DSTACK(__FUNCTION_NAME);
3900 infostream<<"Server: Calculating media file checksums"<<std::endl;
3902 // Collect all media file paths
3903 std::list<std::string> paths;
3904 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3905 i != m_mods.end(); i++){
3906 const ModSpec &mod = *i;
3907 paths.push_back(mod.path + DIR_DELIM + "textures");
3908 paths.push_back(mod.path + DIR_DELIM + "sounds");
3909 paths.push_back(mod.path + DIR_DELIM + "media");
3910 paths.push_back(mod.path + DIR_DELIM + "models");
3912 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3914 // Collect media file information from paths into cache
3915 for(std::list<std::string>::iterator i = paths.begin();
3916 i != paths.end(); i++)
3918 std::string mediapath = *i;
3919 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3920 for(u32 j=0; j<dirlist.size(); j++){
3921 if(dirlist[j].dir) // Ignode dirs
3923 std::string filename = dirlist[j].name;
3924 // If name contains illegal characters, ignore the file
3925 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3926 infostream<<"Server: ignoring illegal file name: \""
3927 <<filename<<"\""<<std::endl;
3930 // If name is not in a supported format, ignore it
3931 const char *supported_ext[] = {
3932 ".png", ".jpg", ".bmp", ".tga",
3933 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3935 ".x", ".b3d", ".md2", ".obj",
3938 if(removeStringEnd(filename, supported_ext) == ""){
3939 infostream<<"Server: ignoring unsupported file extension: \""
3940 <<filename<<"\""<<std::endl;
3943 // Ok, attempt to load the file and add to cache
3944 std::string filepath = mediapath + DIR_DELIM + filename;
3946 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3947 if(fis.good() == false){
3948 errorstream<<"Server::fillMediaCache(): Could not open \""
3949 <<filename<<"\" for reading"<<std::endl;
3952 std::ostringstream tmp_os(std::ios_base::binary);
3956 fis.read(buf, 1024);
3957 std::streamsize len = fis.gcount();
3958 tmp_os.write(buf, len);
3967 errorstream<<"Server::fillMediaCache(): Failed to read \""
3968 <<filename<<"\""<<std::endl;
3971 if(tmp_os.str().length() == 0){
3972 errorstream<<"Server::fillMediaCache(): Empty file \""
3973 <<filepath<<"\""<<std::endl;
3978 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3980 unsigned char *digest = sha1.getDigest();
3981 std::string sha1_base64 = base64_encode(digest, 20);
3982 std::string sha1_hex = hex_encode((char*)digest, 20);
3986 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3987 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3992 struct SendableMediaAnnouncement
3995 std::string sha1_digest;
3997 SendableMediaAnnouncement(const std::string &name_="",
3998 const std::string &sha1_digest_=""):
4000 sha1_digest(sha1_digest_)
4004 void Server::sendMediaAnnouncement(u16 peer_id)
4006 DSTACK(__FUNCTION_NAME);
4008 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4011 std::list<SendableMediaAnnouncement> file_announcements;
4013 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4014 i != m_media.end(); i++){
4016 file_announcements.push_back(
4017 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4021 std::ostringstream os(std::ios_base::binary);
4029 u16 length of sha1_digest
4034 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4035 writeU16(os, file_announcements.size());
4037 for(std::list<SendableMediaAnnouncement>::iterator
4038 j = file_announcements.begin();
4039 j != file_announcements.end(); ++j){
4040 os<<serializeString(j->name);
4041 os<<serializeString(j->sha1_digest);
4043 os<<serializeString(g_settings->get("remote_media"));
4046 std::string s = os.str();
4047 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4050 m_clients.send(peer_id, 0, data, true);
4053 struct SendableMedia
4059 SendableMedia(const std::string &name_="", const std::string &path_="",
4060 const std::string &data_=""):
4067 void Server::sendRequestedMedia(u16 peer_id,
4068 const std::list<std::string> &tosend)
4070 DSTACK(__FUNCTION_NAME);
4072 verbosestream<<"Server::sendRequestedMedia(): "
4073 <<"Sending files to client"<<std::endl;
4077 // Put 5kB in one bunch (this is not accurate)
4078 u32 bytes_per_bunch = 5000;
4080 std::vector< std::list<SendableMedia> > file_bunches;
4081 file_bunches.push_back(std::list<SendableMedia>());
4083 u32 file_size_bunch_total = 0;
4085 for(std::list<std::string>::const_iterator i = tosend.begin();
4086 i != tosend.end(); ++i)
4088 const std::string &name = *i;
4090 if(m_media.find(name) == m_media.end()){
4091 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4092 <<"unknown file \""<<(name)<<"\""<<std::endl;
4096 //TODO get path + name
4097 std::string tpath = m_media[name].path;
4100 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4101 if(fis.good() == false){
4102 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4103 <<tpath<<"\" for reading"<<std::endl;
4106 std::ostringstream tmp_os(std::ios_base::binary);
4110 fis.read(buf, 1024);
4111 std::streamsize len = fis.gcount();
4112 tmp_os.write(buf, len);
4113 file_size_bunch_total += len;
4122 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4123 <<name<<"\""<<std::endl;
4126 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4127 <<tname<<"\""<<std::endl;*/
4129 file_bunches[file_bunches.size()-1].push_back(
4130 SendableMedia(name, tpath, tmp_os.str()));
4132 // Start next bunch if got enough data
4133 if(file_size_bunch_total >= bytes_per_bunch){
4134 file_bunches.push_back(std::list<SendableMedia>());
4135 file_size_bunch_total = 0;
4140 /* Create and send packets */
4142 u32 num_bunches = file_bunches.size();
4143 for(u32 i=0; i<num_bunches; i++)
4145 std::ostringstream os(std::ios_base::binary);
4149 u16 total number of texture bunches
4150 u16 index of this bunch
4151 u32 number of files in this bunch
4160 writeU16(os, TOCLIENT_MEDIA);
4161 writeU16(os, num_bunches);
4163 writeU32(os, file_bunches[i].size());
4165 for(std::list<SendableMedia>::iterator
4166 j = file_bunches[i].begin();
4167 j != file_bunches[i].end(); ++j){
4168 os<<serializeString(j->name);
4169 os<<serializeLongString(j->data);
4173 std::string s = os.str();
4174 verbosestream<<"Server::sendRequestedMedia(): bunch "
4175 <<i<<"/"<<num_bunches
4176 <<" files="<<file_bunches[i].size()
4177 <<" size=" <<s.size()<<std::endl;
4178 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4180 m_clients.send(peer_id, 2, data, true);
4184 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4186 if(m_detached_inventories.count(name) == 0){
4187 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4190 Inventory *inv = m_detached_inventories[name];
4192 std::ostringstream os(std::ios_base::binary);
4193 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4194 os<<serializeString(name);
4198 std::string s = os.str();
4199 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4201 if (peer_id != PEER_ID_INEXISTENT)
4204 m_clients.send(peer_id, 0, data, true);
4208 m_clients.sendToAll(0,data,true);
4212 void Server::sendDetachedInventories(u16 peer_id)
4214 DSTACK(__FUNCTION_NAME);
4216 for(std::map<std::string, Inventory*>::iterator
4217 i = m_detached_inventories.begin();
4218 i != m_detached_inventories.end(); i++){
4219 const std::string &name = i->first;
4220 //Inventory *inv = i->second;
4221 sendDetachedInventory(name, peer_id);
4229 void Server::DiePlayer(u16 peer_id)
4231 DSTACK(__FUNCTION_NAME);
4233 PlayerSAO *playersao = getPlayerSAO(peer_id);
4236 infostream<<"Server::DiePlayer(): Player "
4237 <<playersao->getPlayer()->getName()
4238 <<" dies"<<std::endl;
4240 playersao->setHP(0);
4242 // Trigger scripted stuff
4243 m_script->on_dieplayer(playersao);
4245 SendPlayerHP(peer_id);
4246 SendDeathscreen(peer_id, false, v3f(0,0,0));
4249 void Server::RespawnPlayer(u16 peer_id)
4251 DSTACK(__FUNCTION_NAME);
4253 PlayerSAO *playersao = getPlayerSAO(peer_id);
4256 infostream<<"Server::RespawnPlayer(): Player "
4257 <<playersao->getPlayer()->getName()
4258 <<" respawns"<<std::endl;
4260 playersao->setHP(PLAYER_MAX_HP);
4262 bool repositioned = m_script->on_respawnplayer(playersao);
4264 v3f pos = findSpawnPos(m_env->getServerMap());
4265 playersao->setPos(pos);
4269 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4271 DSTACK(__FUNCTION_NAME);
4273 SendAccessDenied(peer_id, reason);
4274 m_clients.event(peer_id, CSE_SetDenied);
4275 m_con.DisconnectPeer(peer_id);
4278 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4280 DSTACK(__FUNCTION_NAME);
4281 std::wstring message;
4284 Clear references to playing sounds
4286 for(std::map<s32, ServerPlayingSound>::iterator
4287 i = m_playing_sounds.begin();
4288 i != m_playing_sounds.end();)
4290 ServerPlayingSound &psound = i->second;
4291 psound.clients.erase(peer_id);
4292 if(psound.clients.size() == 0)
4293 m_playing_sounds.erase(i++);
4298 Player *player = m_env->getPlayer(peer_id);
4300 // Collect information about leaving in chat
4302 if(player != NULL && reason != CDR_DENY)
4304 std::wstring name = narrow_to_wide(player->getName());
4307 message += L" left the game.";
4308 if(reason == CDR_TIMEOUT)
4309 message += L" (timed out)";
4313 /* Run scripts and remove from environment */
4317 PlayerSAO *playersao = player->getPlayerSAO();
4320 m_script->on_leaveplayer(playersao);
4322 playersao->disconnected();
4330 if(player != NULL && reason != CDR_DENY)
4332 std::ostringstream os(std::ios_base::binary);
4333 std::list<u16> clients = m_clients.getClientIDs();
4335 for(std::list<u16>::iterator
4336 i = clients.begin();
4337 i != clients.end(); ++i)
4340 Player *player = m_env->getPlayer(*i);
4343 // Get name of player
4344 os<<player->getName()<<" ";
4347 actionstream<<player->getName()<<" "
4348 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4349 <<" List of players: "<<os.str()<<std::endl;
4353 JMutexAutoLock env_lock(m_env_mutex);
4354 m_clients.DeleteClient(peer_id);
4358 // Send leave chat message to all remaining clients
4359 if(message.length() != 0)
4360 SendChatMessage(PEER_ID_INEXISTENT,message);
4363 void Server::UpdateCrafting(u16 peer_id)
4365 DSTACK(__FUNCTION_NAME);
4367 Player* player = m_env->getPlayer(peer_id);
4370 // Get a preview for crafting
4372 InventoryLocation loc;
4373 loc.setPlayer(player->getName());
4374 getCraftingResult(&player->inventory, preview, false, this);
4375 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4377 // Put the new preview in
4378 InventoryList *plist = player->inventory.getList("craftpreview");
4380 assert(plist->getSize() >= 1);
4381 plist->changeItem(0, preview);
4384 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4386 RemoteClient *client = getClientNoEx(peer_id,state_min);
4388 throw ClientNotFoundException("Client not found");
4392 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4394 return m_clients.getClientNoEx(peer_id, state_min);
4397 std::string Server::getPlayerName(u16 peer_id)
4399 Player *player = m_env->getPlayer(peer_id);
4401 return "[id="+itos(peer_id)+"]";
4402 return player->getName();
4405 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4407 Player *player = m_env->getPlayer(peer_id);
4410 return player->getPlayerSAO();
4413 std::wstring Server::getStatusString()
4415 std::wostringstream os(std::ios_base::binary);
4418 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4420 os<<L", uptime="<<m_uptime.get();
4422 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4423 // Information about clients
4426 std::list<u16> clients = m_clients.getClientIDs();
4427 for(std::list<u16>::iterator i = clients.begin();
4428 i != clients.end(); ++i)
4431 Player *player = m_env->getPlayer(*i);
4432 // Get name of player
4433 std::wstring name = L"unknown";
4435 name = narrow_to_wide(player->getName());
4436 // Add name to information string
4444 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4445 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4446 if(g_settings->get("motd") != "")
4447 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4451 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4453 std::set<std::string> privs;
4454 m_script->getAuth(name, NULL, &privs);
4458 bool Server::checkPriv(const std::string &name, const std::string &priv)
4460 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4461 return (privs.count(priv) != 0);
4464 void Server::reportPrivsModified(const std::string &name)
4467 std::list<u16> clients = m_clients.getClientIDs();
4468 for(std::list<u16>::iterator
4469 i = clients.begin();
4470 i != clients.end(); ++i){
4471 Player *player = m_env->getPlayer(*i);
4472 reportPrivsModified(player->getName());
4475 Player *player = m_env->getPlayer(name.c_str());
4478 SendPlayerPrivileges(player->peer_id);
4479 PlayerSAO *sao = player->getPlayerSAO();
4482 sao->updatePrivileges(
4483 getPlayerEffectivePrivs(name),
4488 void Server::reportInventoryFormspecModified(const std::string &name)
4490 Player *player = m_env->getPlayer(name.c_str());
4493 SendPlayerInventoryFormspec(player->peer_id);
4496 void Server::setIpBanned(const std::string &ip, const std::string &name)
4498 m_banmanager->add(ip, name);
4501 void Server::unsetIpBanned(const std::string &ip_or_name)
4503 m_banmanager->remove(ip_or_name);
4506 std::string Server::getBanDescription(const std::string &ip_or_name)
4508 return m_banmanager->getBanDescription(ip_or_name);
4511 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4513 Player *player = m_env->getPlayer(name);
4517 if (player->peer_id == PEER_ID_INEXISTENT)
4520 SendChatMessage(player->peer_id, msg);
4523 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4525 Player *player = m_env->getPlayer(playername);
4529 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4533 SendShowFormspecMessage(player->peer_id, formspec, formname);
4537 u32 Server::hudAdd(Player *player, HudElement *form) {
4541 u32 id = player->addHud(form);
4543 SendHUDAdd(player->peer_id, id, form);
4548 bool Server::hudRemove(Player *player, u32 id) {
4552 HudElement* todel = player->removeHud(id);
4559 SendHUDRemove(player->peer_id, id);
4563 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4567 SendHUDChange(player->peer_id, id, stat, data);
4571 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4575 SendHUDSetFlags(player->peer_id, flags, mask);
4576 player->hud_flags = flags;
4578 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4582 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4585 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4588 std::ostringstream os(std::ios::binary);
4589 writeS32(os, hotbar_itemcount);
4590 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4594 void Server::hudSetHotbarImage(Player *player, std::string name) {
4598 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4601 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4605 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4608 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4613 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4617 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4622 SendEyeOffset(player->peer_id, first, third);
4626 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4627 const std::string &type, const std::vector<std::string> ¶ms)
4632 SendSetSky(player->peer_id, bgcolor, type, params);
4636 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4642 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4646 void Server::notifyPlayers(const std::wstring &msg)
4648 SendChatMessage(PEER_ID_INEXISTENT,msg);
4651 void Server::spawnParticle(const char *playername, v3f pos,
4652 v3f velocity, v3f acceleration,
4653 float expirationtime, float size, bool
4654 collisiondetection, bool vertical, std::string texture)
4656 Player *player = m_env->getPlayer(playername);
4659 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4660 expirationtime, size, collisiondetection, vertical, texture);
4663 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4664 float expirationtime, float size,
4665 bool collisiondetection, bool vertical, std::string texture)
4667 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4668 expirationtime, size, collisiondetection, vertical, texture);
4671 u32 Server::addParticleSpawner(const char *playername,
4672 u16 amount, float spawntime,
4673 v3f minpos, v3f maxpos,
4674 v3f minvel, v3f maxvel,
4675 v3f minacc, v3f maxacc,
4676 float minexptime, float maxexptime,
4677 float minsize, float maxsize,
4678 bool collisiondetection, bool vertical, std::string texture)
4680 Player *player = m_env->getPlayer(playername);
4685 for(;;) // look for unused particlespawner id
4688 if (std::find(m_particlespawner_ids.begin(),
4689 m_particlespawner_ids.end(), id)
4690 == m_particlespawner_ids.end())
4692 m_particlespawner_ids.push_back(id);
4697 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4698 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4699 minexptime, maxexptime, minsize, maxsize,
4700 collisiondetection, vertical, texture, id);
4705 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4706 v3f minpos, v3f maxpos,
4707 v3f minvel, v3f maxvel,
4708 v3f minacc, v3f maxacc,
4709 float minexptime, float maxexptime,
4710 float minsize, float maxsize,
4711 bool collisiondetection, bool vertical, std::string texture)
4714 for(;;) // look for unused particlespawner id
4717 if (std::find(m_particlespawner_ids.begin(),
4718 m_particlespawner_ids.end(), id)
4719 == m_particlespawner_ids.end())
4721 m_particlespawner_ids.push_back(id);
4726 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4727 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4728 minexptime, maxexptime, minsize, maxsize,
4729 collisiondetection, vertical, texture, id);
4734 void Server::deleteParticleSpawner(const char *playername, u32 id)
4736 Player *player = m_env->getPlayer(playername);
4740 m_particlespawner_ids.erase(
4741 std::remove(m_particlespawner_ids.begin(),
4742 m_particlespawner_ids.end(), id),
4743 m_particlespawner_ids.end());
4744 SendDeleteParticleSpawner(player->peer_id, id);
4747 void Server::deleteParticleSpawnerAll(u32 id)
4749 m_particlespawner_ids.erase(
4750 std::remove(m_particlespawner_ids.begin(),
4751 m_particlespawner_ids.end(), id),
4752 m_particlespawner_ids.end());
4753 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4756 Inventory* Server::createDetachedInventory(const std::string &name)
4758 if(m_detached_inventories.count(name) > 0){
4759 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4760 delete m_detached_inventories[name];
4762 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4764 Inventory *inv = new Inventory(m_itemdef);
4766 m_detached_inventories[name] = inv;
4767 //TODO find a better way to do this
4768 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4775 BoolScopeSet(bool *dst, bool val):
4778 m_orig_state = *m_dst;
4783 *m_dst = m_orig_state;
4790 // actions: time-reversed list
4791 // Return value: success/failure
4792 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4793 std::list<std::string> *log)
4795 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4796 ServerMap *map = (ServerMap*)(&m_env->getMap());
4797 // Disable rollback report sink while reverting
4798 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4800 // Fail if no actions to handle
4801 if(actions.empty()){
4802 log->push_back("Nothing to do.");
4809 for(std::list<RollbackAction>::const_iterator
4810 i = actions.begin();
4811 i != actions.end(); i++)
4813 const RollbackAction &action = *i;
4815 bool success = action.applyRevert(map, this, this);
4818 std::ostringstream os;
4819 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4820 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4822 log->push_back(os.str());
4824 std::ostringstream os;
4825 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4826 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4828 log->push_back(os.str());
4832 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4833 <<" failed"<<std::endl;
4835 // Call it done if less than half failed
4836 return num_failed <= num_tried/2;
4839 // IGameDef interface
4841 IItemDefManager* Server::getItemDefManager()
4845 INodeDefManager* Server::getNodeDefManager()
4849 ICraftDefManager* Server::getCraftDefManager()
4853 ITextureSource* Server::getTextureSource()
4857 IShaderSource* Server::getShaderSource()
4861 u16 Server::allocateUnknownNodeId(const std::string &name)
4863 return m_nodedef->allocateDummy(name);
4865 ISoundManager* Server::getSoundManager()
4867 return &dummySoundManager;
4869 MtEventManager* Server::getEventManager()
4873 IRollbackReportSink* Server::getRollbackReportSink()
4875 if(!m_enable_rollback_recording)
4877 if(!m_rollback_sink_enabled)
4882 IWritableItemDefManager* Server::getWritableItemDefManager()
4886 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4890 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4895 const ModSpec* Server::getModSpec(const std::string &modname)
4897 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4898 i != m_mods.end(); i++){
4899 const ModSpec &mod = *i;
4900 if(mod.name == modname)
4905 void Server::getModNames(std::list<std::string> &modlist)
4907 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4909 modlist.push_back(i->name);
4912 std::string Server::getBuiltinLuaPath()
4914 return porting::path_share + DIR_DELIM + "builtin";
4917 v3f findSpawnPos(ServerMap &map)
4919 //return v3f(50,50,50)*BS;
4924 nodepos = v2s16(0,0);
4929 s16 water_level = map.getWaterLevel();
4931 // Try to find a good place a few times
4932 for(s32 i=0; i<1000; i++)
4935 // We're going to try to throw the player to this position
4936 v2s16 nodepos2d = v2s16(
4937 -range + (myrand() % (range * 2)),
4938 -range + (myrand() % (range * 2)));
4940 // Get ground height at point
4941 s16 groundheight = map.findGroundLevel(nodepos2d);
4942 if (groundheight <= water_level) // Don't go underwater
4944 if (groundheight > water_level + 6) // Don't go to high places
4947 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4948 bool is_good = false;
4950 for (s32 i = 0; i < 10; i++) {
4951 v3s16 blockpos = getNodeBlockPos(nodepos);
4952 map.emergeBlock(blockpos, true);
4953 content_t c = map.getNodeNoEx(nodepos).getContent();
4954 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4956 if (air_count >= 2){
4964 // Found a good place
4965 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4971 return intToFloat(nodepos, BS);
4974 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4976 RemotePlayer *player = NULL;
4977 bool newplayer = false;
4980 Try to get an existing player
4982 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4984 // If player is already connected, cancel
4985 if(player != NULL && player->peer_id != 0)
4987 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4992 If player with the wanted peer_id already exists, cancel.
4994 if(m_env->getPlayer(peer_id) != NULL)
4996 infostream<<"emergePlayer(): Player with wrong name but same"
4997 " peer_id already exists"<<std::endl;
5001 // Load player if it isn't already loaded
5003 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5006 // Create player if it doesn't exist
5009 player = new RemotePlayer(this);
5010 player->updateName(name);
5011 /* Set player position */
5012 infostream<<"Server: Finding spawn place for player \""
5013 <<name<<"\""<<std::endl;
5014 v3f pos = findSpawnPos(m_env->getServerMap());
5015 player->setPosition(pos);
5017 /* Add player to environment */
5018 m_env->addPlayer(player);
5021 // Create a new player active object
5022 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5023 getPlayerEffectivePrivs(player->getName()),
5026 /* Clean up old HUD elements from previous sessions */
5029 /* Add object to environment */
5030 m_env->addActiveObject(playersao);
5034 m_script->on_newplayer(playersao);
5040 void dedicated_server_loop(Server &server, bool &kill)
5042 DSTACK(__FUNCTION_NAME);
5044 verbosestream<<"dedicated_server_loop()"<<std::endl;
5046 IntervalLimiter m_profiler_interval;
5050 float steplen = g_settings->getFloat("dedicated_server_step");
5051 // This is kind of a hack but can be done like this
5052 // because server.step() is very light
5054 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5055 sleep_ms((int)(steplen*1000.0));
5057 server.step(steplen);
5059 if(server.getShutdownRequested() || kill)
5061 infostream<<"Dedicated server quitting"<<std::endl;
5063 if(g_settings->getBool("server_announce") == true)
5064 ServerList::sendAnnounce("delete");
5072 float profiler_print_interval =
5073 g_settings->getFloat("profiler_print_interval");
5074 if(profiler_print_interval != 0)
5076 if(m_profiler_interval.step(steplen, profiler_print_interval))
5078 infostream<<"Profiler:"<<std::endl;
5079 g_profiler->print(infostream);
5080 g_profiler->clear();