3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_rollback_sink_enabled(true),
185 m_enable_rollback_recording(false),
188 m_itemdef(createItemDefManager()),
189 m_nodedef(createNodeDefManager()),
190 m_craftdef(createCraftDefManager()),
191 m_event(new EventManager()),
193 m_time_of_day_send_timer(0),
196 m_shutdown_requested(false),
197 m_ignore_map_edit_events(false),
198 m_ignore_map_edit_events_peer_id(0)
201 m_liquid_transform_timer = 0.0;
202 m_liquid_transform_every = 1.0;
203 m_print_info_timer = 0.0;
204 m_masterserver_timer = 0.0;
205 m_objectdata_timer = 0.0;
206 m_emergethread_trigger_timer = 0.0;
207 m_savemap_timer = 0.0;
210 m_lag = g_settings->getFloat("dedicated_server_step");
213 throw ServerError("Supplied empty world path");
215 if(!gamespec.isValid())
216 throw ServerError("Supplied invalid gamespec");
218 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
219 if(m_simple_singleplayer_mode)
220 infostream<<" in simple singleplayer mode"<<std::endl;
222 infostream<<std::endl;
223 infostream<<"- world: "<<m_path_world<<std::endl;
224 infostream<<"- game: "<<m_gamespec.path<<std::endl;
226 // Initialize default settings and override defaults with those provided
228 set_default_settings(g_settings);
229 Settings gamedefaults;
230 getGameMinetestConfig(gamespec.path, gamedefaults);
231 override_default_settings(g_settings, &gamedefaults);
233 // Create server thread
234 m_thread = new ServerThread(this);
236 // Create emerge manager
237 m_emerge = new EmergeManager(this);
239 // Create world if it doesn't exist
240 if(!initializeWorld(m_path_world, m_gamespec.id))
241 throw ServerError("Failed to initialize world");
243 // Create ban manager
244 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
245 m_banmanager = new BanManager(ban_path);
247 // Create rollback manager
248 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
249 m_rollback = createRollbackManager(rollback_path, this);
251 ModConfiguration modconf(m_path_world);
252 m_mods = modconf.getMods();
253 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
254 // complain about mods with unsatisfied dependencies
255 if(!modconf.isConsistent())
257 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
258 it != unsatisfied_mods.end(); ++it)
261 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
262 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
263 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
264 errorstream << " \"" << *dep_it << "\"";
265 errorstream << std::endl;
269 Settings worldmt_settings;
270 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
271 worldmt_settings.readConfigFile(worldmt.c_str());
272 std::vector<std::string> names = worldmt_settings.getNames();
273 std::set<std::string> load_mod_names;
274 for(std::vector<std::string>::iterator it = names.begin();
275 it != names.end(); ++it)
277 std::string name = *it;
278 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
279 load_mod_names.insert(name.substr(9));
281 // complain about mods declared to be loaded, but not found
282 for(std::vector<ModSpec>::iterator it = m_mods.begin();
283 it != m_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
286 it != unsatisfied_mods.end(); ++it)
287 load_mod_names.erase((*it).name);
288 if(!load_mod_names.empty())
290 errorstream << "The following mods could not be found:";
291 for(std::set<std::string>::iterator it = load_mod_names.begin();
292 it != load_mod_names.end(); ++it)
293 errorstream << " \"" << (*it) << "\"";
294 errorstream << std::endl;
298 JMutexAutoLock envlock(m_env_mutex);
300 // Initialize scripting
301 infostream<<"Server: Initializing Lua"<<std::endl;
303 m_script = new GameScripting(this);
305 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
307 if (!m_script->loadScript(scriptpath)) {
308 throw ModError("Failed to load and run " + scriptpath);
313 infostream<<"Server: Loading mods: ";
314 for(std::vector<ModSpec>::iterator i = m_mods.begin();
315 i != m_mods.end(); i++){
316 const ModSpec &mod = *i;
317 infostream<<mod.name<<" ";
319 infostream<<std::endl;
320 // Load and run "mod" scripts
321 for(std::vector<ModSpec>::iterator i = m_mods.begin();
322 i != m_mods.end(); i++){
323 const ModSpec &mod = *i;
324 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
325 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
326 <<scriptpath<<"\"]"<<std::endl;
327 bool success = m_script->loadMod(scriptpath, mod.name);
329 errorstream<<"Server: Failed to load and run "
330 <<scriptpath<<std::endl;
331 throw ModError("Failed to load and run "+scriptpath);
335 // Read Textures and calculate sha1 sums
338 // Apply item aliases in the node definition manager
339 m_nodedef->updateAliases(m_itemdef);
341 // Load the mapgen params from global settings now after any
342 // initial overrides have been set by the mods
343 m_emerge->loadMapgenParams();
345 // Initialize Environment
346 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
347 m_env = new ServerEnvironment(servermap, m_script, this);
349 m_clients.setEnv(m_env);
351 // Run some callbacks after the MG params have been set up but before activation
352 m_script->environment_OnMapgenInit(&m_emerge->params);
354 // Initialize mapgens
355 m_emerge->initMapgens();
357 // Give environment reference to scripting api
358 m_script->initializeEnvironment(m_env);
360 // Register us to receive map edit events
361 servermap->addEventReceiver(this);
363 // If file exists, load environment metadata
364 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
366 infostream<<"Server: Loading environment metadata"<<std::endl;
367 m_env->loadMeta(m_path_world);
371 infostream<<"Server: Loading players"<<std::endl;
372 m_env->deSerializePlayers(m_path_world);
375 Add some test ActiveBlockModifiers to environment
377 add_legacy_abms(m_env, m_nodedef);
379 m_liquid_transform_every = g_settings->getFloat("liquid_update");
384 infostream<<"Server destructing"<<std::endl;
387 Send shutdown message
390 std::wstring line = L"*** Server shutting down";
391 SendChatMessage(PEER_ID_INEXISTENT, line);
395 JMutexAutoLock envlock(m_env_mutex);
398 Execute script shutdown hooks
400 m_script->on_shutdown();
404 JMutexAutoLock envlock(m_env_mutex);
409 infostream<<"Server: Saving players"<<std::endl;
410 m_env->serializePlayers(m_path_world);
413 Save environment metadata
415 infostream<<"Server: Saving environment metadata"<<std::endl;
416 m_env->saveMeta(m_path_world);
425 // stop all emerge threads before deleting players that may have
426 // requested blocks to be emerged
427 m_emerge->stopThreads();
429 // Delete things in the reverse order of creation
432 // N.B. the EmergeManager should be deleted after the Environment since Map
433 // depends on EmergeManager to write its current params to the map meta
442 // Deinitialize scripting
443 infostream<<"Server: Deinitializing scripting"<<std::endl;
446 // Delete detached inventories
448 for(std::map<std::string, Inventory*>::iterator
449 i = m_detached_inventories.begin();
450 i != m_detached_inventories.end(); i++){
456 void Server::start(Address bind_addr)
458 DSTACK(__FUNCTION_NAME);
459 infostream<<"Starting server on "
460 << bind_addr.serializeString() <<"..."<<std::endl;
462 // Stop thread if already running
465 // Initialize connection
466 m_con.SetTimeoutMs(30);
467 m_con.Serve(bind_addr);
472 // ASCII art for the win!
474 <<" .__ __ __ "<<std::endl
475 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
476 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
477 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
478 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
479 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
480 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
481 actionstream<<"Server for gameid=\""<<m_gamespec.id
482 <<"\" listening on "<<bind_addr.serializeString()<<":"
483 <<bind_addr.getPort() << "."<<std::endl;
488 DSTACK(__FUNCTION_NAME);
490 infostream<<"Server: Stopping and waiting threads"<<std::endl;
492 // Stop threads (set run=false first so both start stopping)
494 //m_emergethread.setRun(false);
496 //m_emergethread.stop();
498 infostream<<"Server: Threads stopped"<<std::endl;
501 void Server::step(float dtime)
503 DSTACK(__FUNCTION_NAME);
508 JMutexAutoLock lock(m_step_dtime_mutex);
509 m_step_dtime += dtime;
511 // Throw if fatal error occurred in thread
512 std::string async_err = m_async_fatal_error.get();
514 throw ServerError(async_err);
518 void Server::AsyncRunStep(bool initial_step)
520 DSTACK(__FUNCTION_NAME);
522 g_profiler->add("Server::AsyncRunStep (num)", 1);
526 JMutexAutoLock lock1(m_step_dtime_mutex);
527 dtime = m_step_dtime;
531 // Send blocks to clients
535 if((dtime < 0.001) && (initial_step == false))
538 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
540 //infostream<<"Server steps "<<dtime<<std::endl;
541 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
544 JMutexAutoLock lock1(m_step_dtime_mutex);
545 m_step_dtime -= dtime;
552 m_uptime.set(m_uptime.get() + dtime);
558 Update time of day and overall game time
561 JMutexAutoLock envlock(m_env_mutex);
563 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
566 Send to clients at constant intervals
569 m_time_of_day_send_timer -= dtime;
570 if(m_time_of_day_send_timer < 0.0)
572 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
573 u16 time = m_env->getTimeOfDay();
574 float time_speed = g_settings->getFloat("time_speed");
575 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
580 JMutexAutoLock lock(m_env_mutex);
581 // Figure out and report maximum lag to environment
582 float max_lag = m_env->getMaxLagEstimate();
583 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
585 if(dtime > 0.1 && dtime > max_lag * 2.0)
586 infostream<<"Server: Maximum lag peaked to "<<dtime
590 m_env->reportMaxLagEstimate(max_lag);
592 ScopeProfiler sp(g_profiler, "SEnv step");
593 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
597 const float map_timer_and_unload_dtime = 2.92;
598 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
600 JMutexAutoLock lock(m_env_mutex);
601 // Run Map's timers and unload unused data
602 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
603 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
604 g_settings->getFloat("server_unload_unused_data_timeout"));
615 JMutexAutoLock lock(m_env_mutex);
617 std::list<u16> clientids = m_clients.getClientIDs();
619 ScopeProfiler sp(g_profiler, "Server: handle players");
621 for(std::list<u16>::iterator
622 i = clientids.begin();
623 i != clientids.end(); ++i)
625 PlayerSAO *playersao = getPlayerSAO(*i);
626 if(playersao == NULL)
630 Handle player HPs (die if hp=0)
632 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
634 if(playersao->getHP() == 0)
641 Send player breath if changed
643 if(playersao->m_breath_not_sent) {
644 SendPlayerBreath(*i);
648 Send player inventories if necessary
650 if(playersao->m_moved){
652 playersao->m_moved = false;
654 if(playersao->m_inventory_not_sent){
661 /* Transform liquids */
662 m_liquid_transform_timer += dtime;
663 if(m_liquid_transform_timer >= m_liquid_transform_every)
665 m_liquid_transform_timer -= m_liquid_transform_every;
667 JMutexAutoLock lock(m_env_mutex);
669 ScopeProfiler sp(g_profiler, "Server: liquid transform");
671 std::map<v3s16, MapBlock*> modified_blocks;
672 m_env->getMap().transformLiquids(modified_blocks);
677 core::map<v3s16, MapBlock*> lighting_modified_blocks;
678 ServerMap &map = ((ServerMap&)m_env->getMap());
679 map.updateLighting(modified_blocks, lighting_modified_blocks);
681 // Add blocks modified by lighting to modified_blocks
682 for(core::map<v3s16, MapBlock*>::Iterator
683 i = lighting_modified_blocks.getIterator();
684 i.atEnd() == false; i++)
686 MapBlock *block = i.getNode()->getValue();
687 modified_blocks.insert(block->getPos(), block);
691 Set the modified blocks unsent for all the clients
693 if(modified_blocks.size() > 0)
695 SetBlocksNotSent(modified_blocks);
698 m_clients.step(dtime);
700 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
702 // send masterserver announce
704 float &counter = m_masterserver_timer;
705 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
706 g_settings->getBool("server_announce") == true)
708 ServerList::sendAnnounce(!counter ? "start" : "update",
709 m_clients.getPlayerNames(),
711 m_env->getGameTime(),
722 Check added and deleted active objects
725 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
726 JMutexAutoLock envlock(m_env_mutex);
729 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
730 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
732 // Radius inside which objects are active
733 s16 radius = g_settings->getS16("active_object_send_range_blocks");
734 radius *= MAP_BLOCKSIZE;
736 for(std::map<u16, RemoteClient*>::iterator
738 i != clients.end(); ++i)
740 RemoteClient *client = i->second;
742 // If definitions and textures have not been sent, don't
743 // send objects either
744 if (client->getState() < DefinitionsSent)
747 Player *player = m_env->getPlayer(client->peer_id);
750 // This can happen if the client timeouts somehow
751 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
753 <<" has no associated player"<<std::endl;*/
756 v3s16 pos = floatToInt(player->getPosition(), BS);
758 std::set<u16> removed_objects;
759 std::set<u16> added_objects;
760 m_env->getRemovedActiveObjects(pos, radius,
761 client->m_known_objects, removed_objects);
762 m_env->getAddedActiveObjects(pos, radius,
763 client->m_known_objects, added_objects);
765 // Ignore if nothing happened
766 if(removed_objects.size() == 0 && added_objects.size() == 0)
768 //infostream<<"active objects: none changed"<<std::endl;
772 std::string data_buffer;
776 // Handle removed objects
777 writeU16((u8*)buf, removed_objects.size());
778 data_buffer.append(buf, 2);
779 for(std::set<u16>::iterator
780 i = removed_objects.begin();
781 i != removed_objects.end(); ++i)
785 ServerActiveObject* obj = m_env->getActiveObject(id);
787 // Add to data buffer for sending
788 writeU16((u8*)buf, id);
789 data_buffer.append(buf, 2);
791 // Remove from known objects
792 client->m_known_objects.erase(id);
794 if(obj && obj->m_known_by_count > 0)
795 obj->m_known_by_count--;
798 // Handle added objects
799 writeU16((u8*)buf, added_objects.size());
800 data_buffer.append(buf, 2);
801 for(std::set<u16>::iterator
802 i = added_objects.begin();
803 i != added_objects.end(); ++i)
807 ServerActiveObject* obj = m_env->getActiveObject(id);
810 u8 type = ACTIVEOBJECT_TYPE_INVALID;
812 infostream<<"WARNING: "<<__FUNCTION_NAME
813 <<": NULL object"<<std::endl;
815 type = obj->getSendType();
817 // Add to data buffer for sending
818 writeU16((u8*)buf, id);
819 data_buffer.append(buf, 2);
820 writeU8((u8*)buf, type);
821 data_buffer.append(buf, 1);
824 data_buffer.append(serializeLongString(
825 obj->getClientInitializationData(client->net_proto_version)));
827 data_buffer.append(serializeLongString(""));
829 // Add to known objects
830 client->m_known_objects.insert(id);
833 obj->m_known_by_count++;
837 SharedBuffer<u8> reply(2 + data_buffer.size());
838 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
839 memcpy((char*)&reply[2], data_buffer.c_str(),
842 m_clients.send(client->peer_id, 0, reply, true);
844 verbosestream<<"Server: Sent object remove/add: "
845 <<removed_objects.size()<<" removed, "
846 <<added_objects.size()<<" added, "
847 <<"packet size is "<<reply.getSize()<<std::endl;
852 Collect a list of all the objects known by the clients
853 and report it back to the environment.
856 core::map<u16, bool> all_known_objects;
858 for(core::map<u16, RemoteClient*>::Iterator
859 i = m_clients.getIterator();
860 i.atEnd() == false; i++)
862 RemoteClient *client = i.getNode()->getValue();
863 // Go through all known objects of client
864 for(core::map<u16, bool>::Iterator
865 i = client->m_known_objects.getIterator();
866 i.atEnd()==false; i++)
868 u16 id = i.getNode()->getKey();
869 all_known_objects[id] = true;
873 m_env->setKnownActiveObjects(whatever);
882 JMutexAutoLock envlock(m_env_mutex);
883 ScopeProfiler sp(g_profiler, "Server: sending object messages");
886 // Value = data sent by object
887 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
889 // Get active object messages from environment
892 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
896 std::list<ActiveObjectMessage>* message_list = NULL;
897 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
898 n = buffered_messages.find(aom.id);
899 if(n == buffered_messages.end())
901 message_list = new std::list<ActiveObjectMessage>;
902 buffered_messages[aom.id] = message_list;
906 message_list = n->second;
908 message_list->push_back(aom);
912 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
913 // Route data to every client
914 for(std::map<u16, RemoteClient*>::iterator
916 i != clients.end(); ++i)
918 RemoteClient *client = i->second;
919 std::string reliable_data;
920 std::string unreliable_data;
921 // Go through all objects in message buffer
922 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
923 j = buffered_messages.begin();
924 j != buffered_messages.end(); ++j)
926 // If object is not known by client, skip it
928 if(client->m_known_objects.find(id) == client->m_known_objects.end())
930 // Get message list of object
931 std::list<ActiveObjectMessage>* list = j->second;
932 // Go through every message
933 for(std::list<ActiveObjectMessage>::iterator
934 k = list->begin(); k != list->end(); ++k)
936 // Compose the full new data with header
937 ActiveObjectMessage aom = *k;
938 std::string new_data;
941 writeU16((u8*)&buf[0], aom.id);
942 new_data.append(buf, 2);
944 new_data += serializeString(aom.datastring);
945 // Add data to buffer
947 reliable_data += new_data;
949 unreliable_data += new_data;
953 reliable_data and unreliable_data are now ready.
956 if(reliable_data.size() > 0)
958 SharedBuffer<u8> reply(2 + reliable_data.size());
959 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
960 memcpy((char*)&reply[2], reliable_data.c_str(),
961 reliable_data.size());
963 m_clients.send(client->peer_id, 0, reply, true);
965 if(unreliable_data.size() > 0)
967 SharedBuffer<u8> reply(2 + unreliable_data.size());
968 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
969 memcpy((char*)&reply[2], unreliable_data.c_str(),
970 unreliable_data.size());
971 // Send as unreliable
972 m_clients.send(client->peer_id, 1, reply, false);
975 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
977 infostream<<"Server: Size of object message data: "
978 <<"reliable: "<<reliable_data.size()
979 <<", unreliable: "<<unreliable_data.size()
985 // Clear buffered_messages
986 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
987 i = buffered_messages.begin();
988 i != buffered_messages.end(); ++i)
995 Send queued-for-sending map edit events.
998 // We will be accessing the environment
999 JMutexAutoLock lock(m_env_mutex);
1001 // Don't send too many at a time
1004 // Single change sending is disabled if queue size is not small
1005 bool disable_single_change_sending = false;
1006 if(m_unsent_map_edit_queue.size() >= 4)
1007 disable_single_change_sending = true;
1009 int event_count = m_unsent_map_edit_queue.size();
1011 // We'll log the amount of each
1014 while(m_unsent_map_edit_queue.size() != 0)
1016 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1018 // Players far away from the change are stored here.
1019 // Instead of sending the changes, MapBlocks are set not sent
1021 std::list<u16> far_players;
1023 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1025 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1026 prof.add("MEET_ADDNODE", 1);
1027 if(disable_single_change_sending)
1028 sendAddNode(event->p, event->n, event->already_known_by_peer,
1029 &far_players, 5, event->type == MEET_ADDNODE);
1031 sendAddNode(event->p, event->n, event->already_known_by_peer,
1032 &far_players, 30, event->type == MEET_ADDNODE);
1034 else if(event->type == MEET_REMOVENODE)
1036 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1037 prof.add("MEET_REMOVENODE", 1);
1038 if(disable_single_change_sending)
1039 sendRemoveNode(event->p, event->already_known_by_peer,
1042 sendRemoveNode(event->p, event->already_known_by_peer,
1045 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1047 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1048 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1049 setBlockNotSent(event->p);
1051 else if(event->type == MEET_OTHER)
1053 infostream<<"Server: MEET_OTHER"<<std::endl;
1054 prof.add("MEET_OTHER", 1);
1055 for(std::set<v3s16>::iterator
1056 i = event->modified_blocks.begin();
1057 i != event->modified_blocks.end(); ++i)
1059 setBlockNotSent(*i);
1064 prof.add("unknown", 1);
1065 infostream<<"WARNING: Server: Unknown MapEditEvent "
1066 <<((u32)event->type)<<std::endl;
1070 Set blocks not sent to far players
1072 if(far_players.size() > 0)
1074 // Convert list format to that wanted by SetBlocksNotSent
1075 std::map<v3s16, MapBlock*> modified_blocks2;
1076 for(std::set<v3s16>::iterator
1077 i = event->modified_blocks.begin();
1078 i != event->modified_blocks.end(); ++i)
1080 modified_blocks2[*i] =
1081 m_env->getMap().getBlockNoCreateNoEx(*i);
1083 // Set blocks not sent
1084 for(std::list<u16>::iterator
1085 i = far_players.begin();
1086 i != far_players.end(); ++i)
1089 RemoteClient *client = getClient(peer_id);
1092 client->SetBlocksNotSent(modified_blocks2);
1098 /*// Don't send too many at a time
1100 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1104 if(event_count >= 5){
1105 infostream<<"Server: MapEditEvents:"<<std::endl;
1106 prof.print(infostream);
1107 } else if(event_count != 0){
1108 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1109 prof.print(verbosestream);
1115 Trigger emergethread (it somehow gets to a non-triggered but
1116 bysy state sometimes)
1119 float &counter = m_emergethread_trigger_timer;
1125 m_emerge->startThreads();
1127 // Update m_enable_rollback_recording here too
1128 m_enable_rollback_recording =
1129 g_settings->getBool("enable_rollback_recording");
1133 // Save map, players and auth stuff
1135 float &counter = m_savemap_timer;
1137 if(counter >= g_settings->getFloat("server_map_save_interval"))
1140 JMutexAutoLock lock(m_env_mutex);
1142 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1145 if(m_banmanager->isModified())
1146 m_banmanager->save();
1148 // Save changed parts of map
1149 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1152 m_env->serializePlayers(m_path_world);
1154 // Save environment metadata
1155 m_env->saveMeta(m_path_world);
1160 void Server::Receive()
1162 DSTACK(__FUNCTION_NAME);
1163 SharedBuffer<u8> data;
1167 datasize = m_con.Receive(peer_id,data);
1168 ProcessData(*data, datasize, peer_id);
1170 catch(con::InvalidIncomingDataException &e)
1172 infostream<<"Server::Receive(): "
1173 "InvalidIncomingDataException: what()="
1174 <<e.what()<<std::endl;
1176 catch(con::PeerNotFoundException &e)
1178 //NOTE: This is not needed anymore
1180 // The peer has been disconnected.
1181 // Find the associated player and remove it.
1183 /*JMutexAutoLock envlock(m_env_mutex);
1185 infostream<<"ServerThread: peer_id="<<peer_id
1186 <<" has apparently closed connection. "
1187 <<"Removing player."<<std::endl;
1189 m_env->removePlayer(peer_id);*/
1191 catch(ClientStateError &e)
1193 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1194 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1195 L"Try reconnecting or updating your client");
1199 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1201 std::string playername = "";
1202 PlayerSAO *playersao = NULL;
1204 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
1205 if (client != NULL) {
1206 playername = client->getName();
1207 playersao = emergePlayer(playername.c_str(), peer_id);
1211 RemotePlayer *player =
1212 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1214 // If failed, cancel
1215 if((playersao == NULL) || (player == NULL))
1217 if(player && player->peer_id != 0){
1218 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1219 <<" (player allocated to an another client)"<<std::endl;
1220 DenyAccess(peer_id, L"Another client is connected with this "
1221 L"name. If your client closed unexpectedly, try again in "
1224 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1226 DenyAccess(peer_id, L"Could not allocate player.");
1232 Send complete position information
1234 SendMovePlayer(peer_id);
1237 SendPlayerPrivileges(peer_id);
1239 // Send inventory formspec
1240 SendPlayerInventoryFormspec(peer_id);
1243 UpdateCrafting(peer_id);
1244 SendInventory(peer_id);
1247 if(g_settings->getBool("enable_damage"))
1248 SendPlayerHP(peer_id);
1251 SendPlayerBreath(peer_id);
1253 // Show death screen if necessary
1255 SendDeathscreen(peer_id, false, v3f(0,0,0));
1257 // Note things in chat if not in simple singleplayer mode
1258 if(!m_simple_singleplayer_mode)
1260 // Send information about server to player in chat
1261 SendChatMessage(peer_id, getStatusString());
1263 // Send information about joining in chat
1265 std::wstring name = L"unknown";
1266 Player *player = m_env->getPlayer(peer_id);
1268 name = narrow_to_wide(player->getName());
1270 std::wstring message;
1273 message += L" joined the game.";
1274 SendChatMessage(PEER_ID_INEXISTENT,message);
1277 Address addr = getPeerAddress(player->peer_id);
1278 std::string ip_str = addr.serializeString();
1279 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1284 std::vector<std::string> names = m_clients.getPlayerNames();
1286 actionstream<<player->getName() <<" joins game. List of players: ";
1288 for (std::vector<std::string>::iterator i = names.begin();
1289 i != names.end(); i++)
1291 actionstream << *i << " ";
1294 actionstream<<std::endl;
1299 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1301 DSTACK(__FUNCTION_NAME);
1302 // Environment is locked first.
1303 JMutexAutoLock envlock(m_env_mutex);
1305 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1309 Address address = getPeerAddress(peer_id);
1310 addr_s = address.serializeString();
1312 // drop player if is ip is banned
1313 if(m_banmanager->isIpBanned(addr_s)){
1314 std::string ban_name = m_banmanager->getBanName(addr_s);
1315 infostream<<"Server: A banned client tried to connect from "
1316 <<addr_s<<"; banned name was "
1317 <<ban_name<<std::endl;
1318 // This actually doesn't seem to transfer to the client
1319 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1320 +narrow_to_wide(ban_name));
1324 catch(con::PeerNotFoundException &e)
1327 * no peer for this packet found
1328 * most common reason is peer timeout, e.g. peer didn't
1329 * respond for some time, your server was overloaded or
1332 infostream<<"Server::ProcessData(): Cancelling: peer "
1333 <<peer_id<<" not found"<<std::endl;
1343 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1345 if(command == TOSERVER_INIT)
1347 // [0] u16 TOSERVER_INIT
1348 // [2] u8 SER_FMT_VER_HIGHEST_READ
1349 // [3] u8[20] player_name
1350 // [23] u8[28] password <--- can be sent without this, from old versions
1352 if(datasize < 2+1+PLAYERNAME_SIZE)
1355 RemoteClient* client = getClient(peer_id,Created);
1357 // If net_proto_version is set, this client has already been handled
1358 if(client->getState() > Created)
1360 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1361 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1365 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1366 <<peer_id<<")"<<std::endl;
1368 // Do not allow multiple players in simple singleplayer mode.
1369 // This isn't a perfect way to do it, but will suffice for now
1370 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1371 infostream<<"Server: Not allowing another client ("<<addr_s
1372 <<") to connect in simple singleplayer mode"<<std::endl;
1373 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1377 // First byte after command is maximum supported
1378 // serialization version
1379 u8 client_max = data[2];
1380 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1381 // Use the highest version supported by both
1382 u8 deployed = std::min(client_max, our_max);
1383 // If it's lower than the lowest supported, give up.
1384 if(deployed < SER_FMT_VER_LOWEST)
1385 deployed = SER_FMT_VER_INVALID;
1387 if(deployed == SER_FMT_VER_INVALID)
1389 actionstream<<"Server: A mismatched client tried to connect from "
1390 <<addr_s<<std::endl;
1391 infostream<<"Server: Cannot negotiate serialization version with "
1392 <<addr_s<<std::endl;
1393 DenyAccess(peer_id, std::wstring(
1394 L"Your client's version is not supported.\n"
1395 L"Server version is ")
1396 + narrow_to_wide(minetest_version_simple) + L"."
1401 client->setPendingSerializationVersion(deployed);
1404 Read and check network protocol version
1407 u16 min_net_proto_version = 0;
1408 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1409 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1411 // Use same version as minimum and maximum if maximum version field
1412 // doesn't exist (backwards compatibility)
1413 u16 max_net_proto_version = min_net_proto_version;
1414 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1415 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1417 // Start with client's maximum version
1418 u16 net_proto_version = max_net_proto_version;
1420 // Figure out a working version if it is possible at all
1421 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1422 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1424 // If maximum is larger than our maximum, go with our maximum
1425 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1426 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1427 // Else go with client's maximum
1429 net_proto_version = max_net_proto_version;
1432 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1433 <<min_net_proto_version<<", max: "<<max_net_proto_version
1434 <<", chosen: "<<net_proto_version<<std::endl;
1436 client->net_proto_version = net_proto_version;
1438 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1439 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1441 actionstream<<"Server: A mismatched client tried to connect from "
1442 <<addr_s<<std::endl;
1443 DenyAccess(peer_id, std::wstring(
1444 L"Your client's version is not supported.\n"
1445 L"Server version is ")
1446 + narrow_to_wide(minetest_version_simple) + L",\n"
1447 + L"server's PROTOCOL_VERSION is "
1448 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1450 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1451 + L", client's PROTOCOL_VERSION is "
1452 + narrow_to_wide(itos(min_net_proto_version))
1454 + narrow_to_wide(itos(max_net_proto_version))
1459 if(g_settings->getBool("strict_protocol_version_checking"))
1461 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1463 actionstream<<"Server: A mismatched (strict) client tried to "
1464 <<"connect from "<<addr_s<<std::endl;
1465 DenyAccess(peer_id, std::wstring(
1466 L"Your client's version is not supported.\n"
1467 L"Server version is ")
1468 + narrow_to_wide(minetest_version_simple) + L",\n"
1469 + L"server's PROTOCOL_VERSION (strict) is "
1470 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1471 + L", client's PROTOCOL_VERSION is "
1472 + narrow_to_wide(itos(min_net_proto_version))
1474 + narrow_to_wide(itos(max_net_proto_version))
1485 char playername[PLAYERNAME_SIZE];
1486 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1488 playername[i] = data[3+i];
1490 playername[PLAYERNAME_SIZE-1] = 0;
1492 if(playername[0]=='\0')
1494 actionstream<<"Server: Player with an empty name "
1495 <<"tried to connect from "<<addr_s<<std::endl;
1496 DenyAccess(peer_id, L"Empty name");
1500 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1502 actionstream<<"Server: Player with an invalid name "
1503 <<"tried to connect from "<<addr_s<<std::endl;
1504 DenyAccess(peer_id, L"Name contains unallowed characters");
1508 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1510 actionstream<<"Server: Player with the name \"singleplayer\" "
1511 <<"tried to connect from "<<addr_s<<std::endl;
1512 DenyAccess(peer_id, L"Name is not allowed");
1518 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1520 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1521 <<"tried to connect from "<<addr_s<<" "
1522 <<"but it was disallowed for the following reason: "
1523 <<reason<<std::endl;
1524 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1529 infostream<<"Server: New connection: \""<<playername<<"\" from "
1530 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1533 char given_password[PASSWORD_SIZE];
1534 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1536 // old version - assume blank password
1537 given_password[0] = 0;
1541 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1543 given_password[i] = data[23+i];
1545 given_password[PASSWORD_SIZE-1] = 0;
1548 if(!base64_is_valid(given_password)){
1549 actionstream<<"Server: "<<playername
1550 <<" supplied invalid password hash"<<std::endl;
1551 DenyAccess(peer_id, L"Invalid password hash");
1555 // Enforce user limit.
1556 // Don't enforce for users that have some admin right
1557 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1558 !checkPriv(playername, "server") &&
1559 !checkPriv(playername, "ban") &&
1560 !checkPriv(playername, "privs") &&
1561 !checkPriv(playername, "password") &&
1562 playername != g_settings->get("name"))
1564 actionstream<<"Server: "<<playername<<" tried to join, but there"
1565 <<" are already max_users="
1566 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1567 DenyAccess(peer_id, L"Too many users.");
1571 std::string checkpwd; // Password hash to check against
1572 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1574 // If no authentication info exists for user, create it
1576 if(!isSingleplayer() &&
1577 g_settings->getBool("disallow_empty_password") &&
1578 std::string(given_password) == ""){
1579 actionstream<<"Server: "<<playername
1580 <<" supplied empty password"<<std::endl;
1581 DenyAccess(peer_id, L"Empty passwords are "
1582 L"disallowed. Set a password and try again.");
1585 std::wstring raw_default_password =
1586 narrow_to_wide(g_settings->get("default_password"));
1587 std::string initial_password =
1588 translatePassword(playername, raw_default_password);
1590 // If default_password is empty, allow any initial password
1591 if (raw_default_password.length() == 0)
1592 initial_password = given_password;
1594 m_script->createAuth(playername, initial_password);
1597 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1600 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1601 <<" (auth handler does not work?)"<<std::endl;
1602 DenyAccess(peer_id, L"Not allowed to login");
1606 if(given_password != checkpwd){
1607 actionstream<<"Server: "<<playername<<" supplied wrong password"
1609 DenyAccess(peer_id, L"Wrong password");
1613 RemotePlayer *player =
1614 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1616 if(player && player->peer_id != 0){
1617 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1618 <<" (player allocated to an another client)"<<std::endl;
1619 DenyAccess(peer_id, L"Another client is connected with this "
1620 L"name. If your client closed unexpectedly, try again in "
1624 m_clients.setPlayerName(peer_id,playername);
1627 Answer with a TOCLIENT_INIT
1630 SharedBuffer<u8> reply(2+1+6+8+4);
1631 writeU16(&reply[0], TOCLIENT_INIT);
1632 writeU8(&reply[2], deployed);
1633 //send dummy pos for legacy reasons only
1634 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1635 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1636 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1639 m_clients.send(peer_id, 0, reply, true);
1640 m_clients.event(peer_id, Init);
1646 if(command == TOSERVER_INIT2)
1649 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1650 <<peer_id<<std::endl;
1652 m_clients.event(peer_id, GotInit2);
1653 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1656 ///// begin compatibility code
1657 PlayerSAO* playersao = NULL;
1658 if (protocol_version <= 22) {
1659 playersao = StageTwoClientInit(peer_id);
1661 if (playersao == NULL) {
1663 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1664 << peer_id << std::endl;
1668 ///// end compatibility code
1671 Send some initialization data
1674 infostream<<"Server: Sending content to "
1675 <<getPlayerName(peer_id)<<std::endl;
1677 // Send player movement settings
1678 SendMovement(peer_id);
1680 // Send item definitions
1681 SendItemDef(peer_id, m_itemdef, protocol_version);
1683 // Send node definitions
1684 SendNodeDef(peer_id, m_nodedef, protocol_version);
1686 m_clients.event(peer_id, SetDefinitionsSent);
1688 // Send media announcement
1689 sendMediaAnnouncement(peer_id);
1691 // Send detached inventories
1692 sendDetachedInventories(peer_id);
1695 u16 time = m_env->getTimeOfDay();
1696 float time_speed = g_settings->getFloat("time_speed");
1697 SendTimeOfDay(peer_id, time, time_speed);
1699 ///// begin compatibility code
1700 if (protocol_version <= 22) {
1701 m_clients.event(peer_id, SetClientReady);
1702 m_script->on_joinplayer(playersao);
1704 ///// end compatibility code
1706 // Warnings about protocol version can be issued here
1707 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1709 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1710 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1716 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1717 u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1719 if(peer_ser_ver == SER_FMT_VER_INVALID)
1721 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1722 " serialization format invalid or not initialized."
1723 " Skipping incoming command="<<command<<std::endl;
1727 /* Handle commands relate to client startup */
1728 if(command == TOSERVER_REQUEST_MEDIA) {
1729 std::string datastring((char*)&data[2], datasize-2);
1730 std::istringstream is(datastring, std::ios_base::binary);
1732 std::list<std::string> tosend;
1733 u16 numfiles = readU16(is);
1735 infostream<<"Sending "<<numfiles<<" files to "
1736 <<getPlayerName(peer_id)<<std::endl;
1737 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1739 for(int i = 0; i < numfiles; i++) {
1740 std::string name = deSerializeString(is);
1741 tosend.push_back(name);
1742 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1746 sendRequestedMedia(peer_id, tosend);
1749 else if(command == TOSERVER_RECEIVED_MEDIA) {
1752 else if(command == TOSERVER_CLIENT_READY) {
1753 // clients <= protocol version 22 did not send ready message,
1754 // they're already initialized
1755 assert(peer_proto_ver > 22);
1757 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1759 if (playersao == NULL) {
1761 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1762 << peer_id << std::endl;
1770 m_clients.setClientVersion(
1772 data[2], data[3], data[4],
1773 std::string((char*) &data[8],(u16) data[6]));
1775 m_clients.event(peer_id, SetClientReady);
1776 m_script->on_joinplayer(playersao);
1779 else if(command == TOSERVER_GOTBLOCKS)
1792 u16 count = data[2];
1793 for(u16 i=0; i<count; i++)
1795 if((s16)datasize < 2+1+(i+1)*6)
1796 throw con::InvalidIncomingDataException
1797 ("GOTBLOCKS length is too short");
1798 v3s16 p = readV3S16(&data[2+1+i*6]);
1799 /*infostream<<"Server: GOTBLOCKS ("
1800 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1801 RemoteClient *client = getClient(peer_id);
1802 client->GotBlock(p);
1807 if (m_clients.getClientState(peer_id) < Active)
1809 if (command == TOSERVER_PLAYERPOS) return;
1811 errorstream<<"Got packet command: " << command << " for peer id "
1812 << peer_id << " but client isn't active yet. Dropping packet "
1817 Player *player = m_env->getPlayer(peer_id);
1819 errorstream<<"Server::ProcessData(): Cancelling: "
1820 "No player for peer_id="<<peer_id
1825 PlayerSAO *playersao = player->getPlayerSAO();
1826 if(playersao == NULL){
1827 errorstream<<"Server::ProcessData(): Cancelling: "
1828 "No player object for peer_id="<<peer_id
1833 if(command == TOSERVER_PLAYERPOS)
1835 if(datasize < 2+12+12+4+4)
1839 v3s32 ps = readV3S32(&data[start+2]);
1840 v3s32 ss = readV3S32(&data[start+2+12]);
1841 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1842 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1844 if(datasize >= 2+12+12+4+4+4)
1845 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1846 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1847 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1848 pitch = wrapDegrees(pitch);
1849 yaw = wrapDegrees(yaw);
1851 player->setPosition(position);
1852 player->setSpeed(speed);
1853 player->setPitch(pitch);
1854 player->setYaw(yaw);
1855 player->keyPressed=keyPressed;
1856 player->control.up = (bool)(keyPressed&1);
1857 player->control.down = (bool)(keyPressed&2);
1858 player->control.left = (bool)(keyPressed&4);
1859 player->control.right = (bool)(keyPressed&8);
1860 player->control.jump = (bool)(keyPressed&16);
1861 player->control.aux1 = (bool)(keyPressed&32);
1862 player->control.sneak = (bool)(keyPressed&64);
1863 player->control.LMB = (bool)(keyPressed&128);
1864 player->control.RMB = (bool)(keyPressed&256);
1866 bool cheated = playersao->checkMovementCheat();
1869 m_script->on_cheat(playersao, "moved_too_fast");
1872 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1873 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1874 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1876 else if(command == TOSERVER_DELETEDBLOCKS)
1889 u16 count = data[2];
1890 for(u16 i=0; i<count; i++)
1892 if((s16)datasize < 2+1+(i+1)*6)
1893 throw con::InvalidIncomingDataException
1894 ("DELETEDBLOCKS length is too short");
1895 v3s16 p = readV3S16(&data[2+1+i*6]);
1896 /*infostream<<"Server: DELETEDBLOCKS ("
1897 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1898 RemoteClient *client = getClient(peer_id);
1899 client->SetBlockNotSent(p);
1902 else if(command == TOSERVER_CLICK_OBJECT)
1904 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1907 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1909 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1912 else if(command == TOSERVER_GROUND_ACTION)
1914 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1918 else if(command == TOSERVER_RELEASE)
1920 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1923 else if(command == TOSERVER_SIGNTEXT)
1925 infostream<<"Server: SIGNTEXT not supported anymore"
1929 else if(command == TOSERVER_SIGNNODETEXT)
1931 infostream<<"Server: SIGNNODETEXT not supported anymore"
1935 else if(command == TOSERVER_INVENTORY_ACTION)
1937 // Strip command and create a stream
1938 std::string datastring((char*)&data[2], datasize-2);
1939 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1940 std::istringstream is(datastring, std::ios_base::binary);
1942 InventoryAction *a = InventoryAction::deSerialize(is);
1945 infostream<<"TOSERVER_INVENTORY_ACTION: "
1946 <<"InventoryAction::deSerialize() returned NULL"
1951 // If something goes wrong, this player is to blame
1952 RollbackScopeActor rollback_scope(m_rollback,
1953 std::string("player:")+player->getName());
1956 Note: Always set inventory not sent, to repair cases
1957 where the client made a bad prediction.
1961 Handle restrictions and special cases of the move action
1963 if(a->getType() == IACTION_MOVE)
1965 IMoveAction *ma = (IMoveAction*)a;
1967 ma->from_inv.applyCurrentPlayer(player->getName());
1968 ma->to_inv.applyCurrentPlayer(player->getName());
1970 setInventoryModified(ma->from_inv);
1971 setInventoryModified(ma->to_inv);
1973 bool from_inv_is_current_player =
1974 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1975 (ma->from_inv.name == player->getName());
1977 bool to_inv_is_current_player =
1978 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1979 (ma->to_inv.name == player->getName());
1982 Disable moving items out of craftpreview
1984 if(ma->from_list == "craftpreview")
1986 infostream<<"Ignoring IMoveAction from "
1987 <<(ma->from_inv.dump())<<":"<<ma->from_list
1988 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1989 <<" because src is "<<ma->from_list<<std::endl;
1995 Disable moving items into craftresult and craftpreview
1997 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1999 infostream<<"Ignoring IMoveAction from "
2000 <<(ma->from_inv.dump())<<":"<<ma->from_list
2001 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2002 <<" because dst is "<<ma->to_list<<std::endl;
2007 // Disallow moving items in elsewhere than player's inventory
2008 // if not allowed to interact
2009 if(!checkPriv(player->getName(), "interact") &&
2010 (!from_inv_is_current_player ||
2011 !to_inv_is_current_player))
2013 infostream<<"Cannot move outside of player's inventory: "
2014 <<"No interact privilege"<<std::endl;
2020 Handle restrictions and special cases of the drop action
2022 else if(a->getType() == IACTION_DROP)
2024 IDropAction *da = (IDropAction*)a;
2026 da->from_inv.applyCurrentPlayer(player->getName());
2028 setInventoryModified(da->from_inv);
2031 Disable dropping items out of craftpreview
2033 if(da->from_list == "craftpreview")
2035 infostream<<"Ignoring IDropAction from "
2036 <<(da->from_inv.dump())<<":"<<da->from_list
2037 <<" because src is "<<da->from_list<<std::endl;
2042 // Disallow dropping items if not allowed to interact
2043 if(!checkPriv(player->getName(), "interact"))
2050 Handle restrictions and special cases of the craft action
2052 else if(a->getType() == IACTION_CRAFT)
2054 ICraftAction *ca = (ICraftAction*)a;
2056 ca->craft_inv.applyCurrentPlayer(player->getName());
2058 setInventoryModified(ca->craft_inv);
2060 //bool craft_inv_is_current_player =
2061 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2062 // (ca->craft_inv.name == player->getName());
2064 // Disallow crafting if not allowed to interact
2065 if(!checkPriv(player->getName(), "interact"))
2067 infostream<<"Cannot craft: "
2068 <<"No interact privilege"<<std::endl;
2075 a->apply(this, playersao, this);
2079 else if(command == TOSERVER_CHAT_MESSAGE)
2087 std::string datastring((char*)&data[2], datasize-2);
2088 std::istringstream is(datastring, std::ios_base::binary);
2091 is.read((char*)buf, 2);
2092 u16 len = readU16(buf);
2094 std::wstring message;
2095 for(u16 i=0; i<len; i++)
2097 is.read((char*)buf, 2);
2098 message += (wchar_t)readU16(buf);
2101 // If something goes wrong, this player is to blame
2102 RollbackScopeActor rollback_scope(m_rollback,
2103 std::string("player:")+player->getName());
2105 // Get player name of this client
2106 std::wstring name = narrow_to_wide(player->getName());
2109 bool ate = m_script->on_chat_message(player->getName(),
2110 wide_to_narrow(message));
2111 // If script ate the message, don't proceed
2115 // Line to send to players
2117 // Whether to send to the player that sent the line
2118 bool send_to_sender_only = false;
2120 // Commands are implemented in Lua, so only catch invalid
2121 // commands that were not "eaten" and send an error back
2122 if(message[0] == L'/')
2124 message = message.substr(1);
2125 send_to_sender_only = true;
2126 if(message.length() == 0)
2127 line += L"-!- Empty command";
2129 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2133 if(checkPriv(player->getName(), "shout")){
2139 line += L"-!- You don't have permission to shout.";
2140 send_to_sender_only = true;
2147 Send the message to sender
2149 if (send_to_sender_only)
2151 SendChatMessage(peer_id, line);
2154 Send the message to others
2158 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2160 std::list<u16> clients = m_clients.getClientIDs();
2162 for(std::list<u16>::iterator
2163 i = clients.begin();
2164 i != clients.end(); ++i)
2167 SendChatMessage(*i, line);
2172 else if(command == TOSERVER_DAMAGE)
2174 std::string datastring((char*)&data[2], datasize-2);
2175 std::istringstream is(datastring, std::ios_base::binary);
2176 u8 damage = readU8(is);
2178 if(g_settings->getBool("enable_damage"))
2180 actionstream<<player->getName()<<" damaged by "
2181 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2184 playersao->setHP(playersao->getHP() - damage);
2186 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2189 if(playersao->m_hp_not_sent)
2190 SendPlayerHP(peer_id);
2193 else if(command == TOSERVER_BREATH)
2195 std::string datastring((char*)&data[2], datasize-2);
2196 std::istringstream is(datastring, std::ios_base::binary);
2197 u16 breath = readU16(is);
2198 playersao->setBreath(breath);
2199 m_script->player_event(playersao,"breath_changed");
2201 else if(command == TOSERVER_PASSWORD)
2204 [0] u16 TOSERVER_PASSWORD
2205 [2] u8[28] old password
2206 [30] u8[28] new password
2209 if(datasize != 2+PASSWORD_SIZE*2)
2211 /*char password[PASSWORD_SIZE];
2212 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2213 password[i] = data[2+i];
2214 password[PASSWORD_SIZE-1] = 0;*/
2216 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2224 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2226 char c = data[2+PASSWORD_SIZE+i];
2232 if(!base64_is_valid(newpwd)){
2233 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2234 // Wrong old password supplied!!
2235 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2239 infostream<<"Server: Client requests a password change from "
2240 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2242 std::string playername = player->getName();
2244 std::string checkpwd;
2245 m_script->getAuth(playername, &checkpwd, NULL);
2247 if(oldpwd != checkpwd)
2249 infostream<<"Server: invalid old password"<<std::endl;
2250 // Wrong old password supplied!!
2251 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2255 bool success = m_script->setPassword(playername, newpwd);
2257 actionstream<<player->getName()<<" changes password"<<std::endl;
2258 SendChatMessage(peer_id, L"Password change successful.");
2260 actionstream<<player->getName()<<" tries to change password but "
2261 <<"it fails"<<std::endl;
2262 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2265 else if(command == TOSERVER_PLAYERITEM)
2270 u16 item = readU16(&data[2]);
2271 playersao->setWieldIndex(item);
2273 else if(command == TOSERVER_RESPAWN)
2275 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2278 RespawnPlayer(peer_id);
2280 actionstream<<player->getName()<<" respawns at "
2281 <<PP(player->getPosition()/BS)<<std::endl;
2283 // ActiveObject is added to environment in AsyncRunStep after
2284 // the previous addition has been succesfully removed
2286 else if(command == TOSERVER_INTERACT)
2288 std::string datastring((char*)&data[2], datasize-2);
2289 std::istringstream is(datastring, std::ios_base::binary);
2295 [5] u32 length of the next item
2296 [9] serialized PointedThing
2298 0: start digging (from undersurface) or use
2299 1: stop digging (all parameters ignored)
2300 2: digging completed
2301 3: place block or item (to abovesurface)
2304 u8 action = readU8(is);
2305 u16 item_i = readU16(is);
2306 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2307 PointedThing pointed;
2308 pointed.deSerialize(tmp_is);
2310 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2311 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2315 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2316 <<" tried to interact, but is dead!"<<std::endl;
2320 v3f player_pos = playersao->getLastGoodPosition();
2322 // Update wielded item
2323 playersao->setWieldIndex(item_i);
2325 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2326 v3s16 p_under = pointed.node_undersurface;
2327 v3s16 p_above = pointed.node_abovesurface;
2329 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2330 ServerActiveObject *pointed_object = NULL;
2331 if(pointed.type == POINTEDTHING_OBJECT)
2333 pointed_object = m_env->getActiveObject(pointed.object_id);
2334 if(pointed_object == NULL)
2336 verbosestream<<"TOSERVER_INTERACT: "
2337 "pointed object is NULL"<<std::endl;
2343 v3f pointed_pos_under = player_pos;
2344 v3f pointed_pos_above = player_pos;
2345 if(pointed.type == POINTEDTHING_NODE)
2347 pointed_pos_under = intToFloat(p_under, BS);
2348 pointed_pos_above = intToFloat(p_above, BS);
2350 else if(pointed.type == POINTEDTHING_OBJECT)
2352 pointed_pos_under = pointed_object->getBasePosition();
2353 pointed_pos_above = pointed_pos_under;
2357 Check that target is reasonably close
2358 (only when digging or placing things)
2360 if(action == 0 || action == 2 || action == 3)
2362 float d = player_pos.getDistanceFrom(pointed_pos_under);
2363 float max_d = BS * 14; // Just some large enough value
2365 actionstream<<"Player "<<player->getName()
2366 <<" tried to access "<<pointed.dump()
2368 <<"d="<<d<<", max_d="<<max_d
2369 <<". ignoring."<<std::endl;
2370 // Re-send block to revert change on client-side
2371 RemoteClient *client = getClient(peer_id);
2372 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2373 client->SetBlockNotSent(blockpos);
2375 m_script->on_cheat(playersao, "interacted_too_far");
2382 Make sure the player is allowed to do it
2384 if(!checkPriv(player->getName(), "interact"))
2386 actionstream<<player->getName()<<" attempted to interact with "
2387 <<pointed.dump()<<" without 'interact' privilege"
2389 // Re-send block to revert change on client-side
2390 RemoteClient *client = getClient(peer_id);
2391 // Digging completed -> under
2393 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2394 client->SetBlockNotSent(blockpos);
2396 // Placement -> above
2398 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2399 client->SetBlockNotSent(blockpos);
2405 If something goes wrong, this player is to blame
2407 RollbackScopeActor rollback_scope(m_rollback,
2408 std::string("player:")+player->getName());
2411 0: start digging or punch object
2415 if(pointed.type == POINTEDTHING_NODE)
2418 NOTE: This can be used in the future to check if
2419 somebody is cheating, by checking the timing.
2421 MapNode n(CONTENT_IGNORE);
2424 n = m_env->getMap().getNode(p_under);
2426 catch(InvalidPositionException &e)
2428 infostream<<"Server: Not punching: Node not found."
2429 <<" Adding block to emerge queue."
2431 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2433 if(n.getContent() != CONTENT_IGNORE)
2434 m_script->node_on_punch(p_under, n, playersao, pointed);
2436 playersao->noCheatDigStart(p_under);
2438 else if(pointed.type == POINTEDTHING_OBJECT)
2440 // Skip if object has been removed
2441 if(pointed_object->m_removed)
2444 actionstream<<player->getName()<<" punches object "
2445 <<pointed.object_id<<": "
2446 <<pointed_object->getDescription()<<std::endl;
2448 ItemStack punchitem = playersao->getWieldedItem();
2449 ToolCapabilities toolcap =
2450 punchitem.getToolCapabilities(m_itemdef);
2451 v3f dir = (pointed_object->getBasePosition() -
2452 (player->getPosition() + player->getEyeOffset())
2454 float time_from_last_punch =
2455 playersao->resetTimeFromLastPunch();
2456 pointed_object->punch(dir, &toolcap, playersao,
2457 time_from_last_punch);
2465 else if(action == 1)
2470 2: Digging completed
2472 else if(action == 2)
2474 // Only digging of nodes
2475 if(pointed.type == POINTEDTHING_NODE)
2477 MapNode n(CONTENT_IGNORE);
2480 n = m_env->getMap().getNode(p_under);
2482 catch(InvalidPositionException &e)
2484 infostream<<"Server: Not finishing digging: Node not found."
2485 <<" Adding block to emerge queue."
2487 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2490 /* Cheat prevention */
2491 bool is_valid_dig = true;
2492 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2494 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2495 float nocheat_t = playersao->getNoCheatDigTime();
2496 playersao->noCheatDigEnd();
2497 // If player didn't start digging this, ignore dig
2498 if(nocheat_p != p_under){
2499 infostream<<"Server: NoCheat: "<<player->getName()
2500 <<" started digging "
2501 <<PP(nocheat_p)<<" and completed digging "
2502 <<PP(p_under)<<"; not digging."<<std::endl;
2503 is_valid_dig = false;
2505 m_script->on_cheat(playersao, "finished_unknown_dig");
2507 // Get player's wielded item
2508 ItemStack playeritem;
2509 InventoryList *mlist = playersao->getInventory()->getList("main");
2511 playeritem = mlist->getItem(playersao->getWieldIndex());
2512 ToolCapabilities playeritem_toolcap =
2513 playeritem.getToolCapabilities(m_itemdef);
2514 // Get diggability and expected digging time
2515 DigParams params = getDigParams(m_nodedef->get(n).groups,
2516 &playeritem_toolcap);
2517 // If can't dig, try hand
2518 if(!params.diggable){
2519 const ItemDefinition &hand = m_itemdef->get("");
2520 const ToolCapabilities *tp = hand.tool_capabilities;
2522 params = getDigParams(m_nodedef->get(n).groups, tp);
2524 // If can't dig, ignore dig
2525 if(!params.diggable){
2526 infostream<<"Server: NoCheat: "<<player->getName()
2527 <<" completed digging "<<PP(p_under)
2528 <<", which is not diggable with tool. not digging."
2530 is_valid_dig = false;
2532 m_script->on_cheat(playersao, "dug_unbreakable");
2534 // Check digging time
2535 // If already invalidated, we don't have to
2537 // Well not our problem then
2539 // Clean and long dig
2540 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2541 // All is good, but grab time from pool; don't care if
2542 // it's actually available
2543 playersao->getDigPool().grab(params.time);
2545 // Short or laggy dig
2546 // Try getting the time from pool
2547 else if(playersao->getDigPool().grab(params.time)){
2552 infostream<<"Server: NoCheat: "<<player->getName()
2553 <<" completed digging "<<PP(p_under)
2554 <<"too fast; not digging."<<std::endl;
2555 is_valid_dig = false;
2557 m_script->on_cheat(playersao, "dug_too_fast");
2561 /* Actually dig node */
2563 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2564 m_script->node_on_dig(p_under, n, playersao);
2566 // Send unusual result (that is, node not being removed)
2567 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2569 // Re-send block to revert change on client-side
2570 RemoteClient *client = getClient(peer_id);
2571 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2572 client->SetBlockNotSent(blockpos);
2578 3: place block or right-click object
2580 else if(action == 3)
2582 ItemStack item = playersao->getWieldedItem();
2584 // Reset build time counter
2585 if(pointed.type == POINTEDTHING_NODE &&
2586 item.getDefinition(m_itemdef).type == ITEM_NODE)
2587 getClient(peer_id)->m_time_from_building = 0.0;
2589 if(pointed.type == POINTEDTHING_OBJECT)
2591 // Right click object
2593 // Skip if object has been removed
2594 if(pointed_object->m_removed)
2597 actionstream<<player->getName()<<" right-clicks object "
2598 <<pointed.object_id<<": "
2599 <<pointed_object->getDescription()<<std::endl;
2602 pointed_object->rightClick(playersao);
2604 else if(m_script->item_OnPlace(
2605 item, playersao, pointed))
2607 // Placement was handled in lua
2609 // Apply returned ItemStack
2610 playersao->setWieldedItem(item);
2613 // If item has node placement prediction, always send the
2614 // blocks to make sure the client knows what exactly happened
2615 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2616 RemoteClient *client = getClient(peer_id);
2617 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2618 client->SetBlockNotSent(blockpos);
2619 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2620 if(blockpos2 != blockpos){
2621 client->SetBlockNotSent(blockpos2);
2629 else if(action == 4)
2631 ItemStack item = playersao->getWieldedItem();
2633 actionstream<<player->getName()<<" uses "<<item.name
2634 <<", pointing at "<<pointed.dump()<<std::endl;
2636 if(m_script->item_OnUse(
2637 item, playersao, pointed))
2639 // Apply returned ItemStack
2640 playersao->setWieldedItem(item);
2647 Catch invalid actions
2651 infostream<<"WARNING: Server: Invalid action "
2652 <<action<<std::endl;
2655 else if(command == TOSERVER_REMOVED_SOUNDS)
2657 std::string datastring((char*)&data[2], datasize-2);
2658 std::istringstream is(datastring, std::ios_base::binary);
2660 int num = readU16(is);
2661 for(int k=0; k<num; k++){
2662 s32 id = readS32(is);
2663 std::map<s32, ServerPlayingSound>::iterator i =
2664 m_playing_sounds.find(id);
2665 if(i == m_playing_sounds.end())
2667 ServerPlayingSound &psound = i->second;
2668 psound.clients.erase(peer_id);
2669 if(psound.clients.size() == 0)
2670 m_playing_sounds.erase(i++);
2673 else if(command == TOSERVER_NODEMETA_FIELDS)
2675 std::string datastring((char*)&data[2], datasize-2);
2676 std::istringstream is(datastring, std::ios_base::binary);
2678 v3s16 p = readV3S16(is);
2679 std::string formname = deSerializeString(is);
2680 int num = readU16(is);
2681 std::map<std::string, std::string> fields;
2682 for(int k=0; k<num; k++){
2683 std::string fieldname = deSerializeString(is);
2684 std::string fieldvalue = deSerializeLongString(is);
2685 fields[fieldname] = fieldvalue;
2688 // If something goes wrong, this player is to blame
2689 RollbackScopeActor rollback_scope(m_rollback,
2690 std::string("player:")+player->getName());
2692 // Check the target node for rollback data; leave others unnoticed
2693 RollbackNode rn_old(&m_env->getMap(), p, this);
2695 m_script->node_on_receive_fields(p, formname, fields,playersao);
2697 // Report rollback data
2698 RollbackNode rn_new(&m_env->getMap(), p, this);
2699 if(rollback() && rn_new != rn_old){
2700 RollbackAction action;
2701 action.setSetNode(p, rn_old, rn_new);
2702 rollback()->reportAction(action);
2705 else if(command == TOSERVER_INVENTORY_FIELDS)
2707 std::string datastring((char*)&data[2], datasize-2);
2708 std::istringstream is(datastring, std::ios_base::binary);
2710 std::string formname = deSerializeString(is);
2711 int num = readU16(is);
2712 std::map<std::string, std::string> fields;
2713 for(int k=0; k<num; k++){
2714 std::string fieldname = deSerializeString(is);
2715 std::string fieldvalue = deSerializeLongString(is);
2716 fields[fieldname] = fieldvalue;
2719 m_script->on_playerReceiveFields(playersao, formname, fields);
2723 infostream<<"Server::ProcessData(): Ignoring "
2724 "unknown command "<<command<<std::endl;
2728 catch(SendFailedException &e)
2730 errorstream<<"Server::ProcessData(): SendFailedException: "
2736 void Server::setTimeOfDay(u32 time)
2738 m_env->setTimeOfDay(time);
2739 m_time_of_day_send_timer = 0;
2742 void Server::onMapEditEvent(MapEditEvent *event)
2744 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2745 if(m_ignore_map_edit_events)
2747 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2749 MapEditEvent *e = event->clone();
2750 m_unsent_map_edit_queue.push_back(e);
2753 Inventory* Server::getInventory(const InventoryLocation &loc)
2756 case InventoryLocation::UNDEFINED:
2759 case InventoryLocation::CURRENT_PLAYER:
2762 case InventoryLocation::PLAYER:
2764 Player *player = m_env->getPlayer(loc.name.c_str());
2767 PlayerSAO *playersao = player->getPlayerSAO();
2770 return playersao->getInventory();
2773 case InventoryLocation::NODEMETA:
2775 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2778 return meta->getInventory();
2781 case InventoryLocation::DETACHED:
2783 if(m_detached_inventories.count(loc.name) == 0)
2785 return m_detached_inventories[loc.name];
2793 void Server::setInventoryModified(const InventoryLocation &loc)
2796 case InventoryLocation::UNDEFINED:
2799 case InventoryLocation::PLAYER:
2801 Player *player = m_env->getPlayer(loc.name.c_str());
2804 PlayerSAO *playersao = player->getPlayerSAO();
2807 playersao->m_inventory_not_sent = true;
2808 playersao->m_wielded_item_not_sent = true;
2811 case InventoryLocation::NODEMETA:
2813 v3s16 blockpos = getNodeBlockPos(loc.p);
2815 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2817 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2819 setBlockNotSent(blockpos);
2822 case InventoryLocation::DETACHED:
2824 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2832 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2834 std::list<u16> clients = m_clients.getClientIDs();
2836 // Set the modified blocks unsent for all the clients
2837 for (std::list<u16>::iterator
2838 i = clients.begin();
2839 i != clients.end(); ++i) {
2840 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2842 client->SetBlocksNotSent(block);
2847 void Server::peerAdded(con::Peer *peer)
2849 DSTACK(__FUNCTION_NAME);
2850 verbosestream<<"Server::peerAdded(): peer->id="
2851 <<peer->id<<std::endl;
2854 c.type = con::PEER_ADDED;
2855 c.peer_id = peer->id;
2857 m_peer_change_queue.push_back(c);
2860 void Server::deletingPeer(con::Peer *peer, bool timeout)
2862 DSTACK(__FUNCTION_NAME);
2863 verbosestream<<"Server::deletingPeer(): peer->id="
2864 <<peer->id<<", timeout="<<timeout<<std::endl;
2866 m_clients.event(peer->id,Disconnect);
2868 c.type = con::PEER_REMOVED;
2869 c.peer_id = peer->id;
2870 c.timeout = timeout;
2871 m_peer_change_queue.push_back(c);
2874 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2876 *retval = m_con.getPeerStat(peer_id,type);
2877 if (*retval == -1) return false;
2881 bool Server::getClientInfo(
2890 std::string* vers_string
2893 *state = m_clients.getClientState(peer_id);
2895 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2897 if (client == NULL) {
2902 *uptime = client->uptime();
2903 *ser_vers = client->serialization_version;
2904 *prot_vers = client->net_proto_version;
2906 *major = client->getMajor();
2907 *minor = client->getMinor();
2908 *patch = client->getPatch();
2909 *vers_string = client->getPatch();
2916 void Server::handlePeerChanges()
2918 while(m_peer_change_queue.size() > 0)
2920 con::PeerChange c = m_peer_change_queue.pop_front();
2922 verbosestream<<"Server: Handling peer change: "
2923 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2928 case con::PEER_ADDED:
2929 m_clients.CreateClient(c.peer_id);
2932 case con::PEER_REMOVED:
2933 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2937 assert("Invalid peer change event received!" == 0);
2943 void Server::SendMovement(u16 peer_id)
2945 DSTACK(__FUNCTION_NAME);
2946 std::ostringstream os(std::ios_base::binary);
2948 writeU16(os, TOCLIENT_MOVEMENT);
2949 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2950 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2951 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2952 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2953 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2954 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2955 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2956 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2957 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2958 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2959 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2960 writeF1000(os, g_settings->getFloat("movement_gravity"));
2963 std::string s = os.str();
2964 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2966 m_clients.send(peer_id, 0, data, true);
2969 void Server::SendHP(u16 peer_id, u8 hp)
2971 DSTACK(__FUNCTION_NAME);
2972 std::ostringstream os(std::ios_base::binary);
2974 writeU16(os, TOCLIENT_HP);
2978 std::string s = os.str();
2979 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2981 m_clients.send(peer_id, 0, data, true);
2984 void Server::SendBreath(u16 peer_id, u16 breath)
2986 DSTACK(__FUNCTION_NAME);
2987 std::ostringstream os(std::ios_base::binary);
2989 writeU16(os, TOCLIENT_BREATH);
2990 writeU16(os, breath);
2993 std::string s = os.str();
2994 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2996 m_clients.send(peer_id, 0, data, true);
2999 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3001 DSTACK(__FUNCTION_NAME);
3002 std::ostringstream os(std::ios_base::binary);
3004 writeU16(os, TOCLIENT_ACCESS_DENIED);
3005 os<<serializeWideString(reason);
3008 std::string s = os.str();
3009 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3011 m_clients.send(peer_id, 0, data, true);
3014 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3015 v3f camera_point_target)
3017 DSTACK(__FUNCTION_NAME);
3018 std::ostringstream os(std::ios_base::binary);
3020 writeU16(os, TOCLIENT_DEATHSCREEN);
3021 writeU8(os, set_camera_point_target);
3022 writeV3F1000(os, camera_point_target);
3025 std::string s = os.str();
3026 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3028 m_clients.send(peer_id, 0, data, true);
3031 void Server::SendItemDef(u16 peer_id,
3032 IItemDefManager *itemdef, u16 protocol_version)
3034 DSTACK(__FUNCTION_NAME);
3035 std::ostringstream os(std::ios_base::binary);
3039 u32 length of the next item
3040 zlib-compressed serialized ItemDefManager
3042 writeU16(os, TOCLIENT_ITEMDEF);
3043 std::ostringstream tmp_os(std::ios::binary);
3044 itemdef->serialize(tmp_os, protocol_version);
3045 std::ostringstream tmp_os2(std::ios::binary);
3046 compressZlib(tmp_os.str(), tmp_os2);
3047 os<<serializeLongString(tmp_os2.str());
3050 std::string s = os.str();
3051 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3052 <<"): size="<<s.size()<<std::endl;
3053 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3055 m_clients.send(peer_id, 0, data, true);
3058 void Server::SendNodeDef(u16 peer_id,
3059 INodeDefManager *nodedef, u16 protocol_version)
3061 DSTACK(__FUNCTION_NAME);
3062 std::ostringstream os(std::ios_base::binary);
3066 u32 length of the next item
3067 zlib-compressed serialized NodeDefManager
3069 writeU16(os, TOCLIENT_NODEDEF);
3070 std::ostringstream tmp_os(std::ios::binary);
3071 nodedef->serialize(tmp_os, protocol_version);
3072 std::ostringstream tmp_os2(std::ios::binary);
3073 compressZlib(tmp_os.str(), tmp_os2);
3074 os<<serializeLongString(tmp_os2.str());
3077 std::string s = os.str();
3078 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3079 <<"): size="<<s.size()<<std::endl;
3080 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3082 m_clients.send(peer_id, 0, data, true);
3086 Non-static send methods
3089 void Server::SendInventory(u16 peer_id)
3091 DSTACK(__FUNCTION_NAME);
3093 PlayerSAO *playersao = getPlayerSAO(peer_id);
3096 playersao->m_inventory_not_sent = false;
3102 std::ostringstream os;
3103 playersao->getInventory()->serialize(os);
3105 std::string s = os.str();
3107 SharedBuffer<u8> data(s.size()+2);
3108 writeU16(&data[0], TOCLIENT_INVENTORY);
3109 memcpy(&data[2], s.c_str(), s.size());
3112 m_clients.send(peer_id, 0, data, true);
3115 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3117 DSTACK(__FUNCTION_NAME);
3119 std::ostringstream os(std::ios_base::binary);
3123 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3124 os.write((char*)buf, 2);
3127 writeU16(buf, message.size());
3128 os.write((char*)buf, 2);
3131 for(u32 i=0; i<message.size(); i++)
3135 os.write((char*)buf, 2);
3139 std::string s = os.str();
3140 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3142 if (peer_id != PEER_ID_INEXISTENT)
3145 m_clients.send(peer_id, 0, data, true);
3149 m_clients.sendToAll(0,data,true);
3153 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3154 const std::string &formname)
3156 DSTACK(__FUNCTION_NAME);
3158 std::ostringstream os(std::ios_base::binary);
3162 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3163 os.write((char*)buf, 2);
3164 os<<serializeLongString(formspec);
3165 os<<serializeString(formname);
3168 std::string s = os.str();
3169 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3171 m_clients.send(peer_id, 0, data, true);
3174 // Spawns a particle on peer with peer_id
3175 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3176 float expirationtime, float size, bool collisiondetection,
3177 bool vertical, std::string texture)
3179 DSTACK(__FUNCTION_NAME);
3181 std::ostringstream os(std::ios_base::binary);
3182 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3183 writeV3F1000(os, pos);
3184 writeV3F1000(os, velocity);
3185 writeV3F1000(os, acceleration);
3186 writeF1000(os, expirationtime);
3187 writeF1000(os, size);
3188 writeU8(os, collisiondetection);
3189 os<<serializeLongString(texture);
3190 writeU8(os, vertical);
3193 std::string s = os.str();
3194 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3196 if (peer_id != PEER_ID_INEXISTENT)
3199 m_clients.send(peer_id, 0, data, true);
3203 m_clients.sendToAll(0,data,true);
3207 // Adds a ParticleSpawner on peer with peer_id
3208 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3209 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3210 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3212 DSTACK(__FUNCTION_NAME);
3214 std::ostringstream os(std::ios_base::binary);
3215 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3217 writeU16(os, amount);
3218 writeF1000(os, spawntime);
3219 writeV3F1000(os, minpos);
3220 writeV3F1000(os, maxpos);
3221 writeV3F1000(os, minvel);
3222 writeV3F1000(os, maxvel);
3223 writeV3F1000(os, minacc);
3224 writeV3F1000(os, maxacc);
3225 writeF1000(os, minexptime);
3226 writeF1000(os, maxexptime);
3227 writeF1000(os, minsize);
3228 writeF1000(os, maxsize);
3229 writeU8(os, collisiondetection);
3230 os<<serializeLongString(texture);
3232 writeU8(os, vertical);
3235 std::string s = os.str();
3236 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3238 if (peer_id != PEER_ID_INEXISTENT)
3241 m_clients.send(peer_id, 0, data, true);
3244 m_clients.sendToAll(0,data,true);
3248 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3250 DSTACK(__FUNCTION_NAME);
3252 std::ostringstream os(std::ios_base::binary);
3253 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3258 std::string s = os.str();
3259 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3261 if (peer_id != PEER_ID_INEXISTENT) {
3263 m_clients.send(peer_id, 0, data, true);
3266 m_clients.sendToAll(0,data,true);
3271 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3273 std::ostringstream os(std::ios_base::binary);
3276 writeU16(os, TOCLIENT_HUDADD);
3278 writeU8(os, (u8)form->type);
3279 writeV2F1000(os, form->pos);
3280 os << serializeString(form->name);
3281 writeV2F1000(os, form->scale);
3282 os << serializeString(form->text);
3283 writeU32(os, form->number);
3284 writeU32(os, form->item);
3285 writeU32(os, form->dir);
3286 writeV2F1000(os, form->align);
3287 writeV2F1000(os, form->offset);
3288 writeV3F1000(os, form->world_pos);
3289 writeV2S32(os,form->size);
3292 std::string s = os.str();
3293 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3295 m_clients.send(peer_id, 1, data, true);
3298 void Server::SendHUDRemove(u16 peer_id, u32 id)
3300 std::ostringstream os(std::ios_base::binary);
3303 writeU16(os, TOCLIENT_HUDRM);
3307 std::string s = os.str();
3308 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3311 m_clients.send(peer_id, 1, data, true);
3314 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3316 std::ostringstream os(std::ios_base::binary);
3319 writeU16(os, TOCLIENT_HUDCHANGE);
3321 writeU8(os, (u8)stat);
3324 case HUD_STAT_SCALE:
3325 case HUD_STAT_ALIGN:
3326 case HUD_STAT_OFFSET:
3327 writeV2F1000(os, *(v2f *)value);
3331 os << serializeString(*(std::string *)value);
3333 case HUD_STAT_WORLD_POS:
3334 writeV3F1000(os, *(v3f *)value);
3337 writeV2S32(os,*(v2s32 *)value);
3339 case HUD_STAT_NUMBER:
3343 writeU32(os, *(u32 *)value);
3348 std::string s = os.str();
3349 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3351 m_clients.send(peer_id, 0, data, true);
3354 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3356 std::ostringstream os(std::ios_base::binary);
3359 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3361 //////////////////////////// compatibility code to be removed //////////////
3362 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3363 ////////////////////////////////////////////////////////////////////////////
3364 writeU32(os, flags);
3368 std::string s = os.str();
3369 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3371 m_clients.send(peer_id, 0, data, true);
3374 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3376 std::ostringstream os(std::ios_base::binary);
3379 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3380 writeU16(os, param);
3381 os<<serializeString(value);
3384 std::string s = os.str();
3385 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3387 m_clients.send(peer_id, 0, data, true);
3390 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3391 const std::string &type, const std::vector<std::string> ¶ms)
3393 std::ostringstream os(std::ios_base::binary);
3396 writeU16(os, TOCLIENT_SET_SKY);
3397 writeARGB8(os, bgcolor);
3398 os<<serializeString(type);
3399 writeU16(os, params.size());
3400 for(size_t i=0; i<params.size(); i++)
3401 os<<serializeString(params[i]);
3404 std::string s = os.str();
3405 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3407 m_clients.send(peer_id, 0, data, true);
3410 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3413 std::ostringstream os(std::ios_base::binary);
3416 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3417 writeU8(os, do_override);
3418 writeU16(os, ratio*65535);
3421 std::string s = os.str();
3422 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3424 m_clients.send(peer_id, 0, data, true);
3427 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3429 DSTACK(__FUNCTION_NAME);
3432 SharedBuffer<u8> data(2+2+4);
3433 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3434 writeU16(&data[2], time);
3435 writeF1000(&data[4], time_speed);
3437 if (peer_id == PEER_ID_INEXISTENT) {
3438 m_clients.sendToAll(0,data,true);
3442 m_clients.send(peer_id, 0, data, true);
3446 void Server::SendPlayerHP(u16 peer_id)
3448 DSTACK(__FUNCTION_NAME);
3449 PlayerSAO *playersao = getPlayerSAO(peer_id);
3451 playersao->m_hp_not_sent = false;
3452 SendHP(peer_id, playersao->getHP());
3453 m_script->player_event(playersao,"health_changed");
3455 // Send to other clients
3456 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3457 ActiveObjectMessage aom(playersao->getId(), true, str);
3458 playersao->m_messages_out.push_back(aom);
3461 void Server::SendPlayerBreath(u16 peer_id)
3463 DSTACK(__FUNCTION_NAME);
3464 PlayerSAO *playersao = getPlayerSAO(peer_id);
3466 playersao->m_breath_not_sent = false;
3467 m_script->player_event(playersao,"breath_changed");
3468 SendBreath(peer_id, playersao->getBreath());
3471 void Server::SendMovePlayer(u16 peer_id)
3473 DSTACK(__FUNCTION_NAME);
3474 Player *player = m_env->getPlayer(peer_id);
3477 std::ostringstream os(std::ios_base::binary);
3478 writeU16(os, TOCLIENT_MOVE_PLAYER);
3479 writeV3F1000(os, player->getPosition());
3480 writeF1000(os, player->getPitch());
3481 writeF1000(os, player->getYaw());
3484 v3f pos = player->getPosition();
3485 f32 pitch = player->getPitch();
3486 f32 yaw = player->getYaw();
3487 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3488 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3495 std::string s = os.str();
3496 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3498 m_clients.send(peer_id, 0, data, true);
3501 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3503 std::ostringstream os(std::ios_base::binary);
3505 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3506 writeV2S32(os, animation_frames[0]);
3507 writeV2S32(os, animation_frames[1]);
3508 writeV2S32(os, animation_frames[2]);
3509 writeV2S32(os, animation_frames[3]);
3510 writeF1000(os, animation_speed);
3513 std::string s = os.str();
3514 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3516 m_clients.send(peer_id, 0, data, true);
3519 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3521 std::ostringstream os(std::ios_base::binary);
3523 writeU16(os, TOCLIENT_EYE_OFFSET);
3524 writeV3F1000(os, first);
3525 writeV3F1000(os, third);
3528 std::string s = os.str();
3529 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3531 m_clients.send(peer_id, 0, data, true);
3533 void Server::SendPlayerPrivileges(u16 peer_id)
3535 Player *player = m_env->getPlayer(peer_id);
3537 if(player->peer_id == PEER_ID_INEXISTENT)
3540 std::set<std::string> privs;
3541 m_script->getAuth(player->getName(), NULL, &privs);
3543 std::ostringstream os(std::ios_base::binary);
3544 writeU16(os, TOCLIENT_PRIVILEGES);
3545 writeU16(os, privs.size());
3546 for(std::set<std::string>::const_iterator i = privs.begin();
3547 i != privs.end(); i++){
3548 os<<serializeString(*i);
3552 std::string s = os.str();
3553 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3555 m_clients.send(peer_id, 0, data, true);
3558 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3560 Player *player = m_env->getPlayer(peer_id);
3562 if(player->peer_id == PEER_ID_INEXISTENT)
3565 std::ostringstream os(std::ios_base::binary);
3566 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3567 os<<serializeLongString(player->inventory_formspec);
3570 std::string s = os.str();
3571 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3573 m_clients.send(peer_id, 0, data, true);
3576 s32 Server::playSound(const SimpleSoundSpec &spec,
3577 const ServerSoundParams ¶ms)
3579 // Find out initial position of sound
3580 bool pos_exists = false;
3581 v3f pos = params.getPos(m_env, &pos_exists);
3582 // If position is not found while it should be, cancel sound
3583 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3586 // Filter destination clients
3587 std::list<u16> dst_clients;
3588 if(params.to_player != "")
3590 Player *player = m_env->getPlayer(params.to_player.c_str());
3592 infostream<<"Server::playSound: Player \""<<params.to_player
3593 <<"\" not found"<<std::endl;
3596 if(player->peer_id == PEER_ID_INEXISTENT){
3597 infostream<<"Server::playSound: Player \""<<params.to_player
3598 <<"\" not connected"<<std::endl;
3601 dst_clients.push_back(player->peer_id);
3605 std::list<u16> clients = m_clients.getClientIDs();
3607 for(std::list<u16>::iterator
3608 i = clients.begin(); i != clients.end(); ++i)
3610 Player *player = m_env->getPlayer(*i);
3614 if(player->getPosition().getDistanceFrom(pos) >
3615 params.max_hear_distance)
3618 dst_clients.push_back(*i);
3621 if(dst_clients.size() == 0)
3625 s32 id = m_next_sound_id++;
3626 // The sound will exist as a reference in m_playing_sounds
3627 m_playing_sounds[id] = ServerPlayingSound();
3628 ServerPlayingSound &psound = m_playing_sounds[id];
3629 psound.params = params;
3630 for(std::list<u16>::iterator i = dst_clients.begin();
3631 i != dst_clients.end(); i++)
3632 psound.clients.insert(*i);
3634 std::ostringstream os(std::ios_base::binary);
3635 writeU16(os, TOCLIENT_PLAY_SOUND);
3637 os<<serializeString(spec.name);
3638 writeF1000(os, spec.gain * params.gain);
3639 writeU8(os, params.type);
3640 writeV3F1000(os, pos);
3641 writeU16(os, params.object);
3642 writeU8(os, params.loop);
3644 std::string s = os.str();
3645 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3647 for(std::list<u16>::iterator i = dst_clients.begin();
3648 i != dst_clients.end(); i++){
3650 m_clients.send(*i, 0, data, true);
3654 void Server::stopSound(s32 handle)
3656 // Get sound reference
3657 std::map<s32, ServerPlayingSound>::iterator i =
3658 m_playing_sounds.find(handle);
3659 if(i == m_playing_sounds.end())
3661 ServerPlayingSound &psound = i->second;
3663 std::ostringstream os(std::ios_base::binary);
3664 writeU16(os, TOCLIENT_STOP_SOUND);
3665 writeS32(os, handle);
3667 std::string s = os.str();
3668 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3670 for(std::set<u16>::iterator i = psound.clients.begin();
3671 i != psound.clients.end(); i++){
3673 m_clients.send(*i, 0, data, true);
3675 // Remove sound reference
3676 m_playing_sounds.erase(i);
3679 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3680 std::list<u16> *far_players, float far_d_nodes)
3682 float maxd = far_d_nodes*BS;
3683 v3f p_f = intToFloat(p, BS);
3687 SharedBuffer<u8> reply(replysize);
3688 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3689 writeS16(&reply[2], p.X);
3690 writeS16(&reply[4], p.Y);
3691 writeS16(&reply[6], p.Z);
3693 std::list<u16> clients = m_clients.getClientIDs();
3694 for(std::list<u16>::iterator
3695 i = clients.begin();
3696 i != clients.end(); ++i)
3701 Player *player = m_env->getPlayer(*i);
3704 // If player is far away, only set modified blocks not sent
3705 v3f player_pos = player->getPosition();
3706 if(player_pos.getDistanceFrom(p_f) > maxd)
3708 far_players->push_back(*i);
3715 m_clients.send(*i, 0, reply, true);
3719 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3720 std::list<u16> *far_players, float far_d_nodes,
3721 bool remove_metadata)
3723 float maxd = far_d_nodes*BS;
3724 v3f p_f = intToFloat(p, BS);
3726 std::list<u16> clients = m_clients.getClientIDs();
3727 for(std::list<u16>::iterator
3728 i = clients.begin();
3729 i != clients.end(); ++i)
3735 Player *player = m_env->getPlayer(*i);
3738 // If player is far away, only set modified blocks not sent
3739 v3f player_pos = player->getPosition();
3740 if(player_pos.getDistanceFrom(p_f) > maxd)
3742 far_players->push_back(*i);
3747 SharedBuffer<u8> reply(0);
3749 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3753 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3754 reply = SharedBuffer<u8>(replysize);
3755 writeU16(&reply[0], TOCLIENT_ADDNODE);
3756 writeS16(&reply[2], p.X);
3757 writeS16(&reply[4], p.Y);
3758 writeS16(&reply[6], p.Z);
3759 n.serialize(&reply[8], client->serialization_version);
3760 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3761 writeU8(&reply[index], remove_metadata ? 0 : 1);
3763 if (!remove_metadata) {
3764 if (client->net_proto_version <= 21) {
3765 // Old clients always clear metadata; fix it
3766 // by sending the full block again.
3767 client->SetBlockNotSent(p);
3774 if (reply.getSize() > 0)
3775 m_clients.send(*i, 0, reply, true);
3779 void Server::setBlockNotSent(v3s16 p)
3781 std::list<u16> clients = m_clients.getClientIDs();
3783 for(std::list<u16>::iterator
3784 i = clients.begin();
3785 i != clients.end(); ++i)
3787 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3788 client->SetBlockNotSent(p);
3793 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3795 DSTACK(__FUNCTION_NAME);
3797 v3s16 p = block->getPos();
3801 bool completely_air = true;
3802 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3803 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3804 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3806 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3808 completely_air = false;
3809 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3814 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3816 infostream<<"[completely air] ";
3817 infostream<<std::endl;
3821 Create a packet with the block in the right format
3824 std::ostringstream os(std::ios_base::binary);
3825 block->serialize(os, ver, false);
3826 block->serializeNetworkSpecific(os, net_proto_version);
3827 std::string s = os.str();
3828 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3830 u32 replysize = 8 + blockdata.getSize();
3831 SharedBuffer<u8> reply(replysize);
3832 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3833 writeS16(&reply[2], p.X);
3834 writeS16(&reply[4], p.Y);
3835 writeS16(&reply[6], p.Z);
3836 memcpy(&reply[8], *blockdata, blockdata.getSize());
3838 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3839 <<": \tpacket size: "<<replysize<<std::endl;*/
3844 m_clients.send(peer_id, 2, reply, true);
3847 void Server::SendBlocks(float dtime)
3849 DSTACK(__FUNCTION_NAME);
3851 JMutexAutoLock envlock(m_env_mutex);
3852 //TODO check if one big lock could be faster then multiple small ones
3854 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3856 std::vector<PrioritySortedBlockTransfer> queue;
3858 s32 total_sending = 0;
3861 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3863 std::list<u16> clients = m_clients.getClientIDs();
3866 for(std::list<u16>::iterator
3867 i = clients.begin();
3868 i != clients.end(); ++i)
3870 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3875 total_sending += client->SendingCount();
3876 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3882 // Lowest priority number comes first.
3883 // Lowest is most important.
3884 std::sort(queue.begin(), queue.end());
3887 for(u32 i=0; i<queue.size(); i++)
3889 //TODO: Calculate limit dynamically
3890 if(total_sending >= g_settings->getS32
3891 ("max_simultaneous_block_sends_server_total"))
3894 PrioritySortedBlockTransfer q = queue[i];
3896 MapBlock *block = NULL;
3899 block = m_env->getMap().getBlockNoCreate(q.pos);
3901 catch(InvalidPositionException &e)
3906 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3911 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3913 client->SentBlock(q.pos);
3919 void Server::fillMediaCache()
3921 DSTACK(__FUNCTION_NAME);
3923 infostream<<"Server: Calculating media file checksums"<<std::endl;
3925 // Collect all media file paths
3926 std::list<std::string> paths;
3927 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3928 i != m_mods.end(); i++){
3929 const ModSpec &mod = *i;
3930 paths.push_back(mod.path + DIR_DELIM + "textures");
3931 paths.push_back(mod.path + DIR_DELIM + "sounds");
3932 paths.push_back(mod.path + DIR_DELIM + "media");
3933 paths.push_back(mod.path + DIR_DELIM + "models");
3935 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3937 // Collect media file information from paths into cache
3938 for(std::list<std::string>::iterator i = paths.begin();
3939 i != paths.end(); i++)
3941 std::string mediapath = *i;
3942 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3943 for(u32 j=0; j<dirlist.size(); j++){
3944 if(dirlist[j].dir) // Ignode dirs
3946 std::string filename = dirlist[j].name;
3947 // If name contains illegal characters, ignore the file
3948 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3949 infostream<<"Server: ignoring illegal file name: \""
3950 <<filename<<"\""<<std::endl;
3953 // If name is not in a supported format, ignore it
3954 const char *supported_ext[] = {
3955 ".png", ".jpg", ".bmp", ".tga",
3956 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3958 ".x", ".b3d", ".md2", ".obj",
3961 if(removeStringEnd(filename, supported_ext) == ""){
3962 infostream<<"Server: ignoring unsupported file extension: \""
3963 <<filename<<"\""<<std::endl;
3966 // Ok, attempt to load the file and add to cache
3967 std::string filepath = mediapath + DIR_DELIM + filename;
3969 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3970 if(fis.good() == false){
3971 errorstream<<"Server::fillMediaCache(): Could not open \""
3972 <<filename<<"\" for reading"<<std::endl;
3975 std::ostringstream tmp_os(std::ios_base::binary);
3979 fis.read(buf, 1024);
3980 std::streamsize len = fis.gcount();
3981 tmp_os.write(buf, len);
3990 errorstream<<"Server::fillMediaCache(): Failed to read \""
3991 <<filename<<"\""<<std::endl;
3994 if(tmp_os.str().length() == 0){
3995 errorstream<<"Server::fillMediaCache(): Empty file \""
3996 <<filepath<<"\""<<std::endl;
4001 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4003 unsigned char *digest = sha1.getDigest();
4004 std::string sha1_base64 = base64_encode(digest, 20);
4005 std::string sha1_hex = hex_encode((char*)digest, 20);
4009 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4010 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4015 struct SendableMediaAnnouncement
4018 std::string sha1_digest;
4020 SendableMediaAnnouncement(const std::string &name_="",
4021 const std::string &sha1_digest_=""):
4023 sha1_digest(sha1_digest_)
4027 void Server::sendMediaAnnouncement(u16 peer_id)
4029 DSTACK(__FUNCTION_NAME);
4031 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4034 std::list<SendableMediaAnnouncement> file_announcements;
4036 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4037 i != m_media.end(); i++){
4039 file_announcements.push_back(
4040 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4044 std::ostringstream os(std::ios_base::binary);
4052 u16 length of sha1_digest
4057 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4058 writeU16(os, file_announcements.size());
4060 for(std::list<SendableMediaAnnouncement>::iterator
4061 j = file_announcements.begin();
4062 j != file_announcements.end(); ++j){
4063 os<<serializeString(j->name);
4064 os<<serializeString(j->sha1_digest);
4066 os<<serializeString(g_settings->get("remote_media"));
4069 std::string s = os.str();
4070 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4073 m_clients.send(peer_id, 0, data, true);
4076 struct SendableMedia
4082 SendableMedia(const std::string &name_="", const std::string &path_="",
4083 const std::string &data_=""):
4090 void Server::sendRequestedMedia(u16 peer_id,
4091 const std::list<std::string> &tosend)
4093 DSTACK(__FUNCTION_NAME);
4095 verbosestream<<"Server::sendRequestedMedia(): "
4096 <<"Sending files to client"<<std::endl;
4100 // Put 5kB in one bunch (this is not accurate)
4101 u32 bytes_per_bunch = 5000;
4103 std::vector< std::list<SendableMedia> > file_bunches;
4104 file_bunches.push_back(std::list<SendableMedia>());
4106 u32 file_size_bunch_total = 0;
4108 for(std::list<std::string>::const_iterator i = tosend.begin();
4109 i != tosend.end(); ++i)
4111 const std::string &name = *i;
4113 if(m_media.find(name) == m_media.end()){
4114 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4115 <<"unknown file \""<<(name)<<"\""<<std::endl;
4119 //TODO get path + name
4120 std::string tpath = m_media[name].path;
4123 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4124 if(fis.good() == false){
4125 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4126 <<tpath<<"\" for reading"<<std::endl;
4129 std::ostringstream tmp_os(std::ios_base::binary);
4133 fis.read(buf, 1024);
4134 std::streamsize len = fis.gcount();
4135 tmp_os.write(buf, len);
4136 file_size_bunch_total += len;
4145 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4146 <<name<<"\""<<std::endl;
4149 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4150 <<tname<<"\""<<std::endl;*/
4152 file_bunches[file_bunches.size()-1].push_back(
4153 SendableMedia(name, tpath, tmp_os.str()));
4155 // Start next bunch if got enough data
4156 if(file_size_bunch_total >= bytes_per_bunch){
4157 file_bunches.push_back(std::list<SendableMedia>());
4158 file_size_bunch_total = 0;
4163 /* Create and send packets */
4165 u32 num_bunches = file_bunches.size();
4166 for(u32 i=0; i<num_bunches; i++)
4168 std::ostringstream os(std::ios_base::binary);
4172 u16 total number of texture bunches
4173 u16 index of this bunch
4174 u32 number of files in this bunch
4183 writeU16(os, TOCLIENT_MEDIA);
4184 writeU16(os, num_bunches);
4186 writeU32(os, file_bunches[i].size());
4188 for(std::list<SendableMedia>::iterator
4189 j = file_bunches[i].begin();
4190 j != file_bunches[i].end(); ++j){
4191 os<<serializeString(j->name);
4192 os<<serializeLongString(j->data);
4196 std::string s = os.str();
4197 verbosestream<<"Server::sendRequestedMedia(): bunch "
4198 <<i<<"/"<<num_bunches
4199 <<" files="<<file_bunches[i].size()
4200 <<" size=" <<s.size()<<std::endl;
4201 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4203 m_clients.send(peer_id, 2, data, true);
4207 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4209 if(m_detached_inventories.count(name) == 0){
4210 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4213 Inventory *inv = m_detached_inventories[name];
4215 std::ostringstream os(std::ios_base::binary);
4216 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4217 os<<serializeString(name);
4221 std::string s = os.str();
4222 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4224 if (peer_id != PEER_ID_INEXISTENT)
4227 m_clients.send(peer_id, 0, data, true);
4231 m_clients.sendToAll(0,data,true);
4235 void Server::sendDetachedInventories(u16 peer_id)
4237 DSTACK(__FUNCTION_NAME);
4239 for(std::map<std::string, Inventory*>::iterator
4240 i = m_detached_inventories.begin();
4241 i != m_detached_inventories.end(); i++){
4242 const std::string &name = i->first;
4243 //Inventory *inv = i->second;
4244 sendDetachedInventory(name, peer_id);
4252 void Server::DiePlayer(u16 peer_id)
4254 DSTACK(__FUNCTION_NAME);
4256 PlayerSAO *playersao = getPlayerSAO(peer_id);
4259 infostream<<"Server::DiePlayer(): Player "
4260 <<playersao->getPlayer()->getName()
4261 <<" dies"<<std::endl;
4263 playersao->setHP(0);
4265 // Trigger scripted stuff
4266 m_script->on_dieplayer(playersao);
4268 SendPlayerHP(peer_id);
4269 SendDeathscreen(peer_id, false, v3f(0,0,0));
4272 void Server::RespawnPlayer(u16 peer_id)
4274 DSTACK(__FUNCTION_NAME);
4276 PlayerSAO *playersao = getPlayerSAO(peer_id);
4279 infostream<<"Server::RespawnPlayer(): Player "
4280 <<playersao->getPlayer()->getName()
4281 <<" respawns"<<std::endl;
4283 playersao->setHP(PLAYER_MAX_HP);
4285 bool repositioned = m_script->on_respawnplayer(playersao);
4287 v3f pos = findSpawnPos(m_env->getServerMap());
4288 playersao->setPos(pos);
4292 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4294 DSTACK(__FUNCTION_NAME);
4296 SendAccessDenied(peer_id, reason);
4297 m_clients.event(peer_id,SetDenied);
4298 m_con.DisconnectPeer(peer_id);
4301 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4303 DSTACK(__FUNCTION_NAME);
4304 std::wstring message;
4307 Clear references to playing sounds
4309 for(std::map<s32, ServerPlayingSound>::iterator
4310 i = m_playing_sounds.begin();
4311 i != m_playing_sounds.end();)
4313 ServerPlayingSound &psound = i->second;
4314 psound.clients.erase(peer_id);
4315 if(psound.clients.size() == 0)
4316 m_playing_sounds.erase(i++);
4321 Player *player = m_env->getPlayer(peer_id);
4323 // Collect information about leaving in chat
4325 if(player != NULL && reason != CDR_DENY)
4327 std::wstring name = narrow_to_wide(player->getName());
4330 message += L" left the game.";
4331 if(reason == CDR_TIMEOUT)
4332 message += L" (timed out)";
4336 /* Run scripts and remove from environment */
4340 PlayerSAO *playersao = player->getPlayerSAO();
4343 m_script->on_leaveplayer(playersao);
4345 playersao->disconnected();
4353 if(player != NULL && reason != CDR_DENY)
4355 std::ostringstream os(std::ios_base::binary);
4356 std::list<u16> clients = m_clients.getClientIDs();
4358 for(std::list<u16>::iterator
4359 i = clients.begin();
4360 i != clients.end(); ++i)
4363 Player *player = m_env->getPlayer(*i);
4366 // Get name of player
4367 os<<player->getName()<<" ";
4370 actionstream<<player->getName()<<" "
4371 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4372 <<" List of players: "<<os.str()<<std::endl;
4376 JMutexAutoLock env_lock(m_env_mutex);
4377 m_clients.DeleteClient(peer_id);
4381 // Send leave chat message to all remaining clients
4382 if(message.length() != 0)
4383 SendChatMessage(PEER_ID_INEXISTENT,message);
4386 void Server::UpdateCrafting(u16 peer_id)
4388 DSTACK(__FUNCTION_NAME);
4390 Player* player = m_env->getPlayer(peer_id);
4393 // Get a preview for crafting
4395 InventoryLocation loc;
4396 loc.setPlayer(player->getName());
4397 getCraftingResult(&player->inventory, preview, false, this);
4398 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4400 // Put the new preview in
4401 InventoryList *plist = player->inventory.getList("craftpreview");
4403 assert(plist->getSize() >= 1);
4404 plist->changeItem(0, preview);
4407 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4409 RemoteClient *client = getClientNoEx(peer_id,state_min);
4411 throw ClientNotFoundException("Client not found");
4415 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4417 return m_clients.getClientNoEx(peer_id, state_min);
4420 std::string Server::getPlayerName(u16 peer_id)
4422 Player *player = m_env->getPlayer(peer_id);
4424 return "[id="+itos(peer_id)+"]";
4425 return player->getName();
4428 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4430 Player *player = m_env->getPlayer(peer_id);
4433 return player->getPlayerSAO();
4436 std::wstring Server::getStatusString()
4438 std::wostringstream os(std::ios_base::binary);
4441 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4443 os<<L", uptime="<<m_uptime.get();
4445 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4446 // Information about clients
4449 std::list<u16> clients = m_clients.getClientIDs();
4450 for(std::list<u16>::iterator i = clients.begin();
4451 i != clients.end(); ++i)
4454 Player *player = m_env->getPlayer(*i);
4455 // Get name of player
4456 std::wstring name = L"unknown";
4458 name = narrow_to_wide(player->getName());
4459 // Add name to information string
4467 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4468 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4469 if(g_settings->get("motd") != "")
4470 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4474 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4476 std::set<std::string> privs;
4477 m_script->getAuth(name, NULL, &privs);
4481 bool Server::checkPriv(const std::string &name, const std::string &priv)
4483 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4484 return (privs.count(priv) != 0);
4487 void Server::reportPrivsModified(const std::string &name)
4490 std::list<u16> clients = m_clients.getClientIDs();
4491 for(std::list<u16>::iterator
4492 i = clients.begin();
4493 i != clients.end(); ++i){
4494 Player *player = m_env->getPlayer(*i);
4495 reportPrivsModified(player->getName());
4498 Player *player = m_env->getPlayer(name.c_str());
4501 SendPlayerPrivileges(player->peer_id);
4502 PlayerSAO *sao = player->getPlayerSAO();
4505 sao->updatePrivileges(
4506 getPlayerEffectivePrivs(name),
4511 void Server::reportInventoryFormspecModified(const std::string &name)
4513 Player *player = m_env->getPlayer(name.c_str());
4516 SendPlayerInventoryFormspec(player->peer_id);
4519 void Server::setIpBanned(const std::string &ip, const std::string &name)
4521 m_banmanager->add(ip, name);
4524 void Server::unsetIpBanned(const std::string &ip_or_name)
4526 m_banmanager->remove(ip_or_name);
4529 std::string Server::getBanDescription(const std::string &ip_or_name)
4531 return m_banmanager->getBanDescription(ip_or_name);
4534 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4536 Player *player = m_env->getPlayer(name);
4540 if (player->peer_id == PEER_ID_INEXISTENT)
4543 SendChatMessage(player->peer_id, msg);
4546 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4548 Player *player = m_env->getPlayer(playername);
4552 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4556 SendShowFormspecMessage(player->peer_id, formspec, formname);
4560 u32 Server::hudAdd(Player *player, HudElement *form) {
4564 u32 id = player->getFreeHudID();
4565 if (id < player->hud.size())
4566 player->hud[id] = form;
4568 player->hud.push_back(form);
4570 SendHUDAdd(player->peer_id, id, form);
4574 bool Server::hudRemove(Player *player, u32 id) {
4575 if (!player || id >= player->hud.size() || !player->hud[id])
4578 delete player->hud[id];
4579 player->hud[id] = NULL;
4581 SendHUDRemove(player->peer_id, id);
4585 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4589 SendHUDChange(player->peer_id, id, stat, data);
4593 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4597 SendHUDSetFlags(player->peer_id, flags, mask);
4598 player->hud_flags = flags;
4600 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4604 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4607 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4610 std::ostringstream os(std::ios::binary);
4611 writeS32(os, hotbar_itemcount);
4612 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4616 void Server::hudSetHotbarImage(Player *player, std::string name) {
4620 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4623 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4627 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4630 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4635 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4639 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4644 SendEyeOffset(player->peer_id, first, third);
4648 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4649 const std::string &type, const std::vector<std::string> ¶ms)
4654 SendSetSky(player->peer_id, bgcolor, type, params);
4658 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4664 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4668 void Server::notifyPlayers(const std::wstring &msg)
4670 SendChatMessage(PEER_ID_INEXISTENT,msg);
4673 void Server::spawnParticle(const char *playername, v3f pos,
4674 v3f velocity, v3f acceleration,
4675 float expirationtime, float size, bool
4676 collisiondetection, bool vertical, std::string texture)
4678 Player *player = m_env->getPlayer(playername);
4681 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4682 expirationtime, size, collisiondetection, vertical, texture);
4685 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4686 float expirationtime, float size,
4687 bool collisiondetection, bool vertical, std::string texture)
4689 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4690 expirationtime, size, collisiondetection, vertical, texture);
4693 u32 Server::addParticleSpawner(const char *playername,
4694 u16 amount, float spawntime,
4695 v3f minpos, v3f maxpos,
4696 v3f minvel, v3f maxvel,
4697 v3f minacc, v3f maxacc,
4698 float minexptime, float maxexptime,
4699 float minsize, float maxsize,
4700 bool collisiondetection, bool vertical, std::string texture)
4702 Player *player = m_env->getPlayer(playername);
4707 for(;;) // look for unused particlespawner id
4710 if (std::find(m_particlespawner_ids.begin(),
4711 m_particlespawner_ids.end(), id)
4712 == m_particlespawner_ids.end())
4714 m_particlespawner_ids.push_back(id);
4719 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4720 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4721 minexptime, maxexptime, minsize, maxsize,
4722 collisiondetection, vertical, texture, id);
4727 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4728 v3f minpos, v3f maxpos,
4729 v3f minvel, v3f maxvel,
4730 v3f minacc, v3f maxacc,
4731 float minexptime, float maxexptime,
4732 float minsize, float maxsize,
4733 bool collisiondetection, bool vertical, std::string texture)
4736 for(;;) // look for unused particlespawner id
4739 if (std::find(m_particlespawner_ids.begin(),
4740 m_particlespawner_ids.end(), id)
4741 == m_particlespawner_ids.end())
4743 m_particlespawner_ids.push_back(id);
4748 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4749 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4750 minexptime, maxexptime, minsize, maxsize,
4751 collisiondetection, vertical, texture, id);
4756 void Server::deleteParticleSpawner(const char *playername, u32 id)
4758 Player *player = m_env->getPlayer(playername);
4762 m_particlespawner_ids.erase(
4763 std::remove(m_particlespawner_ids.begin(),
4764 m_particlespawner_ids.end(), id),
4765 m_particlespawner_ids.end());
4766 SendDeleteParticleSpawner(player->peer_id, id);
4769 void Server::deleteParticleSpawnerAll(u32 id)
4771 m_particlespawner_ids.erase(
4772 std::remove(m_particlespawner_ids.begin(),
4773 m_particlespawner_ids.end(), id),
4774 m_particlespawner_ids.end());
4775 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4778 Inventory* Server::createDetachedInventory(const std::string &name)
4780 if(m_detached_inventories.count(name) > 0){
4781 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4782 delete m_detached_inventories[name];
4784 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4786 Inventory *inv = new Inventory(m_itemdef);
4788 m_detached_inventories[name] = inv;
4789 //TODO find a better way to do this
4790 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4797 BoolScopeSet(bool *dst, bool val):
4800 m_orig_state = *m_dst;
4805 *m_dst = m_orig_state;
4812 // actions: time-reversed list
4813 // Return value: success/failure
4814 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4815 std::list<std::string> *log)
4817 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4818 ServerMap *map = (ServerMap*)(&m_env->getMap());
4819 // Disable rollback report sink while reverting
4820 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4822 // Fail if no actions to handle
4823 if(actions.empty()){
4824 log->push_back("Nothing to do.");
4831 for(std::list<RollbackAction>::const_iterator
4832 i = actions.begin();
4833 i != actions.end(); i++)
4835 const RollbackAction &action = *i;
4837 bool success = action.applyRevert(map, this, this);
4840 std::ostringstream os;
4841 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4842 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4844 log->push_back(os.str());
4846 std::ostringstream os;
4847 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4848 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4850 log->push_back(os.str());
4854 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4855 <<" failed"<<std::endl;
4857 // Call it done if less than half failed
4858 return num_failed <= num_tried/2;
4861 // IGameDef interface
4863 IItemDefManager* Server::getItemDefManager()
4867 INodeDefManager* Server::getNodeDefManager()
4871 ICraftDefManager* Server::getCraftDefManager()
4875 ITextureSource* Server::getTextureSource()
4879 IShaderSource* Server::getShaderSource()
4883 u16 Server::allocateUnknownNodeId(const std::string &name)
4885 return m_nodedef->allocateDummy(name);
4887 ISoundManager* Server::getSoundManager()
4889 return &dummySoundManager;
4891 MtEventManager* Server::getEventManager()
4895 IRollbackReportSink* Server::getRollbackReportSink()
4897 if(!m_enable_rollback_recording)
4899 if(!m_rollback_sink_enabled)
4904 IWritableItemDefManager* Server::getWritableItemDefManager()
4908 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4912 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4917 const ModSpec* Server::getModSpec(const std::string &modname)
4919 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4920 i != m_mods.end(); i++){
4921 const ModSpec &mod = *i;
4922 if(mod.name == modname)
4927 void Server::getModNames(std::list<std::string> &modlist)
4929 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4931 modlist.push_back(i->name);
4934 std::string Server::getBuiltinLuaPath()
4936 return porting::path_share + DIR_DELIM + "builtin";
4939 v3f findSpawnPos(ServerMap &map)
4941 //return v3f(50,50,50)*BS;
4946 nodepos = v2s16(0,0);
4951 s16 water_level = map.getWaterLevel();
4953 // Try to find a good place a few times
4954 for(s32 i=0; i<1000; i++)
4957 // We're going to try to throw the player to this position
4958 v2s16 nodepos2d = v2s16(
4959 -range + (myrand() % (range * 2)),
4960 -range + (myrand() % (range * 2)));
4962 // Get ground height at point
4963 s16 groundheight = map.findGroundLevel(nodepos2d);
4964 if (groundheight <= water_level) // Don't go underwater
4966 if (groundheight > water_level + 6) // Don't go to high places
4969 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4970 bool is_good = false;
4972 for (s32 i = 0; i < 10; i++) {
4973 v3s16 blockpos = getNodeBlockPos(nodepos);
4974 map.emergeBlock(blockpos, true);
4975 content_t c = map.getNodeNoEx(nodepos).getContent();
4976 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4978 if (air_count >= 2){
4986 // Found a good place
4987 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4993 return intToFloat(nodepos, BS);
4996 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4998 RemotePlayer *player = NULL;
4999 bool newplayer = false;
5002 Try to get an existing player
5004 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5006 // If player is already connected, cancel
5007 if(player != NULL && player->peer_id != 0)
5009 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5014 If player with the wanted peer_id already exists, cancel.
5016 if(m_env->getPlayer(peer_id) != NULL)
5018 infostream<<"emergePlayer(): Player with wrong name but same"
5019 " peer_id already exists"<<std::endl;
5024 Create a new player if it doesn't exist yet
5029 player = new RemotePlayer(this);
5030 player->updateName(name);
5032 /* Set player position */
5033 infostream<<"Server: Finding spawn place for player \""
5034 <<name<<"\""<<std::endl;
5035 v3f pos = findSpawnPos(m_env->getServerMap());
5036 player->setPosition(pos);
5038 /* Add player to environment */
5039 m_env->addPlayer(player);
5043 Create a new player active object
5045 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5046 getPlayerEffectivePrivs(player->getName()),
5049 /* Clean up old HUD elements from previous sessions */
5050 player->hud.clear();
5052 /* Add object to environment */
5053 m_env->addActiveObject(playersao);
5057 m_script->on_newplayer(playersao);
5062 void dedicated_server_loop(Server &server, bool &kill)
5064 DSTACK(__FUNCTION_NAME);
5066 verbosestream<<"dedicated_server_loop()"<<std::endl;
5068 IntervalLimiter m_profiler_interval;
5072 float steplen = g_settings->getFloat("dedicated_server_step");
5073 // This is kind of a hack but can be done like this
5074 // because server.step() is very light
5076 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5077 sleep_ms((int)(steplen*1000.0));
5079 server.step(steplen);
5081 if(server.getShutdownRequested() || kill)
5083 infostream<<"Dedicated server quitting"<<std::endl;
5085 if(g_settings->getBool("server_announce") == true)
5086 ServerList::sendAnnounce("delete");
5094 float profiler_print_interval =
5095 g_settings->getFloat("profiler_print_interval");
5096 if(profiler_print_interval != 0)
5098 if(m_profiler_interval.step(steplen, profiler_print_interval))
5100 infostream<<"Profiler:"<<std::endl;
5101 g_profiler->print(infostream);
5102 g_profiler->clear();