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
171 m_path_world(path_world),
172 m_gamespec(gamespec),
173 m_simple_singleplayer_mode(simple_singleplayer_mode),
174 m_async_fatal_error(""),
179 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
183 m_rollback_sink_enabled(true),
184 m_enable_rollback_recording(false),
187 m_itemdef(createItemDefManager()),
188 m_nodedef(createNodeDefManager()),
189 m_craftdef(createCraftDefManager()),
190 m_event(new EventManager()),
192 m_time_of_day_send_timer(0),
195 m_shutdown_requested(false),
196 m_ignore_map_edit_events(false),
197 m_ignore_map_edit_events_peer_id(0)
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 // Create rollback manager
247 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
248 m_rollback = createRollbackManager(rollback_path, this);
250 ModConfiguration modconf(m_path_world);
251 m_mods = modconf.getMods();
252 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
253 // complain about mods with unsatisfied dependencies
254 if(!modconf.isConsistent())
256 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
257 it != unsatisfied_mods.end(); ++it)
260 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
261 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
262 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
263 errorstream << " \"" << *dep_it << "\"";
264 errorstream << std::endl;
268 Settings worldmt_settings;
269 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
270 worldmt_settings.readConfigFile(worldmt.c_str());
271 std::vector<std::string> names = worldmt_settings.getNames();
272 std::set<std::string> load_mod_names;
273 for(std::vector<std::string>::iterator it = names.begin();
274 it != names.end(); ++it)
276 std::string name = *it;
277 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
278 load_mod_names.insert(name.substr(9));
280 // complain about mods declared to be loaded, but not found
281 for(std::vector<ModSpec>::iterator it = m_mods.begin();
282 it != m_mods.end(); ++it)
283 load_mod_names.erase((*it).name);
284 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
285 it != unsatisfied_mods.end(); ++it)
286 load_mod_names.erase((*it).name);
287 if(!load_mod_names.empty())
289 errorstream << "The following mods could not be found:";
290 for(std::set<std::string>::iterator it = load_mod_names.begin();
291 it != load_mod_names.end(); ++it)
292 errorstream << " \"" << (*it) << "\"";
293 errorstream << std::endl;
296 // Path to builtin.lua
297 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
300 JMutexAutoLock envlock(m_env_mutex);
302 // Initialize scripting
303 infostream<<"Server: Initializing Lua"<<std::endl;
305 m_script = new GameScripting(this);
308 // Load and run builtin.lua
309 infostream<<"Server: Loading builtin.lua [\""
310 <<builtinpath<<"\"]"<<std::endl;
311 bool success = m_script->loadMod(builtinpath, "__builtin");
313 errorstream<<"Server: Failed to load and run "
314 <<builtinpath<<std::endl;
315 throw ModError("Failed to load and run "+builtinpath);
318 infostream<<"Server: Loading mods: ";
319 for(std::vector<ModSpec>::iterator i = m_mods.begin();
320 i != m_mods.end(); i++){
321 const ModSpec &mod = *i;
322 infostream<<mod.name<<" ";
324 infostream<<std::endl;
325 // Load and run "mod" scripts
326 for(std::vector<ModSpec>::iterator i = m_mods.begin();
327 i != m_mods.end(); i++){
328 const ModSpec &mod = *i;
329 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
330 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
331 <<scriptpath<<"\"]"<<std::endl;
332 bool success = m_script->loadMod(scriptpath, mod.name);
334 errorstream<<"Server: Failed to load and run "
335 <<scriptpath<<std::endl;
336 throw ModError("Failed to load and run "+scriptpath);
340 // Read Textures and calculate sha1 sums
343 // Apply item aliases in the node definition manager
344 m_nodedef->updateAliases(m_itemdef);
346 // Load the mapgen params from global settings now after any
347 // initial overrides have been set by the mods
348 m_emerge->loadMapgenParams();
350 // Initialize Environment
351 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
352 m_env = new ServerEnvironment(servermap, m_script, this);
354 m_clients.setEnv(m_env);
356 // Run some callbacks after the MG params have been set up but before activation
357 m_script->environment_OnMapgenInit(&m_emerge->params);
359 // Initialize mapgens
360 m_emerge->initMapgens();
362 // Give environment reference to scripting api
363 m_script->initializeEnvironment(m_env);
365 // Register us to receive map edit events
366 servermap->addEventReceiver(this);
368 // If file exists, load environment metadata
369 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
371 infostream<<"Server: Loading environment metadata"<<std::endl;
372 m_env->loadMeta(m_path_world);
376 infostream<<"Server: Loading players"<<std::endl;
377 m_env->deSerializePlayers(m_path_world);
380 Add some test ActiveBlockModifiers to environment
382 add_legacy_abms(m_env, m_nodedef);
384 m_liquid_transform_every = g_settings->getFloat("liquid_update");
389 infostream<<"Server destructing"<<std::endl;
392 Send shutdown message
395 std::wstring line = L"*** Server shutting down";
396 SendChatMessage(PEER_ID_INEXISTENT, line);
400 JMutexAutoLock envlock(m_env_mutex);
403 Execute script shutdown hooks
405 m_script->on_shutdown();
409 JMutexAutoLock envlock(m_env_mutex);
414 infostream<<"Server: Saving players"<<std::endl;
415 m_env->serializePlayers(m_path_world);
418 Save environment metadata
420 infostream<<"Server: Saving environment metadata"<<std::endl;
421 m_env->saveMeta(m_path_world);
430 // stop all emerge threads before deleting players that may have
431 // requested blocks to be emerged
432 m_emerge->stopThreads();
434 // Delete things in the reverse order of creation
437 // N.B. the EmergeManager should be deleted after the Environment since Map
438 // depends on EmergeManager to write its current params to the map meta
447 // Deinitialize scripting
448 infostream<<"Server: Deinitializing scripting"<<std::endl;
451 // Delete detached inventories
453 for(std::map<std::string, Inventory*>::iterator
454 i = m_detached_inventories.begin();
455 i != m_detached_inventories.end(); i++){
461 void Server::start(Address bind_addr)
463 DSTACK(__FUNCTION_NAME);
464 infostream<<"Starting server on "
465 << bind_addr.serializeString() <<"..."<<std::endl;
467 // Stop thread if already running
470 // Initialize connection
471 m_con.SetTimeoutMs(30);
472 m_con.Serve(bind_addr);
477 // ASCII art for the win!
479 <<" .__ __ __ "<<std::endl
480 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
481 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
482 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
483 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
484 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
485 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
486 actionstream<<"Server for gameid=\""<<m_gamespec.id
487 <<"\" listening on "<<bind_addr.serializeString()<<":"
488 <<bind_addr.getPort() << "."<<std::endl;
493 DSTACK(__FUNCTION_NAME);
495 infostream<<"Server: Stopping and waiting threads"<<std::endl;
497 // Stop threads (set run=false first so both start stopping)
499 //m_emergethread.setRun(false);
501 //m_emergethread.stop();
503 infostream<<"Server: Threads stopped"<<std::endl;
506 void Server::step(float dtime)
508 DSTACK(__FUNCTION_NAME);
513 JMutexAutoLock lock(m_step_dtime_mutex);
514 m_step_dtime += dtime;
516 // Throw if fatal error occurred in thread
517 std::string async_err = m_async_fatal_error.get();
519 throw ServerError(async_err);
523 void Server::AsyncRunStep(bool initial_step)
525 DSTACK(__FUNCTION_NAME);
527 g_profiler->add("Server::AsyncRunStep (num)", 1);
531 JMutexAutoLock lock1(m_step_dtime_mutex);
532 dtime = m_step_dtime;
536 // Send blocks to clients
540 if((dtime < 0.001) && (initial_step == false))
543 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
545 //infostream<<"Server steps "<<dtime<<std::endl;
546 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
549 JMutexAutoLock lock1(m_step_dtime_mutex);
550 m_step_dtime -= dtime;
557 m_uptime.set(m_uptime.get() + dtime);
563 Update time of day and overall game time
566 JMutexAutoLock envlock(m_env_mutex);
568 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
571 Send to clients at constant intervals
574 m_time_of_day_send_timer -= dtime;
575 if(m_time_of_day_send_timer < 0.0)
577 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
578 u16 time = m_env->getTimeOfDay();
579 float time_speed = g_settings->getFloat("time_speed");
580 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
585 JMutexAutoLock lock(m_env_mutex);
586 // Figure out and report maximum lag to environment
587 float max_lag = m_env->getMaxLagEstimate();
588 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
590 if(dtime > 0.1 && dtime > max_lag * 2.0)
591 infostream<<"Server: Maximum lag peaked to "<<dtime
595 m_env->reportMaxLagEstimate(max_lag);
597 ScopeProfiler sp(g_profiler, "SEnv step");
598 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
602 const float map_timer_and_unload_dtime = 2.92;
603 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
605 JMutexAutoLock lock(m_env_mutex);
606 // Run Map's timers and unload unused data
607 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
608 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
609 g_settings->getFloat("server_unload_unused_data_timeout"));
620 JMutexAutoLock lock(m_env_mutex);
622 std::list<u16> clientids = m_clients.getClientIDs();
624 ScopeProfiler sp(g_profiler, "Server: handle players");
626 for(std::list<u16>::iterator
627 i = clientids.begin();
628 i != clientids.end(); ++i)
630 PlayerSAO *playersao = getPlayerSAO(*i);
631 if(playersao == NULL)
635 Handle player HPs (die if hp=0)
637 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
639 if(playersao->getHP() == 0)
646 Send player breath if changed
648 if(playersao->m_breath_not_sent){
649 SendPlayerBreath(*i);
653 Send player inventories if necessary
655 if(playersao->m_moved){
657 playersao->m_moved = false;
659 if(playersao->m_inventory_not_sent){
666 /* Transform liquids */
667 m_liquid_transform_timer += dtime;
668 if(m_liquid_transform_timer >= m_liquid_transform_every)
670 m_liquid_transform_timer -= m_liquid_transform_every;
672 JMutexAutoLock lock(m_env_mutex);
674 ScopeProfiler sp(g_profiler, "Server: liquid transform");
676 std::map<v3s16, MapBlock*> modified_blocks;
677 m_env->getMap().transformLiquids(modified_blocks);
682 core::map<v3s16, MapBlock*> lighting_modified_blocks;
683 ServerMap &map = ((ServerMap&)m_env->getMap());
684 map.updateLighting(modified_blocks, lighting_modified_blocks);
686 // Add blocks modified by lighting to modified_blocks
687 for(core::map<v3s16, MapBlock*>::Iterator
688 i = lighting_modified_blocks.getIterator();
689 i.atEnd() == false; i++)
691 MapBlock *block = i.getNode()->getValue();
692 modified_blocks.insert(block->getPos(), block);
696 Set the modified blocks unsent for all the clients
698 if(modified_blocks.size() > 0)
700 SetBlocksNotSent(modified_blocks);
703 m_clients.step(dtime);
705 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
707 // send masterserver announce
709 float &counter = m_masterserver_timer;
710 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
711 g_settings->getBool("server_announce") == true)
713 ServerList::sendAnnounce(!counter ? "start" : "update",
714 m_clients.getPlayerNames(),
716 m_env->getGameTime(),
727 Check added and deleted active objects
730 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
731 JMutexAutoLock envlock(m_env_mutex);
734 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
735 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
737 // Radius inside which objects are active
738 s16 radius = g_settings->getS16("active_object_send_range_blocks");
739 radius *= MAP_BLOCKSIZE;
741 for(std::map<u16, RemoteClient*>::iterator
743 i != clients.end(); ++i)
745 RemoteClient *client = i->second;
747 // If definitions and textures have not been sent, don't
748 // send objects either
749 if (client->getState() < DefinitionsSent)
752 Player *player = m_env->getPlayer(client->peer_id);
755 // This can happen if the client timeouts somehow
756 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
758 <<" has no associated player"<<std::endl;*/
761 v3s16 pos = floatToInt(player->getPosition(), BS);
763 std::set<u16> removed_objects;
764 std::set<u16> added_objects;
765 m_env->getRemovedActiveObjects(pos, radius,
766 client->m_known_objects, removed_objects);
767 m_env->getAddedActiveObjects(pos, radius,
768 client->m_known_objects, added_objects);
770 // Ignore if nothing happened
771 if(removed_objects.size() == 0 && added_objects.size() == 0)
773 //infostream<<"active objects: none changed"<<std::endl;
777 std::string data_buffer;
781 // Handle removed objects
782 writeU16((u8*)buf, removed_objects.size());
783 data_buffer.append(buf, 2);
784 for(std::set<u16>::iterator
785 i = removed_objects.begin();
786 i != removed_objects.end(); ++i)
790 ServerActiveObject* obj = m_env->getActiveObject(id);
792 // Add to data buffer for sending
793 writeU16((u8*)buf, id);
794 data_buffer.append(buf, 2);
796 // Remove from known objects
797 client->m_known_objects.erase(id);
799 if(obj && obj->m_known_by_count > 0)
800 obj->m_known_by_count--;
803 // Handle added objects
804 writeU16((u8*)buf, added_objects.size());
805 data_buffer.append(buf, 2);
806 for(std::set<u16>::iterator
807 i = added_objects.begin();
808 i != added_objects.end(); ++i)
812 ServerActiveObject* obj = m_env->getActiveObject(id);
815 u8 type = ACTIVEOBJECT_TYPE_INVALID;
817 infostream<<"WARNING: "<<__FUNCTION_NAME
818 <<": NULL object"<<std::endl;
820 type = obj->getSendType();
822 // Add to data buffer for sending
823 writeU16((u8*)buf, id);
824 data_buffer.append(buf, 2);
825 writeU8((u8*)buf, type);
826 data_buffer.append(buf, 1);
829 data_buffer.append(serializeLongString(
830 obj->getClientInitializationData(client->net_proto_version)));
832 data_buffer.append(serializeLongString(""));
834 // Add to known objects
835 client->m_known_objects.insert(id);
838 obj->m_known_by_count++;
842 SharedBuffer<u8> reply(2 + data_buffer.size());
843 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
844 memcpy((char*)&reply[2], data_buffer.c_str(),
847 m_clients.send(client->peer_id, 0, reply, true);
849 verbosestream<<"Server: Sent object remove/add: "
850 <<removed_objects.size()<<" removed, "
851 <<added_objects.size()<<" added, "
852 <<"packet size is "<<reply.getSize()<<std::endl;
857 Collect a list of all the objects known by the clients
858 and report it back to the environment.
861 core::map<u16, bool> all_known_objects;
863 for(core::map<u16, RemoteClient*>::Iterator
864 i = m_clients.getIterator();
865 i.atEnd() == false; i++)
867 RemoteClient *client = i.getNode()->getValue();
868 // Go through all known objects of client
869 for(core::map<u16, bool>::Iterator
870 i = client->m_known_objects.getIterator();
871 i.atEnd()==false; i++)
873 u16 id = i.getNode()->getKey();
874 all_known_objects[id] = true;
878 m_env->setKnownActiveObjects(whatever);
887 JMutexAutoLock envlock(m_env_mutex);
888 ScopeProfiler sp(g_profiler, "Server: sending object messages");
891 // Value = data sent by object
892 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
894 // Get active object messages from environment
897 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
901 std::list<ActiveObjectMessage>* message_list = NULL;
902 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
903 n = buffered_messages.find(aom.id);
904 if(n == buffered_messages.end())
906 message_list = new std::list<ActiveObjectMessage>;
907 buffered_messages[aom.id] = message_list;
911 message_list = n->second;
913 message_list->push_back(aom);
917 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
918 // Route data to every client
919 for(std::map<u16, RemoteClient*>::iterator
921 i != clients.end(); ++i)
923 RemoteClient *client = i->second;
924 std::string reliable_data;
925 std::string unreliable_data;
926 // Go through all objects in message buffer
927 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
928 j = buffered_messages.begin();
929 j != buffered_messages.end(); ++j)
931 // If object is not known by client, skip it
933 if(client->m_known_objects.find(id) == client->m_known_objects.end())
935 // Get message list of object
936 std::list<ActiveObjectMessage>* list = j->second;
937 // Go through every message
938 for(std::list<ActiveObjectMessage>::iterator
939 k = list->begin(); k != list->end(); ++k)
941 // Compose the full new data with header
942 ActiveObjectMessage aom = *k;
943 std::string new_data;
946 writeU16((u8*)&buf[0], aom.id);
947 new_data.append(buf, 2);
949 new_data += serializeString(aom.datastring);
950 // Add data to buffer
952 reliable_data += new_data;
954 unreliable_data += new_data;
958 reliable_data and unreliable_data are now ready.
961 if(reliable_data.size() > 0)
963 SharedBuffer<u8> reply(2 + reliable_data.size());
964 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
965 memcpy((char*)&reply[2], reliable_data.c_str(),
966 reliable_data.size());
968 m_clients.send(client->peer_id, 0, reply, true);
970 if(unreliable_data.size() > 0)
972 SharedBuffer<u8> reply(2 + unreliable_data.size());
973 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
974 memcpy((char*)&reply[2], unreliable_data.c_str(),
975 unreliable_data.size());
976 // Send as unreliable
977 m_clients.send(client->peer_id, 1, reply, false);
980 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
982 infostream<<"Server: Size of object message data: "
983 <<"reliable: "<<reliable_data.size()
984 <<", unreliable: "<<unreliable_data.size()
990 // Clear buffered_messages
991 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
992 i = buffered_messages.begin();
993 i != buffered_messages.end(); ++i)
1000 Send queued-for-sending map edit events.
1003 // We will be accessing the environment
1004 JMutexAutoLock lock(m_env_mutex);
1006 // Don't send too many at a time
1009 // Single change sending is disabled if queue size is not small
1010 bool disable_single_change_sending = false;
1011 if(m_unsent_map_edit_queue.size() >= 4)
1012 disable_single_change_sending = true;
1014 int event_count = m_unsent_map_edit_queue.size();
1016 // We'll log the amount of each
1019 while(m_unsent_map_edit_queue.size() != 0)
1021 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1023 // Players far away from the change are stored here.
1024 // Instead of sending the changes, MapBlocks are set not sent
1026 std::list<u16> far_players;
1028 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1030 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1031 prof.add("MEET_ADDNODE", 1);
1032 if(disable_single_change_sending)
1033 sendAddNode(event->p, event->n, event->already_known_by_peer,
1034 &far_players, 5, event->type == MEET_ADDNODE);
1036 sendAddNode(event->p, event->n, event->already_known_by_peer,
1037 &far_players, 30, event->type == MEET_ADDNODE);
1039 else if(event->type == MEET_REMOVENODE)
1041 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1042 prof.add("MEET_REMOVENODE", 1);
1043 if(disable_single_change_sending)
1044 sendRemoveNode(event->p, event->already_known_by_peer,
1047 sendRemoveNode(event->p, event->already_known_by_peer,
1050 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1052 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1053 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1054 setBlockNotSent(event->p);
1056 else if(event->type == MEET_OTHER)
1058 infostream<<"Server: MEET_OTHER"<<std::endl;
1059 prof.add("MEET_OTHER", 1);
1060 for(std::set<v3s16>::iterator
1061 i = event->modified_blocks.begin();
1062 i != event->modified_blocks.end(); ++i)
1064 setBlockNotSent(*i);
1069 prof.add("unknown", 1);
1070 infostream<<"WARNING: Server: Unknown MapEditEvent "
1071 <<((u32)event->type)<<std::endl;
1075 Set blocks not sent to far players
1077 if(far_players.size() > 0)
1079 // Convert list format to that wanted by SetBlocksNotSent
1080 std::map<v3s16, MapBlock*> modified_blocks2;
1081 for(std::set<v3s16>::iterator
1082 i = event->modified_blocks.begin();
1083 i != event->modified_blocks.end(); ++i)
1085 modified_blocks2[*i] =
1086 m_env->getMap().getBlockNoCreateNoEx(*i);
1088 // Set blocks not sent
1089 for(std::list<u16>::iterator
1090 i = far_players.begin();
1091 i != far_players.end(); ++i)
1094 RemoteClient *client = getClient(peer_id);
1097 client->SetBlocksNotSent(modified_blocks2);
1103 /*// Don't send too many at a time
1105 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1109 if(event_count >= 5){
1110 infostream<<"Server: MapEditEvents:"<<std::endl;
1111 prof.print(infostream);
1112 } else if(event_count != 0){
1113 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1114 prof.print(verbosestream);
1120 Trigger emergethread (it somehow gets to a non-triggered but
1121 bysy state sometimes)
1124 float &counter = m_emergethread_trigger_timer;
1130 m_emerge->startThreads();
1132 // Update m_enable_rollback_recording here too
1133 m_enable_rollback_recording =
1134 g_settings->getBool("enable_rollback_recording");
1138 // Save map, players and auth stuff
1140 float &counter = m_savemap_timer;
1142 if(counter >= g_settings->getFloat("server_map_save_interval"))
1145 JMutexAutoLock lock(m_env_mutex);
1147 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1150 if(m_banmanager->isModified())
1151 m_banmanager->save();
1153 // Save changed parts of map
1154 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1157 m_env->serializePlayers(m_path_world);
1159 // Save environment metadata
1160 m_env->saveMeta(m_path_world);
1165 void Server::Receive()
1167 DSTACK(__FUNCTION_NAME);
1168 SharedBuffer<u8> data;
1172 datasize = m_con.Receive(peer_id,data);
1173 ProcessData(*data, datasize, peer_id);
1175 catch(con::InvalidIncomingDataException &e)
1177 infostream<<"Server::Receive(): "
1178 "InvalidIncomingDataException: what()="
1179 <<e.what()<<std::endl;
1181 catch(con::PeerNotFoundException &e)
1183 //NOTE: This is not needed anymore
1185 // The peer has been disconnected.
1186 // Find the associated player and remove it.
1188 /*JMutexAutoLock envlock(m_env_mutex);
1190 infostream<<"ServerThread: peer_id="<<peer_id
1191 <<" has apparently closed connection. "
1192 <<"Removing player."<<std::endl;
1194 m_env->removePlayer(peer_id);*/
1196 catch(ClientStateError &e)
1198 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1199 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1200 L"Try reconnecting or updating your client");
1204 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1206 std::string playername = "";
1207 PlayerSAO *playersao = NULL;
1209 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
1210 if (client != NULL) {
1211 playername = client->getName();
1212 playersao = emergePlayer(playername.c_str(), peer_id);
1216 RemotePlayer *player =
1217 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1219 // If failed, cancel
1220 if((playersao == NULL) || (player == NULL))
1222 if(player && player->peer_id != 0){
1223 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1224 <<" (player allocated to an another client)"<<std::endl;
1225 DenyAccess(peer_id, L"Another client is connected with this "
1226 L"name. If your client closed unexpectedly, try again in "
1229 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1231 DenyAccess(peer_id, L"Could not allocate player.");
1237 Send complete position information
1239 SendMovePlayer(peer_id);
1242 SendPlayerPrivileges(peer_id);
1244 // Send inventory formspec
1245 SendPlayerInventoryFormspec(peer_id);
1248 UpdateCrafting(peer_id);
1249 SendInventory(peer_id);
1252 if(g_settings->getBool("enable_damage"))
1253 SendPlayerHP(peer_id);
1256 SendPlayerBreath(peer_id);
1258 // Show death screen if necessary
1260 SendDeathscreen(peer_id, false, v3f(0,0,0));
1262 // Note things in chat if not in simple singleplayer mode
1263 if(!m_simple_singleplayer_mode)
1265 // Send information about server to player in chat
1266 SendChatMessage(peer_id, getStatusString());
1268 // Send information about joining in chat
1270 std::wstring name = L"unknown";
1271 Player *player = m_env->getPlayer(peer_id);
1273 name = narrow_to_wide(player->getName());
1275 std::wstring message;
1278 message += L" joined the game.";
1279 SendChatMessage(PEER_ID_INEXISTENT,message);
1283 actionstream<<player->getName() <<" joins game. " << std::endl;
1288 std::vector<std::string> names = m_clients.getPlayerNames();
1290 actionstream<<player->getName() <<" joins game. List of players: ";
1292 for (std::vector<std::string>::iterator i = names.begin();
1293 i != names.end(); i++)
1295 actionstream << *i << " ";
1298 actionstream<<std::endl;
1303 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1305 DSTACK(__FUNCTION_NAME);
1306 // Environment is locked first.
1307 JMutexAutoLock envlock(m_env_mutex);
1309 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1313 Address address = getPeerAddress(peer_id);
1314 addr_s = address.serializeString();
1316 // drop player if is ip is banned
1317 if(m_banmanager->isIpBanned(addr_s)){
1318 std::string ban_name = m_banmanager->getBanName(addr_s);
1319 infostream<<"Server: A banned client tried to connect from "
1320 <<addr_s<<"; banned name was "
1321 <<ban_name<<std::endl;
1322 // This actually doesn't seem to transfer to the client
1323 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1324 +narrow_to_wide(ban_name));
1328 catch(con::PeerNotFoundException &e)
1330 errorstream<<"Server::ProcessData(): Cancelling: peer "
1331 <<peer_id<<" not found"<<std::endl;
1341 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1343 if(command == TOSERVER_INIT)
1345 // [0] u16 TOSERVER_INIT
1346 // [2] u8 SER_FMT_VER_HIGHEST_READ
1347 // [3] u8[20] player_name
1348 // [23] u8[28] password <--- can be sent without this, from old versions
1350 if(datasize < 2+1+PLAYERNAME_SIZE)
1353 RemoteClient* client = getClient(peer_id,Created);
1355 // If net_proto_version is set, this client has already been handled
1356 if(client->getState() > Created)
1358 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1359 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1363 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1364 <<peer_id<<")"<<std::endl;
1366 // Do not allow multiple players in simple singleplayer mode.
1367 // This isn't a perfect way to do it, but will suffice for now
1368 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1369 infostream<<"Server: Not allowing another client ("<<addr_s
1370 <<") to connect in simple singleplayer mode"<<std::endl;
1371 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1375 // First byte after command is maximum supported
1376 // serialization version
1377 u8 client_max = data[2];
1378 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1379 // Use the highest version supported by both
1380 u8 deployed = std::min(client_max, our_max);
1381 // If it's lower than the lowest supported, give up.
1382 if(deployed < SER_FMT_VER_LOWEST)
1383 deployed = SER_FMT_VER_INVALID;
1385 if(deployed == SER_FMT_VER_INVALID)
1387 actionstream<<"Server: A mismatched client tried to connect from "
1388 <<addr_s<<std::endl;
1389 infostream<<"Server: Cannot negotiate serialization version with "
1390 <<addr_s<<std::endl;
1391 DenyAccess(peer_id, std::wstring(
1392 L"Your client's version is not supported.\n"
1393 L"Server version is ")
1394 + narrow_to_wide(minetest_version_simple) + L"."
1399 client->setPendingSerializationVersion(deployed);
1402 Read and check network protocol version
1405 u16 min_net_proto_version = 0;
1406 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1407 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1409 // Use same version as minimum and maximum if maximum version field
1410 // doesn't exist (backwards compatibility)
1411 u16 max_net_proto_version = min_net_proto_version;
1412 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1413 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1415 // Start with client's maximum version
1416 u16 net_proto_version = max_net_proto_version;
1418 // Figure out a working version if it is possible at all
1419 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1420 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1422 // If maximum is larger than our maximum, go with our maximum
1423 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1424 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1425 // Else go with client's maximum
1427 net_proto_version = max_net_proto_version;
1430 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1431 <<min_net_proto_version<<", max: "<<max_net_proto_version
1432 <<", chosen: "<<net_proto_version<<std::endl;
1434 client->net_proto_version = net_proto_version;
1436 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1437 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1439 actionstream<<"Server: A mismatched client tried to connect from "
1440 <<addr_s<<std::endl;
1441 DenyAccess(peer_id, std::wstring(
1442 L"Your client's version is not supported.\n"
1443 L"Server version is ")
1444 + narrow_to_wide(minetest_version_simple) + L",\n"
1445 + L"server's PROTOCOL_VERSION is "
1446 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1448 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1449 + L", client's PROTOCOL_VERSION is "
1450 + narrow_to_wide(itos(min_net_proto_version))
1452 + narrow_to_wide(itos(max_net_proto_version))
1457 if(g_settings->getBool("strict_protocol_version_checking"))
1459 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1461 actionstream<<"Server: A mismatched (strict) client tried to "
1462 <<"connect from "<<addr_s<<std::endl;
1463 DenyAccess(peer_id, std::wstring(
1464 L"Your client's version is not supported.\n"
1465 L"Server version is ")
1466 + narrow_to_wide(minetest_version_simple) + L",\n"
1467 + L"server's PROTOCOL_VERSION (strict) is "
1468 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1469 + L", client's PROTOCOL_VERSION is "
1470 + narrow_to_wide(itos(min_net_proto_version))
1472 + narrow_to_wide(itos(max_net_proto_version))
1483 char playername[PLAYERNAME_SIZE];
1484 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1486 playername[i] = data[3+i];
1488 playername[PLAYERNAME_SIZE-1] = 0;
1490 if(playername[0]=='\0')
1492 actionstream<<"Server: Player with an empty name "
1493 <<"tried to connect from "<<addr_s<<std::endl;
1494 DenyAccess(peer_id, L"Empty name");
1498 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1500 actionstream<<"Server: Player with an invalid name "
1501 <<"tried to connect from "<<addr_s<<std::endl;
1502 DenyAccess(peer_id, L"Name contains unallowed characters");
1506 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1508 actionstream<<"Server: Player with the name \"singleplayer\" "
1509 <<"tried to connect from "<<addr_s<<std::endl;
1510 DenyAccess(peer_id, L"Name is not allowed");
1516 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1518 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1519 <<"tried to connect from "<<addr_s<<" "
1520 <<"but it was disallowed for the following reason: "
1521 <<reason<<std::endl;
1522 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1527 infostream<<"Server: New connection: \""<<playername<<"\" from "
1528 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1531 char given_password[PASSWORD_SIZE];
1532 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1534 // old version - assume blank password
1535 given_password[0] = 0;
1539 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1541 given_password[i] = data[23+i];
1543 given_password[PASSWORD_SIZE-1] = 0;
1546 if(!base64_is_valid(given_password)){
1547 actionstream<<"Server: "<<playername
1548 <<" supplied invalid password hash"<<std::endl;
1549 DenyAccess(peer_id, L"Invalid password hash");
1553 // Enforce user limit.
1554 // Don't enforce for users that have some admin right
1555 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1556 !checkPriv(playername, "server") &&
1557 !checkPriv(playername, "ban") &&
1558 !checkPriv(playername, "privs") &&
1559 !checkPriv(playername, "password") &&
1560 playername != g_settings->get("name"))
1562 actionstream<<"Server: "<<playername<<" tried to join, but there"
1563 <<" are already max_users="
1564 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1565 DenyAccess(peer_id, L"Too many users.");
1569 std::string checkpwd; // Password hash to check against
1570 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1572 // If no authentication info exists for user, create it
1574 if(!isSingleplayer() &&
1575 g_settings->getBool("disallow_empty_password") &&
1576 std::string(given_password) == ""){
1577 actionstream<<"Server: "<<playername
1578 <<" supplied empty password"<<std::endl;
1579 DenyAccess(peer_id, L"Empty passwords are "
1580 L"disallowed. Set a password and try again.");
1583 std::wstring raw_default_password =
1584 narrow_to_wide(g_settings->get("default_password"));
1585 std::string initial_password =
1586 translatePassword(playername, raw_default_password);
1588 // If default_password is empty, allow any initial password
1589 if (raw_default_password.length() == 0)
1590 initial_password = given_password;
1592 m_script->createAuth(playername, initial_password);
1595 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1598 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1599 <<" (auth handler does not work?)"<<std::endl;
1600 DenyAccess(peer_id, L"Not allowed to login");
1604 if(given_password != checkpwd){
1605 actionstream<<"Server: "<<playername<<" supplied wrong password"
1607 DenyAccess(peer_id, L"Wrong password");
1611 RemotePlayer *player =
1612 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1614 if(player && player->peer_id != 0){
1615 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1616 <<" (player allocated to an another client)"<<std::endl;
1617 DenyAccess(peer_id, L"Another client is connected with this "
1618 L"name. If your client closed unexpectedly, try again in "
1622 m_clients.setPlayerName(peer_id,playername);
1625 Answer with a TOCLIENT_INIT
1628 SharedBuffer<u8> reply(2+1+6+8+4);
1629 writeU16(&reply[0], TOCLIENT_INIT);
1630 writeU8(&reply[2], deployed);
1631 //send dummy pos for legacy reasons only
1632 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1633 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1634 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1637 m_clients.send(peer_id, 0, reply, true);
1638 m_clients.event(peer_id, Init);
1644 if(command == TOSERVER_INIT2)
1647 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1648 <<peer_id<<std::endl;
1650 m_clients.event(peer_id, GotInit2);
1651 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1654 ///// begin compatibility code
1655 PlayerSAO* playersao = NULL;
1656 if (protocol_version <= 22) {
1657 playersao = StageTwoClientInit(peer_id);
1659 if (playersao == NULL) {
1661 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1662 << peer_id << std::endl;
1666 ///// end compatibility code
1669 Send some initialization data
1672 infostream<<"Server: Sending content to "
1673 <<getPlayerName(peer_id)<<std::endl;
1675 // Send player movement settings
1676 SendMovement(peer_id);
1678 // Send item definitions
1679 SendItemDef(peer_id, m_itemdef, protocol_version);
1681 // Send node definitions
1682 SendNodeDef(peer_id, m_nodedef, protocol_version);
1684 m_clients.event(peer_id, SetDefinitionsSent);
1686 // Send media announcement
1687 sendMediaAnnouncement(peer_id);
1689 // Send detached inventories
1690 sendDetachedInventories(peer_id);
1693 u16 time = m_env->getTimeOfDay();
1694 float time_speed = g_settings->getFloat("time_speed");
1695 SendTimeOfDay(peer_id, time, time_speed);
1697 ///// begin compatibility code
1698 if (protocol_version <= 22) {
1699 m_clients.event(peer_id, SetClientReady);
1700 m_script->on_joinplayer(playersao);
1702 ///// end compatibility code
1704 // Warnings about protocol version can be issued here
1705 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1707 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1708 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1714 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1715 u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1717 if(peer_ser_ver == SER_FMT_VER_INVALID)
1719 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1720 " serialization format invalid or not initialized."
1721 " Skipping incoming command="<<command<<std::endl;
1725 /* Handle commands relate to client startup */
1726 if(command == TOSERVER_REQUEST_MEDIA) {
1727 std::string datastring((char*)&data[2], datasize-2);
1728 std::istringstream is(datastring, std::ios_base::binary);
1730 std::list<std::string> tosend;
1731 u16 numfiles = readU16(is);
1733 infostream<<"Sending "<<numfiles<<" files to "
1734 <<getPlayerName(peer_id)<<std::endl;
1735 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1737 for(int i = 0; i < numfiles; i++) {
1738 std::string name = deSerializeString(is);
1739 tosend.push_back(name);
1740 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1744 sendRequestedMedia(peer_id, tosend);
1747 else if(command == TOSERVER_RECEIVED_MEDIA) {
1750 else if(command == TOSERVER_CLIENT_READY) {
1751 // clients <= protocol version 22 did not send ready message,
1752 // they're already initialized
1753 assert(peer_proto_ver > 22);
1755 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1757 if (playersao == NULL) {
1759 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1760 << peer_id << std::endl;
1768 m_clients.setClientVersion(
1770 data[2], data[3], data[4],
1771 std::string((char*) &data[8],(u16) data[6]));
1773 m_clients.event(peer_id, SetClientReady);
1774 m_script->on_joinplayer(playersao);
1777 else if(command == TOSERVER_GOTBLOCKS)
1790 u16 count = data[2];
1791 for(u16 i=0; i<count; i++)
1793 if((s16)datasize < 2+1+(i+1)*6)
1794 throw con::InvalidIncomingDataException
1795 ("GOTBLOCKS length is too short");
1796 v3s16 p = readV3S16(&data[2+1+i*6]);
1797 /*infostream<<"Server: GOTBLOCKS ("
1798 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1799 RemoteClient *client = getClient(peer_id);
1800 client->GotBlock(p);
1805 if (m_clients.getClientState(peer_id) < Active)
1807 if (command == TOSERVER_PLAYERPOS) return;
1809 errorstream<<"Got packet command: " << command << " for peer id "
1810 << peer_id << " but client isn't active yet. Dropping packet "
1815 Player *player = m_env->getPlayer(peer_id);
1817 errorstream<<"Server::ProcessData(): Cancelling: "
1818 "No player for peer_id="<<peer_id
1823 PlayerSAO *playersao = player->getPlayerSAO();
1824 if(playersao == NULL){
1825 errorstream<<"Server::ProcessData(): Cancelling: "
1826 "No player object for peer_id="<<peer_id
1831 if(command == TOSERVER_PLAYERPOS)
1833 if(datasize < 2+12+12+4+4)
1837 v3s32 ps = readV3S32(&data[start+2]);
1838 v3s32 ss = readV3S32(&data[start+2+12]);
1839 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1840 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1842 if(datasize >= 2+12+12+4+4+4)
1843 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1844 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1845 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1846 pitch = wrapDegrees(pitch);
1847 yaw = wrapDegrees(yaw);
1849 player->setPosition(position);
1850 player->setSpeed(speed);
1851 player->setPitch(pitch);
1852 player->setYaw(yaw);
1853 player->keyPressed=keyPressed;
1854 player->control.up = (bool)(keyPressed&1);
1855 player->control.down = (bool)(keyPressed&2);
1856 player->control.left = (bool)(keyPressed&4);
1857 player->control.right = (bool)(keyPressed&8);
1858 player->control.jump = (bool)(keyPressed&16);
1859 player->control.aux1 = (bool)(keyPressed&32);
1860 player->control.sneak = (bool)(keyPressed&64);
1861 player->control.LMB = (bool)(keyPressed&128);
1862 player->control.RMB = (bool)(keyPressed&256);
1864 bool cheated = playersao->checkMovementCheat();
1867 m_script->on_cheat(playersao, "moved_too_fast");
1870 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1871 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1872 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1874 else if(command == TOSERVER_DELETEDBLOCKS)
1887 u16 count = data[2];
1888 for(u16 i=0; i<count; i++)
1890 if((s16)datasize < 2+1+(i+1)*6)
1891 throw con::InvalidIncomingDataException
1892 ("DELETEDBLOCKS length is too short");
1893 v3s16 p = readV3S16(&data[2+1+i*6]);
1894 /*infostream<<"Server: DELETEDBLOCKS ("
1895 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1896 RemoteClient *client = getClient(peer_id);
1897 client->SetBlockNotSent(p);
1900 else if(command == TOSERVER_CLICK_OBJECT)
1902 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1905 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1907 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1910 else if(command == TOSERVER_GROUND_ACTION)
1912 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1916 else if(command == TOSERVER_RELEASE)
1918 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1921 else if(command == TOSERVER_SIGNTEXT)
1923 infostream<<"Server: SIGNTEXT not supported anymore"
1927 else if(command == TOSERVER_SIGNNODETEXT)
1929 infostream<<"Server: SIGNNODETEXT not supported anymore"
1933 else if(command == TOSERVER_INVENTORY_ACTION)
1935 // Strip command and create a stream
1936 std::string datastring((char*)&data[2], datasize-2);
1937 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1938 std::istringstream is(datastring, std::ios_base::binary);
1940 InventoryAction *a = InventoryAction::deSerialize(is);
1943 infostream<<"TOSERVER_INVENTORY_ACTION: "
1944 <<"InventoryAction::deSerialize() returned NULL"
1949 // If something goes wrong, this player is to blame
1950 RollbackScopeActor rollback_scope(m_rollback,
1951 std::string("player:")+player->getName());
1954 Note: Always set inventory not sent, to repair cases
1955 where the client made a bad prediction.
1959 Handle restrictions and special cases of the move action
1961 if(a->getType() == IACTION_MOVE)
1963 IMoveAction *ma = (IMoveAction*)a;
1965 ma->from_inv.applyCurrentPlayer(player->getName());
1966 ma->to_inv.applyCurrentPlayer(player->getName());
1968 setInventoryModified(ma->from_inv);
1969 setInventoryModified(ma->to_inv);
1971 bool from_inv_is_current_player =
1972 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1973 (ma->from_inv.name == player->getName());
1975 bool to_inv_is_current_player =
1976 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1977 (ma->to_inv.name == player->getName());
1980 Disable moving items out of craftpreview
1982 if(ma->from_list == "craftpreview")
1984 infostream<<"Ignoring IMoveAction from "
1985 <<(ma->from_inv.dump())<<":"<<ma->from_list
1986 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1987 <<" because src is "<<ma->from_list<<std::endl;
1993 Disable moving items into craftresult and craftpreview
1995 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1997 infostream<<"Ignoring IMoveAction from "
1998 <<(ma->from_inv.dump())<<":"<<ma->from_list
1999 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2000 <<" because dst is "<<ma->to_list<<std::endl;
2005 // Disallow moving items in elsewhere than player's inventory
2006 // if not allowed to interact
2007 if(!checkPriv(player->getName(), "interact") &&
2008 (!from_inv_is_current_player ||
2009 !to_inv_is_current_player))
2011 infostream<<"Cannot move outside of player's inventory: "
2012 <<"No interact privilege"<<std::endl;
2018 Handle restrictions and special cases of the drop action
2020 else if(a->getType() == IACTION_DROP)
2022 IDropAction *da = (IDropAction*)a;
2024 da->from_inv.applyCurrentPlayer(player->getName());
2026 setInventoryModified(da->from_inv);
2029 Disable dropping items out of craftpreview
2031 if(da->from_list == "craftpreview")
2033 infostream<<"Ignoring IDropAction from "
2034 <<(da->from_inv.dump())<<":"<<da->from_list
2035 <<" because src is "<<da->from_list<<std::endl;
2040 // Disallow dropping items if not allowed to interact
2041 if(!checkPriv(player->getName(), "interact"))
2048 Handle restrictions and special cases of the craft action
2050 else if(a->getType() == IACTION_CRAFT)
2052 ICraftAction *ca = (ICraftAction*)a;
2054 ca->craft_inv.applyCurrentPlayer(player->getName());
2056 setInventoryModified(ca->craft_inv);
2058 //bool craft_inv_is_current_player =
2059 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2060 // (ca->craft_inv.name == player->getName());
2062 // Disallow crafting if not allowed to interact
2063 if(!checkPriv(player->getName(), "interact"))
2065 infostream<<"Cannot craft: "
2066 <<"No interact privilege"<<std::endl;
2073 a->apply(this, playersao, this);
2077 else if(command == TOSERVER_CHAT_MESSAGE)
2085 std::string datastring((char*)&data[2], datasize-2);
2086 std::istringstream is(datastring, std::ios_base::binary);
2089 is.read((char*)buf, 2);
2090 u16 len = readU16(buf);
2092 std::wstring message;
2093 for(u16 i=0; i<len; i++)
2095 is.read((char*)buf, 2);
2096 message += (wchar_t)readU16(buf);
2099 // If something goes wrong, this player is to blame
2100 RollbackScopeActor rollback_scope(m_rollback,
2101 std::string("player:")+player->getName());
2103 // Get player name of this client
2104 std::wstring name = narrow_to_wide(player->getName());
2107 bool ate = m_script->on_chat_message(player->getName(),
2108 wide_to_narrow(message));
2109 // If script ate the message, don't proceed
2113 // Line to send to players
2115 // Whether to send to the player that sent the line
2116 bool send_to_sender_only = false;
2118 // Commands are implemented in Lua, so only catch invalid
2119 // commands that were not "eaten" and send an error back
2120 if(message[0] == L'/')
2122 message = message.substr(1);
2123 send_to_sender_only = true;
2124 if(message.length() == 0)
2125 line += L"-!- Empty command";
2127 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2131 if(checkPriv(player->getName(), "shout")){
2137 line += L"-!- You don't have permission to shout.";
2138 send_to_sender_only = true;
2145 Send the message to sender
2147 if (send_to_sender_only)
2149 SendChatMessage(peer_id, line);
2152 Send the message to others
2156 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2158 std::list<u16> clients = m_clients.getClientIDs();
2160 for(std::list<u16>::iterator
2161 i = clients.begin();
2162 i != clients.end(); ++i)
2165 SendChatMessage(*i, line);
2170 else if(command == TOSERVER_DAMAGE)
2172 std::string datastring((char*)&data[2], datasize-2);
2173 std::istringstream is(datastring, std::ios_base::binary);
2174 u8 damage = readU8(is);
2176 if(g_settings->getBool("enable_damage"))
2178 actionstream<<player->getName()<<" damaged by "
2179 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2182 playersao->setHP(playersao->getHP() - damage);
2184 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2187 if(playersao->m_hp_not_sent)
2188 SendPlayerHP(peer_id);
2191 else if(command == TOSERVER_BREATH)
2193 std::string datastring((char*)&data[2], datasize-2);
2194 std::istringstream is(datastring, std::ios_base::binary);
2195 u16 breath = readU16(is);
2196 playersao->setBreath(breath);
2198 else if(command == TOSERVER_PASSWORD)
2201 [0] u16 TOSERVER_PASSWORD
2202 [2] u8[28] old password
2203 [30] u8[28] new password
2206 if(datasize != 2+PASSWORD_SIZE*2)
2208 /*char password[PASSWORD_SIZE];
2209 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2210 password[i] = data[2+i];
2211 password[PASSWORD_SIZE-1] = 0;*/
2213 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2221 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2223 char c = data[2+PASSWORD_SIZE+i];
2229 if(!base64_is_valid(newpwd)){
2230 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2231 // Wrong old password supplied!!
2232 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2236 infostream<<"Server: Client requests a password change from "
2237 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2239 std::string playername = player->getName();
2241 std::string checkpwd;
2242 m_script->getAuth(playername, &checkpwd, NULL);
2244 if(oldpwd != checkpwd)
2246 infostream<<"Server: invalid old password"<<std::endl;
2247 // Wrong old password supplied!!
2248 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2252 bool success = m_script->setPassword(playername, newpwd);
2254 actionstream<<player->getName()<<" changes password"<<std::endl;
2255 SendChatMessage(peer_id, L"Password change successful.");
2257 actionstream<<player->getName()<<" tries to change password but "
2258 <<"it fails"<<std::endl;
2259 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2262 else if(command == TOSERVER_PLAYERITEM)
2267 u16 item = readU16(&data[2]);
2268 playersao->setWieldIndex(item);
2270 else if(command == TOSERVER_RESPAWN)
2272 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2275 RespawnPlayer(peer_id);
2277 actionstream<<player->getName()<<" respawns at "
2278 <<PP(player->getPosition()/BS)<<std::endl;
2280 // ActiveObject is added to environment in AsyncRunStep after
2281 // the previous addition has been succesfully removed
2283 else if(command == TOSERVER_INTERACT)
2285 std::string datastring((char*)&data[2], datasize-2);
2286 std::istringstream is(datastring, std::ios_base::binary);
2292 [5] u32 length of the next item
2293 [9] serialized PointedThing
2295 0: start digging (from undersurface) or use
2296 1: stop digging (all parameters ignored)
2297 2: digging completed
2298 3: place block or item (to abovesurface)
2301 u8 action = readU8(is);
2302 u16 item_i = readU16(is);
2303 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2304 PointedThing pointed;
2305 pointed.deSerialize(tmp_is);
2307 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2308 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2312 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2313 <<" tried to interact, but is dead!"<<std::endl;
2317 v3f player_pos = playersao->getLastGoodPosition();
2319 // Update wielded item
2320 playersao->setWieldIndex(item_i);
2322 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2323 v3s16 p_under = pointed.node_undersurface;
2324 v3s16 p_above = pointed.node_abovesurface;
2326 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2327 ServerActiveObject *pointed_object = NULL;
2328 if(pointed.type == POINTEDTHING_OBJECT)
2330 pointed_object = m_env->getActiveObject(pointed.object_id);
2331 if(pointed_object == NULL)
2333 verbosestream<<"TOSERVER_INTERACT: "
2334 "pointed object is NULL"<<std::endl;
2340 v3f pointed_pos_under = player_pos;
2341 v3f pointed_pos_above = player_pos;
2342 if(pointed.type == POINTEDTHING_NODE)
2344 pointed_pos_under = intToFloat(p_under, BS);
2345 pointed_pos_above = intToFloat(p_above, BS);
2347 else if(pointed.type == POINTEDTHING_OBJECT)
2349 pointed_pos_under = pointed_object->getBasePosition();
2350 pointed_pos_above = pointed_pos_under;
2354 Check that target is reasonably close
2355 (only when digging or placing things)
2357 if(action == 0 || action == 2 || action == 3)
2359 float d = player_pos.getDistanceFrom(pointed_pos_under);
2360 float max_d = BS * 14; // Just some large enough value
2362 actionstream<<"Player "<<player->getName()
2363 <<" tried to access "<<pointed.dump()
2365 <<"d="<<d<<", max_d="<<max_d
2366 <<". ignoring."<<std::endl;
2367 // Re-send block to revert change on client-side
2368 RemoteClient *client = getClient(peer_id);
2369 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2370 client->SetBlockNotSent(blockpos);
2372 m_script->on_cheat(playersao, "interacted_too_far");
2379 Make sure the player is allowed to do it
2381 if(!checkPriv(player->getName(), "interact"))
2383 actionstream<<player->getName()<<" attempted to interact with "
2384 <<pointed.dump()<<" without 'interact' privilege"
2386 // Re-send block to revert change on client-side
2387 RemoteClient *client = getClient(peer_id);
2388 // Digging completed -> under
2390 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2391 client->SetBlockNotSent(blockpos);
2393 // Placement -> above
2395 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2396 client->SetBlockNotSent(blockpos);
2402 If something goes wrong, this player is to blame
2404 RollbackScopeActor rollback_scope(m_rollback,
2405 std::string("player:")+player->getName());
2408 0: start digging or punch object
2412 if(pointed.type == POINTEDTHING_NODE)
2415 NOTE: This can be used in the future to check if
2416 somebody is cheating, by checking the timing.
2418 MapNode n(CONTENT_IGNORE);
2421 n = m_env->getMap().getNode(p_under);
2423 catch(InvalidPositionException &e)
2425 infostream<<"Server: Not punching: Node not found."
2426 <<" Adding block to emerge queue."
2428 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2430 if(n.getContent() != CONTENT_IGNORE)
2431 m_script->node_on_punch(p_under, n, playersao, pointed);
2433 playersao->noCheatDigStart(p_under);
2435 else if(pointed.type == POINTEDTHING_OBJECT)
2437 // Skip if object has been removed
2438 if(pointed_object->m_removed)
2441 actionstream<<player->getName()<<" punches object "
2442 <<pointed.object_id<<": "
2443 <<pointed_object->getDescription()<<std::endl;
2445 ItemStack punchitem = playersao->getWieldedItem();
2446 ToolCapabilities toolcap =
2447 punchitem.getToolCapabilities(m_itemdef);
2448 v3f dir = (pointed_object->getBasePosition() -
2449 (player->getPosition() + player->getEyeOffset())
2451 float time_from_last_punch =
2452 playersao->resetTimeFromLastPunch();
2453 pointed_object->punch(dir, &toolcap, playersao,
2454 time_from_last_punch);
2462 else if(action == 1)
2467 2: Digging completed
2469 else if(action == 2)
2471 // Only digging of nodes
2472 if(pointed.type == POINTEDTHING_NODE)
2474 MapNode n(CONTENT_IGNORE);
2477 n = m_env->getMap().getNode(p_under);
2479 catch(InvalidPositionException &e)
2481 infostream<<"Server: Not finishing digging: Node not found."
2482 <<" Adding block to emerge queue."
2484 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2487 /* Cheat prevention */
2488 bool is_valid_dig = true;
2489 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2491 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2492 float nocheat_t = playersao->getNoCheatDigTime();
2493 playersao->noCheatDigEnd();
2494 // If player didn't start digging this, ignore dig
2495 if(nocheat_p != p_under){
2496 infostream<<"Server: NoCheat: "<<player->getName()
2497 <<" started digging "
2498 <<PP(nocheat_p)<<" and completed digging "
2499 <<PP(p_under)<<"; not digging."<<std::endl;
2500 is_valid_dig = false;
2502 m_script->on_cheat(playersao, "finished_unknown_dig");
2504 // Get player's wielded item
2505 ItemStack playeritem;
2506 InventoryList *mlist = playersao->getInventory()->getList("main");
2508 playeritem = mlist->getItem(playersao->getWieldIndex());
2509 ToolCapabilities playeritem_toolcap =
2510 playeritem.getToolCapabilities(m_itemdef);
2511 // Get diggability and expected digging time
2512 DigParams params = getDigParams(m_nodedef->get(n).groups,
2513 &playeritem_toolcap);
2514 // If can't dig, try hand
2515 if(!params.diggable){
2516 const ItemDefinition &hand = m_itemdef->get("");
2517 const ToolCapabilities *tp = hand.tool_capabilities;
2519 params = getDigParams(m_nodedef->get(n).groups, tp);
2521 // If can't dig, ignore dig
2522 if(!params.diggable){
2523 infostream<<"Server: NoCheat: "<<player->getName()
2524 <<" completed digging "<<PP(p_under)
2525 <<", which is not diggable with tool. not digging."
2527 is_valid_dig = false;
2529 m_script->on_cheat(playersao, "dug_unbreakable");
2531 // Check digging time
2532 // If already invalidated, we don't have to
2534 // Well not our problem then
2536 // Clean and long dig
2537 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2538 // All is good, but grab time from pool; don't care if
2539 // it's actually available
2540 playersao->getDigPool().grab(params.time);
2542 // Short or laggy dig
2543 // Try getting the time from pool
2544 else if(playersao->getDigPool().grab(params.time)){
2549 infostream<<"Server: NoCheat: "<<player->getName()
2550 <<" completed digging "<<PP(p_under)
2551 <<"too fast; not digging."<<std::endl;
2552 is_valid_dig = false;
2554 m_script->on_cheat(playersao, "dug_too_fast");
2558 /* Actually dig node */
2560 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2561 m_script->node_on_dig(p_under, n, playersao);
2563 // Send unusual result (that is, node not being removed)
2564 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2566 // Re-send block to revert change on client-side
2567 RemoteClient *client = getClient(peer_id);
2568 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2569 client->SetBlockNotSent(blockpos);
2575 3: place block or right-click object
2577 else if(action == 3)
2579 ItemStack item = playersao->getWieldedItem();
2581 // Reset build time counter
2582 if(pointed.type == POINTEDTHING_NODE &&
2583 item.getDefinition(m_itemdef).type == ITEM_NODE)
2584 getClient(peer_id)->m_time_from_building = 0.0;
2586 if(pointed.type == POINTEDTHING_OBJECT)
2588 // Right click object
2590 // Skip if object has been removed
2591 if(pointed_object->m_removed)
2594 actionstream<<player->getName()<<" right-clicks object "
2595 <<pointed.object_id<<": "
2596 <<pointed_object->getDescription()<<std::endl;
2599 pointed_object->rightClick(playersao);
2601 else if(m_script->item_OnPlace(
2602 item, playersao, pointed))
2604 // Placement was handled in lua
2606 // Apply returned ItemStack
2607 playersao->setWieldedItem(item);
2610 // If item has node placement prediction, always send the
2611 // blocks to make sure the client knows what exactly happened
2612 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2613 RemoteClient *client = getClient(peer_id);
2614 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2615 client->SetBlockNotSent(blockpos);
2616 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2617 if(blockpos2 != blockpos){
2618 client->SetBlockNotSent(blockpos2);
2626 else if(action == 4)
2628 ItemStack item = playersao->getWieldedItem();
2630 actionstream<<player->getName()<<" uses "<<item.name
2631 <<", pointing at "<<pointed.dump()<<std::endl;
2633 if(m_script->item_OnUse(
2634 item, playersao, pointed))
2636 // Apply returned ItemStack
2637 playersao->setWieldedItem(item);
2644 Catch invalid actions
2648 infostream<<"WARNING: Server: Invalid action "
2649 <<action<<std::endl;
2652 else if(command == TOSERVER_REMOVED_SOUNDS)
2654 std::string datastring((char*)&data[2], datasize-2);
2655 std::istringstream is(datastring, std::ios_base::binary);
2657 int num = readU16(is);
2658 for(int k=0; k<num; k++){
2659 s32 id = readS32(is);
2660 std::map<s32, ServerPlayingSound>::iterator i =
2661 m_playing_sounds.find(id);
2662 if(i == m_playing_sounds.end())
2664 ServerPlayingSound &psound = i->second;
2665 psound.clients.erase(peer_id);
2666 if(psound.clients.size() == 0)
2667 m_playing_sounds.erase(i++);
2670 else if(command == TOSERVER_NODEMETA_FIELDS)
2672 std::string datastring((char*)&data[2], datasize-2);
2673 std::istringstream is(datastring, std::ios_base::binary);
2675 v3s16 p = readV3S16(is);
2676 std::string formname = deSerializeString(is);
2677 int num = readU16(is);
2678 std::map<std::string, std::string> fields;
2679 for(int k=0; k<num; k++){
2680 std::string fieldname = deSerializeString(is);
2681 std::string fieldvalue = deSerializeLongString(is);
2682 fields[fieldname] = fieldvalue;
2685 // If something goes wrong, this player is to blame
2686 RollbackScopeActor rollback_scope(m_rollback,
2687 std::string("player:")+player->getName());
2689 // Check the target node for rollback data; leave others unnoticed
2690 RollbackNode rn_old(&m_env->getMap(), p, this);
2692 m_script->node_on_receive_fields(p, formname, fields,playersao);
2694 // Report rollback data
2695 RollbackNode rn_new(&m_env->getMap(), p, this);
2696 if(rollback() && rn_new != rn_old){
2697 RollbackAction action;
2698 action.setSetNode(p, rn_old, rn_new);
2699 rollback()->reportAction(action);
2702 else if(command == TOSERVER_INVENTORY_FIELDS)
2704 std::string datastring((char*)&data[2], datasize-2);
2705 std::istringstream is(datastring, std::ios_base::binary);
2707 std::string formname = deSerializeString(is);
2708 int num = readU16(is);
2709 std::map<std::string, std::string> fields;
2710 for(int k=0; k<num; k++){
2711 std::string fieldname = deSerializeString(is);
2712 std::string fieldvalue = deSerializeLongString(is);
2713 fields[fieldname] = fieldvalue;
2716 m_script->on_playerReceiveFields(playersao, formname, fields);
2720 infostream<<"Server::ProcessData(): Ignoring "
2721 "unknown command "<<command<<std::endl;
2725 catch(SendFailedException &e)
2727 errorstream<<"Server::ProcessData(): SendFailedException: "
2733 void Server::setTimeOfDay(u32 time)
2735 m_env->setTimeOfDay(time);
2736 m_time_of_day_send_timer = 0;
2739 void Server::onMapEditEvent(MapEditEvent *event)
2741 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2742 if(m_ignore_map_edit_events)
2744 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2746 MapEditEvent *e = event->clone();
2747 m_unsent_map_edit_queue.push_back(e);
2750 Inventory* Server::getInventory(const InventoryLocation &loc)
2753 case InventoryLocation::UNDEFINED:
2756 case InventoryLocation::CURRENT_PLAYER:
2759 case InventoryLocation::PLAYER:
2761 Player *player = m_env->getPlayer(loc.name.c_str());
2764 PlayerSAO *playersao = player->getPlayerSAO();
2767 return playersao->getInventory();
2770 case InventoryLocation::NODEMETA:
2772 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2775 return meta->getInventory();
2778 case InventoryLocation::DETACHED:
2780 if(m_detached_inventories.count(loc.name) == 0)
2782 return m_detached_inventories[loc.name];
2790 void Server::setInventoryModified(const InventoryLocation &loc)
2793 case InventoryLocation::UNDEFINED:
2796 case InventoryLocation::PLAYER:
2798 Player *player = m_env->getPlayer(loc.name.c_str());
2801 PlayerSAO *playersao = player->getPlayerSAO();
2804 playersao->m_inventory_not_sent = true;
2805 playersao->m_wielded_item_not_sent = true;
2808 case InventoryLocation::NODEMETA:
2810 v3s16 blockpos = getNodeBlockPos(loc.p);
2812 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2814 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2816 setBlockNotSent(blockpos);
2819 case InventoryLocation::DETACHED:
2821 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2829 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2831 std::list<u16> clients = m_clients.getClientIDs();
2833 // Set the modified blocks unsent for all the clients
2834 for (std::list<u16>::iterator
2835 i = clients.begin();
2836 i != clients.end(); ++i) {
2837 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2839 client->SetBlocksNotSent(block);
2844 void Server::peerAdded(con::Peer *peer)
2846 DSTACK(__FUNCTION_NAME);
2847 verbosestream<<"Server::peerAdded(): peer->id="
2848 <<peer->id<<std::endl;
2851 c.type = con::PEER_ADDED;
2852 c.peer_id = peer->id;
2854 m_peer_change_queue.push_back(c);
2857 void Server::deletingPeer(con::Peer *peer, bool timeout)
2859 DSTACK(__FUNCTION_NAME);
2860 verbosestream<<"Server::deletingPeer(): peer->id="
2861 <<peer->id<<", timeout="<<timeout<<std::endl;
2863 m_clients.event(peer->id,Disconnect);
2865 c.type = con::PEER_REMOVED;
2866 c.peer_id = peer->id;
2867 c.timeout = timeout;
2868 m_peer_change_queue.push_back(c);
2871 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2873 *retval = m_con.getPeerStat(peer_id,type);
2874 if (*retval == -1) return false;
2878 bool Server::getClientInfo(
2887 std::string* vers_string
2890 *state = m_clients.getClientState(peer_id);
2892 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2897 *uptime = client->uptime();
2898 *ser_vers = client->serialization_version;
2899 *prot_vers = client->net_proto_version;
2901 *major = client->getMajor();
2902 *minor = client->getMinor();
2903 *patch = client->getPatch();
2904 *vers_string = client->getPatch();
2911 void Server::handlePeerChanges()
2913 while(m_peer_change_queue.size() > 0)
2915 con::PeerChange c = m_peer_change_queue.pop_front();
2917 verbosestream<<"Server: Handling peer change: "
2918 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2923 case con::PEER_ADDED:
2924 m_clients.CreateClient(c.peer_id);
2927 case con::PEER_REMOVED:
2928 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2932 assert("Invalid peer change event received!" == 0);
2938 void Server::SendMovement(u16 peer_id)
2940 DSTACK(__FUNCTION_NAME);
2941 std::ostringstream os(std::ios_base::binary);
2943 writeU16(os, TOCLIENT_MOVEMENT);
2944 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2945 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2946 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2947 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2948 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2949 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2950 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2951 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2952 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2953 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2954 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2955 writeF1000(os, g_settings->getFloat("movement_gravity"));
2958 std::string s = os.str();
2959 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2961 m_clients.send(peer_id, 0, data, true);
2964 void Server::SendHP(u16 peer_id, u8 hp)
2966 DSTACK(__FUNCTION_NAME);
2967 std::ostringstream os(std::ios_base::binary);
2969 writeU16(os, TOCLIENT_HP);
2973 std::string s = os.str();
2974 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2976 m_clients.send(peer_id, 0, data, true);
2979 void Server::SendBreath(u16 peer_id, u16 breath)
2981 DSTACK(__FUNCTION_NAME);
2982 std::ostringstream os(std::ios_base::binary);
2984 writeU16(os, TOCLIENT_BREATH);
2985 writeU16(os, breath);
2988 std::string s = os.str();
2989 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2991 m_clients.send(peer_id, 0, data, true);
2994 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2996 DSTACK(__FUNCTION_NAME);
2997 std::ostringstream os(std::ios_base::binary);
2999 writeU16(os, TOCLIENT_ACCESS_DENIED);
3000 os<<serializeWideString(reason);
3003 std::string s = os.str();
3004 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3006 m_clients.send(peer_id, 0, data, true);
3009 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3010 v3f camera_point_target)
3012 DSTACK(__FUNCTION_NAME);
3013 std::ostringstream os(std::ios_base::binary);
3015 writeU16(os, TOCLIENT_DEATHSCREEN);
3016 writeU8(os, set_camera_point_target);
3017 writeV3F1000(os, camera_point_target);
3020 std::string s = os.str();
3021 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3023 m_clients.send(peer_id, 0, data, true);
3026 void Server::SendItemDef(u16 peer_id,
3027 IItemDefManager *itemdef, u16 protocol_version)
3029 DSTACK(__FUNCTION_NAME);
3030 std::ostringstream os(std::ios_base::binary);
3034 u32 length of the next item
3035 zlib-compressed serialized ItemDefManager
3037 writeU16(os, TOCLIENT_ITEMDEF);
3038 std::ostringstream tmp_os(std::ios::binary);
3039 itemdef->serialize(tmp_os, protocol_version);
3040 std::ostringstream tmp_os2(std::ios::binary);
3041 compressZlib(tmp_os.str(), tmp_os2);
3042 os<<serializeLongString(tmp_os2.str());
3045 std::string s = os.str();
3046 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3047 <<"): size="<<s.size()<<std::endl;
3048 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3050 m_clients.send(peer_id, 0, data, true);
3053 void Server::SendNodeDef(u16 peer_id,
3054 INodeDefManager *nodedef, u16 protocol_version)
3056 DSTACK(__FUNCTION_NAME);
3057 std::ostringstream os(std::ios_base::binary);
3061 u32 length of the next item
3062 zlib-compressed serialized NodeDefManager
3064 writeU16(os, TOCLIENT_NODEDEF);
3065 std::ostringstream tmp_os(std::ios::binary);
3066 nodedef->serialize(tmp_os, protocol_version);
3067 std::ostringstream tmp_os2(std::ios::binary);
3068 compressZlib(tmp_os.str(), tmp_os2);
3069 os<<serializeLongString(tmp_os2.str());
3072 std::string s = os.str();
3073 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3074 <<"): size="<<s.size()<<std::endl;
3075 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3077 m_clients.send(peer_id, 0, data, true);
3081 Non-static send methods
3084 void Server::SendInventory(u16 peer_id)
3086 DSTACK(__FUNCTION_NAME);
3088 PlayerSAO *playersao = getPlayerSAO(peer_id);
3091 playersao->m_inventory_not_sent = false;
3097 std::ostringstream os;
3098 playersao->getInventory()->serialize(os);
3100 std::string s = os.str();
3102 SharedBuffer<u8> data(s.size()+2);
3103 writeU16(&data[0], TOCLIENT_INVENTORY);
3104 memcpy(&data[2], s.c_str(), s.size());
3107 m_clients.send(peer_id, 0, data, true);
3110 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3112 DSTACK(__FUNCTION_NAME);
3114 std::ostringstream os(std::ios_base::binary);
3118 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3119 os.write((char*)buf, 2);
3122 writeU16(buf, message.size());
3123 os.write((char*)buf, 2);
3126 for(u32 i=0; i<message.size(); i++)
3130 os.write((char*)buf, 2);
3134 std::string s = os.str();
3135 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3137 if (peer_id != PEER_ID_INEXISTENT)
3140 m_clients.send(peer_id, 0, data, true);
3144 m_clients.sendToAll(0,data,true);
3148 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3149 const std::string &formname)
3151 DSTACK(__FUNCTION_NAME);
3153 std::ostringstream os(std::ios_base::binary);
3157 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3158 os.write((char*)buf, 2);
3159 os<<serializeLongString(formspec);
3160 os<<serializeString(formname);
3163 std::string s = os.str();
3164 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3166 m_clients.send(peer_id, 0, data, true);
3169 // Spawns a particle on peer with peer_id
3170 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3171 float expirationtime, float size, bool collisiondetection,
3172 bool vertical, std::string texture)
3174 DSTACK(__FUNCTION_NAME);
3176 std::ostringstream os(std::ios_base::binary);
3177 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3178 writeV3F1000(os, pos);
3179 writeV3F1000(os, velocity);
3180 writeV3F1000(os, acceleration);
3181 writeF1000(os, expirationtime);
3182 writeF1000(os, size);
3183 writeU8(os, collisiondetection);
3184 os<<serializeLongString(texture);
3185 writeU8(os, vertical);
3188 std::string s = os.str();
3189 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3191 if (peer_id != PEER_ID_INEXISTENT)
3194 m_clients.send(peer_id, 0, data, true);
3198 m_clients.sendToAll(0,data,true);
3202 // Adds a ParticleSpawner on peer with peer_id
3203 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3204 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3205 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3207 DSTACK(__FUNCTION_NAME);
3209 std::ostringstream os(std::ios_base::binary);
3210 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3212 writeU16(os, amount);
3213 writeF1000(os, spawntime);
3214 writeV3F1000(os, minpos);
3215 writeV3F1000(os, maxpos);
3216 writeV3F1000(os, minvel);
3217 writeV3F1000(os, maxvel);
3218 writeV3F1000(os, minacc);
3219 writeV3F1000(os, maxacc);
3220 writeF1000(os, minexptime);
3221 writeF1000(os, maxexptime);
3222 writeF1000(os, minsize);
3223 writeF1000(os, maxsize);
3224 writeU8(os, collisiondetection);
3225 os<<serializeLongString(texture);
3227 writeU8(os, vertical);
3230 std::string s = os.str();
3231 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3233 if (peer_id != PEER_ID_INEXISTENT)
3236 m_clients.send(peer_id, 0, data, true);
3239 m_clients.sendToAll(0,data,true);
3243 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3245 DSTACK(__FUNCTION_NAME);
3247 std::ostringstream os(std::ios_base::binary);
3248 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3253 std::string s = os.str();
3254 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3256 if (peer_id != PEER_ID_INEXISTENT) {
3258 m_clients.send(peer_id, 0, data, true);
3261 m_clients.sendToAll(0,data,true);
3266 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3268 std::ostringstream os(std::ios_base::binary);
3271 writeU16(os, TOCLIENT_HUDADD);
3273 writeU8(os, (u8)form->type);
3274 writeV2F1000(os, form->pos);
3275 os << serializeString(form->name);
3276 writeV2F1000(os, form->scale);
3277 os << serializeString(form->text);
3278 writeU32(os, form->number);
3279 writeU32(os, form->item);
3280 writeU32(os, form->dir);
3281 writeV2F1000(os, form->align);
3282 writeV2F1000(os, form->offset);
3283 writeV3F1000(os, form->world_pos);
3286 std::string s = os.str();
3287 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3289 m_clients.send(peer_id, 1, data, true);
3292 void Server::SendHUDRemove(u16 peer_id, u32 id)
3294 std::ostringstream os(std::ios_base::binary);
3297 writeU16(os, TOCLIENT_HUDRM);
3301 std::string s = os.str();
3302 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3305 m_clients.send(peer_id, 1, data, true);
3308 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3310 std::ostringstream os(std::ios_base::binary);
3313 writeU16(os, TOCLIENT_HUDCHANGE);
3315 writeU8(os, (u8)stat);
3318 case HUD_STAT_SCALE:
3319 case HUD_STAT_ALIGN:
3320 case HUD_STAT_OFFSET:
3321 writeV2F1000(os, *(v2f *)value);
3325 os << serializeString(*(std::string *)value);
3327 case HUD_STAT_WORLD_POS:
3328 writeV3F1000(os, *(v3f *)value);
3330 case HUD_STAT_NUMBER:
3334 writeU32(os, *(u32 *)value);
3339 std::string s = os.str();
3340 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3342 m_clients.send(peer_id, 0, data, true);
3345 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3347 std::ostringstream os(std::ios_base::binary);
3350 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3351 writeU32(os, flags);
3355 std::string s = os.str();
3356 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3358 m_clients.send(peer_id, 0, data, true);
3361 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3363 std::ostringstream os(std::ios_base::binary);
3366 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3367 writeU16(os, param);
3368 os<<serializeString(value);
3371 std::string s = os.str();
3372 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3374 m_clients.send(peer_id, 0, data, true);
3377 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3378 const std::string &type, const std::vector<std::string> ¶ms)
3380 std::ostringstream os(std::ios_base::binary);
3383 writeU16(os, TOCLIENT_SET_SKY);
3384 writeARGB8(os, bgcolor);
3385 os<<serializeString(type);
3386 writeU16(os, params.size());
3387 for(size_t i=0; i<params.size(); i++)
3388 os<<serializeString(params[i]);
3391 std::string s = os.str();
3392 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3394 m_clients.send(peer_id, 0, data, true);
3397 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3400 std::ostringstream os(std::ios_base::binary);
3403 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3404 writeU8(os, do_override);
3405 writeU16(os, ratio*65535);
3408 std::string s = os.str();
3409 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3411 m_clients.send(peer_id, 0, data, true);
3414 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3416 DSTACK(__FUNCTION_NAME);
3419 SharedBuffer<u8> data(2+2+4);
3420 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3421 writeU16(&data[2], time);
3422 writeF1000(&data[4], time_speed);
3424 if (peer_id == PEER_ID_INEXISTENT) {
3425 m_clients.sendToAll(0,data,true);
3429 m_clients.send(peer_id, 0, data, true);
3433 void Server::SendPlayerHP(u16 peer_id)
3435 DSTACK(__FUNCTION_NAME);
3436 PlayerSAO *playersao = getPlayerSAO(peer_id);
3438 playersao->m_hp_not_sent = false;
3439 SendHP(peer_id, playersao->getHP());
3441 // Send to other clients
3442 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3443 ActiveObjectMessage aom(playersao->getId(), true, str);
3444 playersao->m_messages_out.push_back(aom);
3447 void Server::SendPlayerBreath(u16 peer_id)
3449 DSTACK(__FUNCTION_NAME);
3450 PlayerSAO *playersao = getPlayerSAO(peer_id);
3452 playersao->m_breath_not_sent = false;
3453 SendBreath(peer_id, playersao->getBreath());
3456 void Server::SendMovePlayer(u16 peer_id)
3458 DSTACK(__FUNCTION_NAME);
3459 Player *player = m_env->getPlayer(peer_id);
3462 std::ostringstream os(std::ios_base::binary);
3463 writeU16(os, TOCLIENT_MOVE_PLAYER);
3464 writeV3F1000(os, player->getPosition());
3465 writeF1000(os, player->getPitch());
3466 writeF1000(os, player->getYaw());
3469 v3f pos = player->getPosition();
3470 f32 pitch = player->getPitch();
3471 f32 yaw = player->getYaw();
3472 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3473 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3480 std::string s = os.str();
3481 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3483 m_clients.send(peer_id, 0, data, true);
3486 void Server::SendPlayerPrivileges(u16 peer_id)
3488 Player *player = m_env->getPlayer(peer_id);
3490 if(player->peer_id == PEER_ID_INEXISTENT)
3493 std::set<std::string> privs;
3494 m_script->getAuth(player->getName(), NULL, &privs);
3496 std::ostringstream os(std::ios_base::binary);
3497 writeU16(os, TOCLIENT_PRIVILEGES);
3498 writeU16(os, privs.size());
3499 for(std::set<std::string>::const_iterator i = privs.begin();
3500 i != privs.end(); i++){
3501 os<<serializeString(*i);
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);
3511 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3513 Player *player = m_env->getPlayer(peer_id);
3515 if(player->peer_id == PEER_ID_INEXISTENT)
3518 std::ostringstream os(std::ios_base::binary);
3519 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3520 os<<serializeLongString(player->inventory_formspec);
3523 std::string s = os.str();
3524 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3526 m_clients.send(peer_id, 0, data, true);
3529 s32 Server::playSound(const SimpleSoundSpec &spec,
3530 const ServerSoundParams ¶ms)
3532 // Find out initial position of sound
3533 bool pos_exists = false;
3534 v3f pos = params.getPos(m_env, &pos_exists);
3535 // If position is not found while it should be, cancel sound
3536 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3539 // Filter destination clients
3540 std::list<u16> dst_clients;
3541 if(params.to_player != "")
3543 Player *player = m_env->getPlayer(params.to_player.c_str());
3545 infostream<<"Server::playSound: Player \""<<params.to_player
3546 <<"\" not found"<<std::endl;
3549 if(player->peer_id == PEER_ID_INEXISTENT){
3550 infostream<<"Server::playSound: Player \""<<params.to_player
3551 <<"\" not connected"<<std::endl;
3554 dst_clients.push_back(player->peer_id);
3558 std::list<u16> clients = m_clients.getClientIDs();
3560 for(std::list<u16>::iterator
3561 i = clients.begin(); i != clients.end(); ++i)
3563 Player *player = m_env->getPlayer(*i);
3567 if(player->getPosition().getDistanceFrom(pos) >
3568 params.max_hear_distance)
3571 dst_clients.push_back(*i);
3574 if(dst_clients.size() == 0)
3578 s32 id = m_next_sound_id++;
3579 // The sound will exist as a reference in m_playing_sounds
3580 m_playing_sounds[id] = ServerPlayingSound();
3581 ServerPlayingSound &psound = m_playing_sounds[id];
3582 psound.params = params;
3583 for(std::list<u16>::iterator i = dst_clients.begin();
3584 i != dst_clients.end(); i++)
3585 psound.clients.insert(*i);
3587 std::ostringstream os(std::ios_base::binary);
3588 writeU16(os, TOCLIENT_PLAY_SOUND);
3590 os<<serializeString(spec.name);
3591 writeF1000(os, spec.gain * params.gain);
3592 writeU8(os, params.type);
3593 writeV3F1000(os, pos);
3594 writeU16(os, params.object);
3595 writeU8(os, params.loop);
3597 std::string s = os.str();
3598 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3600 for(std::list<u16>::iterator i = dst_clients.begin();
3601 i != dst_clients.end(); i++){
3603 m_clients.send(*i, 0, data, true);
3607 void Server::stopSound(s32 handle)
3609 // Get sound reference
3610 std::map<s32, ServerPlayingSound>::iterator i =
3611 m_playing_sounds.find(handle);
3612 if(i == m_playing_sounds.end())
3614 ServerPlayingSound &psound = i->second;
3616 std::ostringstream os(std::ios_base::binary);
3617 writeU16(os, TOCLIENT_STOP_SOUND);
3618 writeS32(os, handle);
3620 std::string s = os.str();
3621 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3623 for(std::set<u16>::iterator i = psound.clients.begin();
3624 i != psound.clients.end(); i++){
3626 m_clients.send(*i, 0, data, true);
3628 // Remove sound reference
3629 m_playing_sounds.erase(i);
3632 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3633 std::list<u16> *far_players, float far_d_nodes)
3635 float maxd = far_d_nodes*BS;
3636 v3f p_f = intToFloat(p, BS);
3640 SharedBuffer<u8> reply(replysize);
3641 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3642 writeS16(&reply[2], p.X);
3643 writeS16(&reply[4], p.Y);
3644 writeS16(&reply[6], p.Z);
3646 std::list<u16> clients = m_clients.getClientIDs();
3647 for(std::list<u16>::iterator
3648 i = clients.begin();
3649 i != clients.end(); ++i)
3654 Player *player = m_env->getPlayer(*i);
3657 // If player is far away, only set modified blocks not sent
3658 v3f player_pos = player->getPosition();
3659 if(player_pos.getDistanceFrom(p_f) > maxd)
3661 far_players->push_back(*i);
3668 m_clients.send(*i, 0, reply, true);
3672 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3673 std::list<u16> *far_players, float far_d_nodes,
3674 bool remove_metadata)
3676 float maxd = far_d_nodes*BS;
3677 v3f p_f = intToFloat(p, BS);
3679 std::list<u16> clients = m_clients.getClientIDs();
3680 for(std::list<u16>::iterator
3681 i = clients.begin();
3682 i != clients.end(); ++i)
3688 Player *player = m_env->getPlayer(*i);
3691 // If player is far away, only set modified blocks not sent
3692 v3f player_pos = player->getPosition();
3693 if(player_pos.getDistanceFrom(p_f) > maxd)
3695 far_players->push_back(*i);
3700 SharedBuffer<u8> reply(0);
3702 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3706 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3707 reply = SharedBuffer<u8>(replysize);
3708 writeU16(&reply[0], TOCLIENT_ADDNODE);
3709 writeS16(&reply[2], p.X);
3710 writeS16(&reply[4], p.Y);
3711 writeS16(&reply[6], p.Z);
3712 n.serialize(&reply[8], client->serialization_version);
3713 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3714 writeU8(&reply[index], remove_metadata ? 0 : 1);
3716 if (!remove_metadata) {
3717 if (client->net_proto_version <= 21) {
3718 // Old clients always clear metadata; fix it
3719 // by sending the full block again.
3720 client->SetBlockNotSent(p);
3727 if (reply.getSize() > 0)
3728 m_clients.send(*i, 0, reply, true);
3732 void Server::setBlockNotSent(v3s16 p)
3734 std::list<u16> clients = m_clients.getClientIDs();
3736 for(std::list<u16>::iterator
3737 i = clients.begin();
3738 i != clients.end(); ++i)
3740 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3741 client->SetBlockNotSent(p);
3746 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3748 DSTACK(__FUNCTION_NAME);
3750 v3s16 p = block->getPos();
3754 bool completely_air = true;
3755 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3756 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3757 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3759 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3761 completely_air = false;
3762 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3767 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3769 infostream<<"[completely air] ";
3770 infostream<<std::endl;
3774 Create a packet with the block in the right format
3777 std::ostringstream os(std::ios_base::binary);
3778 block->serialize(os, ver, false);
3779 block->serializeNetworkSpecific(os, net_proto_version);
3780 std::string s = os.str();
3781 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3783 u32 replysize = 8 + blockdata.getSize();
3784 SharedBuffer<u8> reply(replysize);
3785 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3786 writeS16(&reply[2], p.X);
3787 writeS16(&reply[4], p.Y);
3788 writeS16(&reply[6], p.Z);
3789 memcpy(&reply[8], *blockdata, blockdata.getSize());
3791 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3792 <<": \tpacket size: "<<replysize<<std::endl;*/
3797 m_clients.send(peer_id, 2, reply, true);
3800 void Server::SendBlocks(float dtime)
3802 DSTACK(__FUNCTION_NAME);
3804 JMutexAutoLock envlock(m_env_mutex);
3805 //TODO check if one big lock could be faster then multiple small ones
3807 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3809 std::vector<PrioritySortedBlockTransfer> queue;
3811 s32 total_sending = 0;
3814 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3816 std::list<u16> clients = m_clients.getClientIDs();
3819 for(std::list<u16>::iterator
3820 i = clients.begin();
3821 i != clients.end(); ++i)
3823 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3828 total_sending += client->SendingCount();
3829 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3835 // Lowest priority number comes first.
3836 // Lowest is most important.
3837 std::sort(queue.begin(), queue.end());
3840 for(u32 i=0; i<queue.size(); i++)
3842 //TODO: Calculate limit dynamically
3843 if(total_sending >= g_settings->getS32
3844 ("max_simultaneous_block_sends_server_total"))
3847 PrioritySortedBlockTransfer q = queue[i];
3849 MapBlock *block = NULL;
3852 block = m_env->getMap().getBlockNoCreate(q.pos);
3854 catch(InvalidPositionException &e)
3859 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3864 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3866 client->SentBlock(q.pos);
3872 void Server::fillMediaCache()
3874 DSTACK(__FUNCTION_NAME);
3876 infostream<<"Server: Calculating media file checksums"<<std::endl;
3878 // Collect all media file paths
3879 std::list<std::string> paths;
3880 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3881 i != m_mods.end(); i++){
3882 const ModSpec &mod = *i;
3883 paths.push_back(mod.path + DIR_DELIM + "textures");
3884 paths.push_back(mod.path + DIR_DELIM + "sounds");
3885 paths.push_back(mod.path + DIR_DELIM + "media");
3886 paths.push_back(mod.path + DIR_DELIM + "models");
3888 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3890 // Collect media file information from paths into cache
3891 for(std::list<std::string>::iterator i = paths.begin();
3892 i != paths.end(); i++)
3894 std::string mediapath = *i;
3895 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3896 for(u32 j=0; j<dirlist.size(); j++){
3897 if(dirlist[j].dir) // Ignode dirs
3899 std::string filename = dirlist[j].name;
3900 // If name contains illegal characters, ignore the file
3901 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3902 infostream<<"Server: ignoring illegal file name: \""
3903 <<filename<<"\""<<std::endl;
3906 // If name is not in a supported format, ignore it
3907 const char *supported_ext[] = {
3908 ".png", ".jpg", ".bmp", ".tga",
3909 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3911 ".x", ".b3d", ".md2", ".obj",
3914 if(removeStringEnd(filename, supported_ext) == ""){
3915 infostream<<"Server: ignoring unsupported file extension: \""
3916 <<filename<<"\""<<std::endl;
3919 // Ok, attempt to load the file and add to cache
3920 std::string filepath = mediapath + DIR_DELIM + filename;
3922 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3923 if(fis.good() == false){
3924 errorstream<<"Server::fillMediaCache(): Could not open \""
3925 <<filename<<"\" for reading"<<std::endl;
3928 std::ostringstream tmp_os(std::ios_base::binary);
3932 fis.read(buf, 1024);
3933 std::streamsize len = fis.gcount();
3934 tmp_os.write(buf, len);
3943 errorstream<<"Server::fillMediaCache(): Failed to read \""
3944 <<filename<<"\""<<std::endl;
3947 if(tmp_os.str().length() == 0){
3948 errorstream<<"Server::fillMediaCache(): Empty file \""
3949 <<filepath<<"\""<<std::endl;
3954 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3956 unsigned char *digest = sha1.getDigest();
3957 std::string sha1_base64 = base64_encode(digest, 20);
3958 std::string sha1_hex = hex_encode((char*)digest, 20);
3962 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3963 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3968 struct SendableMediaAnnouncement
3971 std::string sha1_digest;
3973 SendableMediaAnnouncement(const std::string &name_="",
3974 const std::string &sha1_digest_=""):
3976 sha1_digest(sha1_digest_)
3980 void Server::sendMediaAnnouncement(u16 peer_id)
3982 DSTACK(__FUNCTION_NAME);
3984 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
3987 std::list<SendableMediaAnnouncement> file_announcements;
3989 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
3990 i != m_media.end(); i++){
3992 file_announcements.push_back(
3993 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
3997 std::ostringstream os(std::ios_base::binary);
4005 u16 length of sha1_digest
4010 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4011 writeU16(os, file_announcements.size());
4013 for(std::list<SendableMediaAnnouncement>::iterator
4014 j = file_announcements.begin();
4015 j != file_announcements.end(); ++j){
4016 os<<serializeString(j->name);
4017 os<<serializeString(j->sha1_digest);
4019 os<<serializeString(g_settings->get("remote_media"));
4022 std::string s = os.str();
4023 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4026 m_clients.send(peer_id, 0, data, true);
4029 struct SendableMedia
4035 SendableMedia(const std::string &name_="", const std::string &path_="",
4036 const std::string &data_=""):
4043 void Server::sendRequestedMedia(u16 peer_id,
4044 const std::list<std::string> &tosend)
4046 DSTACK(__FUNCTION_NAME);
4048 verbosestream<<"Server::sendRequestedMedia(): "
4049 <<"Sending files to client"<<std::endl;
4053 // Put 5kB in one bunch (this is not accurate)
4054 u32 bytes_per_bunch = 5000;
4056 std::vector< std::list<SendableMedia> > file_bunches;
4057 file_bunches.push_back(std::list<SendableMedia>());
4059 u32 file_size_bunch_total = 0;
4061 for(std::list<std::string>::const_iterator i = tosend.begin();
4062 i != tosend.end(); ++i)
4064 const std::string &name = *i;
4066 if(m_media.find(name) == m_media.end()){
4067 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4068 <<"unknown file \""<<(name)<<"\""<<std::endl;
4072 //TODO get path + name
4073 std::string tpath = m_media[name].path;
4076 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4077 if(fis.good() == false){
4078 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4079 <<tpath<<"\" for reading"<<std::endl;
4082 std::ostringstream tmp_os(std::ios_base::binary);
4086 fis.read(buf, 1024);
4087 std::streamsize len = fis.gcount();
4088 tmp_os.write(buf, len);
4089 file_size_bunch_total += len;
4098 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4099 <<name<<"\""<<std::endl;
4102 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4103 <<tname<<"\""<<std::endl;*/
4105 file_bunches[file_bunches.size()-1].push_back(
4106 SendableMedia(name, tpath, tmp_os.str()));
4108 // Start next bunch if got enough data
4109 if(file_size_bunch_total >= bytes_per_bunch){
4110 file_bunches.push_back(std::list<SendableMedia>());
4111 file_size_bunch_total = 0;
4116 /* Create and send packets */
4118 u32 num_bunches = file_bunches.size();
4119 for(u32 i=0; i<num_bunches; i++)
4121 std::ostringstream os(std::ios_base::binary);
4125 u16 total number of texture bunches
4126 u16 index of this bunch
4127 u32 number of files in this bunch
4136 writeU16(os, TOCLIENT_MEDIA);
4137 writeU16(os, num_bunches);
4139 writeU32(os, file_bunches[i].size());
4141 for(std::list<SendableMedia>::iterator
4142 j = file_bunches[i].begin();
4143 j != file_bunches[i].end(); ++j){
4144 os<<serializeString(j->name);
4145 os<<serializeLongString(j->data);
4149 std::string s = os.str();
4150 verbosestream<<"Server::sendRequestedMedia(): bunch "
4151 <<i<<"/"<<num_bunches
4152 <<" files="<<file_bunches[i].size()
4153 <<" size=" <<s.size()<<std::endl;
4154 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4156 m_clients.send(peer_id, 2, data, true);
4160 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4162 if(m_detached_inventories.count(name) == 0){
4163 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4166 Inventory *inv = m_detached_inventories[name];
4168 std::ostringstream os(std::ios_base::binary);
4169 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4170 os<<serializeString(name);
4174 std::string s = os.str();
4175 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4177 if (peer_id != PEER_ID_INEXISTENT)
4180 m_clients.send(peer_id, 0, data, true);
4184 m_clients.sendToAll(0,data,true);
4188 void Server::sendDetachedInventories(u16 peer_id)
4190 DSTACK(__FUNCTION_NAME);
4192 for(std::map<std::string, Inventory*>::iterator
4193 i = m_detached_inventories.begin();
4194 i != m_detached_inventories.end(); i++){
4195 const std::string &name = i->first;
4196 //Inventory *inv = i->second;
4197 sendDetachedInventory(name, peer_id);
4205 void Server::DiePlayer(u16 peer_id)
4207 DSTACK(__FUNCTION_NAME);
4209 PlayerSAO *playersao = getPlayerSAO(peer_id);
4212 infostream<<"Server::DiePlayer(): Player "
4213 <<playersao->getPlayer()->getName()
4214 <<" dies"<<std::endl;
4216 playersao->setHP(0);
4218 // Trigger scripted stuff
4219 m_script->on_dieplayer(playersao);
4221 SendPlayerHP(peer_id);
4222 SendDeathscreen(peer_id, false, v3f(0,0,0));
4225 void Server::RespawnPlayer(u16 peer_id)
4227 DSTACK(__FUNCTION_NAME);
4229 PlayerSAO *playersao = getPlayerSAO(peer_id);
4232 infostream<<"Server::RespawnPlayer(): Player "
4233 <<playersao->getPlayer()->getName()
4234 <<" respawns"<<std::endl;
4236 playersao->setHP(PLAYER_MAX_HP);
4238 bool repositioned = m_script->on_respawnplayer(playersao);
4240 v3f pos = findSpawnPos(m_env->getServerMap());
4241 playersao->setPos(pos);
4245 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4247 DSTACK(__FUNCTION_NAME);
4249 SendAccessDenied(peer_id, reason);
4250 m_clients.event(peer_id,SetDenied);
4251 m_con.DisconnectPeer(peer_id);
4254 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4256 DSTACK(__FUNCTION_NAME);
4257 std::wstring message;
4260 Clear references to playing sounds
4262 for(std::map<s32, ServerPlayingSound>::iterator
4263 i = m_playing_sounds.begin();
4264 i != m_playing_sounds.end();)
4266 ServerPlayingSound &psound = i->second;
4267 psound.clients.erase(peer_id);
4268 if(psound.clients.size() == 0)
4269 m_playing_sounds.erase(i++);
4274 Player *player = m_env->getPlayer(peer_id);
4276 // Collect information about leaving in chat
4278 if(player != NULL && reason != CDR_DENY)
4280 std::wstring name = narrow_to_wide(player->getName());
4283 message += L" left the game.";
4284 if(reason == CDR_TIMEOUT)
4285 message += L" (timed out)";
4289 /* Run scripts and remove from environment */
4293 PlayerSAO *playersao = player->getPlayerSAO();
4296 m_script->on_leaveplayer(playersao);
4298 playersao->disconnected();
4306 if(player != NULL && reason != CDR_DENY)
4308 std::ostringstream os(std::ios_base::binary);
4309 std::list<u16> clients = m_clients.getClientIDs();
4311 for(std::list<u16>::iterator
4312 i = clients.begin();
4313 i != clients.end(); ++i)
4316 Player *player = m_env->getPlayer(*i);
4319 // Get name of player
4320 os<<player->getName()<<" ";
4323 actionstream<<player->getName()<<" "
4324 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4325 <<" List of players: "<<os.str()<<std::endl;
4329 JMutexAutoLock env_lock(m_env_mutex);
4330 m_clients.DeleteClient(peer_id);
4334 // Send leave chat message to all remaining clients
4335 if(message.length() != 0)
4336 SendChatMessage(PEER_ID_INEXISTENT,message);
4339 void Server::UpdateCrafting(u16 peer_id)
4341 DSTACK(__FUNCTION_NAME);
4343 Player* player = m_env->getPlayer(peer_id);
4346 // Get a preview for crafting
4348 InventoryLocation loc;
4349 loc.setPlayer(player->getName());
4350 getCraftingResult(&player->inventory, preview, false, this);
4351 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4353 // Put the new preview in
4354 InventoryList *plist = player->inventory.getList("craftpreview");
4356 assert(plist->getSize() >= 1);
4357 plist->changeItem(0, preview);
4360 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4362 RemoteClient *client = getClientNoEx(peer_id,state_min);
4364 throw ClientNotFoundException("Client not found");
4368 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4370 return m_clients.getClientNoEx(peer_id, state_min);
4373 std::string Server::getPlayerName(u16 peer_id)
4375 Player *player = m_env->getPlayer(peer_id);
4377 return "[id="+itos(peer_id)+"]";
4378 return player->getName();
4381 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4383 Player *player = m_env->getPlayer(peer_id);
4386 return player->getPlayerSAO();
4389 std::wstring Server::getStatusString()
4391 std::wostringstream os(std::ios_base::binary);
4394 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4396 os<<L", uptime="<<m_uptime.get();
4398 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4399 // Information about clients
4402 std::list<u16> clients = m_clients.getClientIDs();
4403 for(std::list<u16>::iterator i = clients.begin();
4404 i != clients.end(); ++i)
4407 Player *player = m_env->getPlayer(*i);
4408 // Get name of player
4409 std::wstring name = L"unknown";
4411 name = narrow_to_wide(player->getName());
4412 // Add name to information string
4420 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4421 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4422 if(g_settings->get("motd") != "")
4423 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4427 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4429 std::set<std::string> privs;
4430 m_script->getAuth(name, NULL, &privs);
4434 bool Server::checkPriv(const std::string &name, const std::string &priv)
4436 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4437 return (privs.count(priv) != 0);
4440 void Server::reportPrivsModified(const std::string &name)
4443 std::list<u16> clients = m_clients.getClientIDs();
4444 for(std::list<u16>::iterator
4445 i = clients.begin();
4446 i != clients.end(); ++i){
4447 Player *player = m_env->getPlayer(*i);
4448 reportPrivsModified(player->getName());
4451 Player *player = m_env->getPlayer(name.c_str());
4454 SendPlayerPrivileges(player->peer_id);
4455 PlayerSAO *sao = player->getPlayerSAO();
4458 sao->updatePrivileges(
4459 getPlayerEffectivePrivs(name),
4464 void Server::reportInventoryFormspecModified(const std::string &name)
4466 Player *player = m_env->getPlayer(name.c_str());
4469 SendPlayerInventoryFormspec(player->peer_id);
4472 void Server::setIpBanned(const std::string &ip, const std::string &name)
4474 m_banmanager->add(ip, name);
4477 void Server::unsetIpBanned(const std::string &ip_or_name)
4479 m_banmanager->remove(ip_or_name);
4482 std::string Server::getBanDescription(const std::string &ip_or_name)
4484 return m_banmanager->getBanDescription(ip_or_name);
4487 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4489 Player *player = m_env->getPlayer(name);
4493 if (player->peer_id == PEER_ID_INEXISTENT)
4496 SendChatMessage(player->peer_id, msg);
4499 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4501 Player *player = m_env->getPlayer(playername);
4505 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4509 SendShowFormspecMessage(player->peer_id, formspec, formname);
4513 u32 Server::hudAdd(Player *player, HudElement *form) {
4517 u32 id = player->getFreeHudID();
4518 if (id < player->hud.size())
4519 player->hud[id] = form;
4521 player->hud.push_back(form);
4523 SendHUDAdd(player->peer_id, id, form);
4527 bool Server::hudRemove(Player *player, u32 id) {
4528 if (!player || id >= player->hud.size() || !player->hud[id])
4531 delete player->hud[id];
4532 player->hud[id] = NULL;
4534 SendHUDRemove(player->peer_id, id);
4538 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4542 SendHUDChange(player->peer_id, id, stat, data);
4546 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4550 SendHUDSetFlags(player->peer_id, flags, mask);
4554 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4557 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4560 std::ostringstream os(std::ios::binary);
4561 writeS32(os, hotbar_itemcount);
4562 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4566 void Server::hudSetHotbarImage(Player *player, std::string name) {
4570 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4573 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4577 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4580 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4581 const std::string &type, const std::vector<std::string> ¶ms)
4586 SendSetSky(player->peer_id, bgcolor, type, params);
4590 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4596 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4600 void Server::notifyPlayers(const std::wstring &msg)
4602 SendChatMessage(PEER_ID_INEXISTENT,msg);
4605 void Server::spawnParticle(const char *playername, v3f pos,
4606 v3f velocity, v3f acceleration,
4607 float expirationtime, float size, bool
4608 collisiondetection, bool vertical, std::string texture)
4610 Player *player = m_env->getPlayer(playername);
4613 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4614 expirationtime, size, collisiondetection, vertical, texture);
4617 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4618 float expirationtime, float size,
4619 bool collisiondetection, bool vertical, std::string texture)
4621 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4622 expirationtime, size, collisiondetection, vertical, texture);
4625 u32 Server::addParticleSpawner(const char *playername,
4626 u16 amount, float spawntime,
4627 v3f minpos, v3f maxpos,
4628 v3f minvel, v3f maxvel,
4629 v3f minacc, v3f maxacc,
4630 float minexptime, float maxexptime,
4631 float minsize, float maxsize,
4632 bool collisiondetection, bool vertical, std::string texture)
4634 Player *player = m_env->getPlayer(playername);
4639 for(;;) // look for unused particlespawner id
4642 if (std::find(m_particlespawner_ids.begin(),
4643 m_particlespawner_ids.end(), id)
4644 == m_particlespawner_ids.end())
4646 m_particlespawner_ids.push_back(id);
4651 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4652 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4653 minexptime, maxexptime, minsize, maxsize,
4654 collisiondetection, vertical, texture, id);
4659 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4660 v3f minpos, v3f maxpos,
4661 v3f minvel, v3f maxvel,
4662 v3f minacc, v3f maxacc,
4663 float minexptime, float maxexptime,
4664 float minsize, float maxsize,
4665 bool collisiondetection, bool vertical, std::string texture)
4668 for(;;) // look for unused particlespawner id
4671 if (std::find(m_particlespawner_ids.begin(),
4672 m_particlespawner_ids.end(), id)
4673 == m_particlespawner_ids.end())
4675 m_particlespawner_ids.push_back(id);
4680 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4681 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4682 minexptime, maxexptime, minsize, maxsize,
4683 collisiondetection, vertical, texture, id);
4688 void Server::deleteParticleSpawner(const char *playername, u32 id)
4690 Player *player = m_env->getPlayer(playername);
4694 m_particlespawner_ids.erase(
4695 std::remove(m_particlespawner_ids.begin(),
4696 m_particlespawner_ids.end(), id),
4697 m_particlespawner_ids.end());
4698 SendDeleteParticleSpawner(player->peer_id, id);
4701 void Server::deleteParticleSpawnerAll(u32 id)
4703 m_particlespawner_ids.erase(
4704 std::remove(m_particlespawner_ids.begin(),
4705 m_particlespawner_ids.end(), id),
4706 m_particlespawner_ids.end());
4707 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4710 Inventory* Server::createDetachedInventory(const std::string &name)
4712 if(m_detached_inventories.count(name) > 0){
4713 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4714 delete m_detached_inventories[name];
4716 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4718 Inventory *inv = new Inventory(m_itemdef);
4720 m_detached_inventories[name] = inv;
4721 //TODO find a better way to do this
4722 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4729 BoolScopeSet(bool *dst, bool val):
4732 m_orig_state = *m_dst;
4737 *m_dst = m_orig_state;
4744 // actions: time-reversed list
4745 // Return value: success/failure
4746 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4747 std::list<std::string> *log)
4749 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4750 ServerMap *map = (ServerMap*)(&m_env->getMap());
4751 // Disable rollback report sink while reverting
4752 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4754 // Fail if no actions to handle
4755 if(actions.empty()){
4756 log->push_back("Nothing to do.");
4763 for(std::list<RollbackAction>::const_iterator
4764 i = actions.begin();
4765 i != actions.end(); i++)
4767 const RollbackAction &action = *i;
4769 bool success = action.applyRevert(map, this, this);
4772 std::ostringstream os;
4773 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4774 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4776 log->push_back(os.str());
4778 std::ostringstream os;
4779 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4780 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4782 log->push_back(os.str());
4786 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4787 <<" failed"<<std::endl;
4789 // Call it done if less than half failed
4790 return num_failed <= num_tried/2;
4793 // IGameDef interface
4795 IItemDefManager* Server::getItemDefManager()
4799 INodeDefManager* Server::getNodeDefManager()
4803 ICraftDefManager* Server::getCraftDefManager()
4807 ITextureSource* Server::getTextureSource()
4811 IShaderSource* Server::getShaderSource()
4815 u16 Server::allocateUnknownNodeId(const std::string &name)
4817 return m_nodedef->allocateDummy(name);
4819 ISoundManager* Server::getSoundManager()
4821 return &dummySoundManager;
4823 MtEventManager* Server::getEventManager()
4827 IRollbackReportSink* Server::getRollbackReportSink()
4829 if(!m_enable_rollback_recording)
4831 if(!m_rollback_sink_enabled)
4836 IWritableItemDefManager* Server::getWritableItemDefManager()
4840 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4844 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4849 const ModSpec* Server::getModSpec(const std::string &modname)
4851 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4852 i != m_mods.end(); i++){
4853 const ModSpec &mod = *i;
4854 if(mod.name == modname)
4859 void Server::getModNames(std::list<std::string> &modlist)
4861 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4863 modlist.push_back(i->name);
4866 std::string Server::getBuiltinLuaPath()
4868 return porting::path_share + DIR_DELIM + "builtin";
4871 v3f findSpawnPos(ServerMap &map)
4873 //return v3f(50,50,50)*BS;
4878 nodepos = v2s16(0,0);
4883 s16 water_level = map.getWaterLevel();
4885 // Try to find a good place a few times
4886 for(s32 i=0; i<1000; i++)
4889 // We're going to try to throw the player to this position
4890 v2s16 nodepos2d = v2s16(
4891 -range + (myrand() % (range * 2)),
4892 -range + (myrand() % (range * 2)));
4894 // Get ground height at point
4895 s16 groundheight = map.findGroundLevel(nodepos2d);
4896 if (groundheight <= water_level) // Don't go underwater
4898 if (groundheight > water_level + 6) // Don't go to high places
4901 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4902 bool is_good = false;
4904 for (s32 i = 0; i < 10; i++) {
4905 v3s16 blockpos = getNodeBlockPos(nodepos);
4906 map.emergeBlock(blockpos, true);
4907 content_t c = map.getNodeNoEx(nodepos).getContent();
4908 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4910 if (air_count >= 2){
4918 // Found a good place
4919 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4925 return intToFloat(nodepos, BS);
4928 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4930 RemotePlayer *player = NULL;
4931 bool newplayer = false;
4934 Try to get an existing player
4936 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4938 // If player is already connected, cancel
4939 if(player != NULL && player->peer_id != 0)
4941 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4946 If player with the wanted peer_id already exists, cancel.
4948 if(m_env->getPlayer(peer_id) != NULL)
4950 infostream<<"emergePlayer(): Player with wrong name but same"
4951 " peer_id already exists"<<std::endl;
4956 Create a new player if it doesn't exist yet
4961 player = new RemotePlayer(this);
4962 player->updateName(name);
4964 /* Set player position */
4965 infostream<<"Server: Finding spawn place for player \""
4966 <<name<<"\""<<std::endl;
4967 v3f pos = findSpawnPos(m_env->getServerMap());
4968 player->setPosition(pos);
4970 /* Add player to environment */
4971 m_env->addPlayer(player);
4975 Create a new player active object
4977 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4978 getPlayerEffectivePrivs(player->getName()),
4981 /* Clean up old HUD elements from previous sessions */
4982 player->hud.clear();
4984 /* Add object to environment */
4985 m_env->addActiveObject(playersao);
4989 m_script->on_newplayer(playersao);
4994 void dedicated_server_loop(Server &server, bool &kill)
4996 DSTACK(__FUNCTION_NAME);
4998 verbosestream<<"dedicated_server_loop()"<<std::endl;
5000 IntervalLimiter m_profiler_interval;
5004 float steplen = g_settings->getFloat("dedicated_server_step");
5005 // This is kind of a hack but can be done like this
5006 // because server.step() is very light
5008 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5009 sleep_ms((int)(steplen*1000.0));
5011 server.step(steplen);
5013 if(server.getShutdownRequested() || kill)
5015 infostream<<"Dedicated server quitting"<<std::endl;
5017 if(g_settings->getBool("server_announce") == true)
5018 ServerList::sendAnnounce("delete");
5026 float profiler_print_interval =
5027 g_settings->getFloat("profiler_print_interval");
5028 if(profiler_print_interval != 0)
5030 if(m_profiler_interval.step(steplen, profiler_print_interval))
5032 infostream<<"Profiler:"<<std::endl;
5033 g_profiler->print(infostream);
5034 g_profiler->clear();