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);
2900 *uptime = client->uptime();
2901 *ser_vers = client->serialization_version;
2902 *prot_vers = client->net_proto_version;
2904 *major = client->getMajor();
2905 *minor = client->getMinor();
2906 *patch = client->getPatch();
2907 *vers_string = client->getPatch();
2914 void Server::handlePeerChanges()
2916 while(m_peer_change_queue.size() > 0)
2918 con::PeerChange c = m_peer_change_queue.pop_front();
2920 verbosestream<<"Server: Handling peer change: "
2921 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2926 case con::PEER_ADDED:
2927 m_clients.CreateClient(c.peer_id);
2930 case con::PEER_REMOVED:
2931 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2935 assert("Invalid peer change event received!" == 0);
2941 void Server::SendMovement(u16 peer_id)
2943 DSTACK(__FUNCTION_NAME);
2944 std::ostringstream os(std::ios_base::binary);
2946 writeU16(os, TOCLIENT_MOVEMENT);
2947 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2948 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2949 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2950 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2951 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2952 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2953 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2954 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2955 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2956 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2957 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2958 writeF1000(os, g_settings->getFloat("movement_gravity"));
2961 std::string s = os.str();
2962 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2964 m_clients.send(peer_id, 0, data, true);
2967 void Server::SendHP(u16 peer_id, u8 hp)
2969 DSTACK(__FUNCTION_NAME);
2970 std::ostringstream os(std::ios_base::binary);
2972 writeU16(os, TOCLIENT_HP);
2976 std::string s = os.str();
2977 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2979 m_clients.send(peer_id, 0, data, true);
2982 void Server::SendBreath(u16 peer_id, u16 breath)
2984 DSTACK(__FUNCTION_NAME);
2985 std::ostringstream os(std::ios_base::binary);
2987 writeU16(os, TOCLIENT_BREATH);
2988 writeU16(os, breath);
2991 std::string s = os.str();
2992 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2994 m_clients.send(peer_id, 0, data, true);
2997 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2999 DSTACK(__FUNCTION_NAME);
3000 std::ostringstream os(std::ios_base::binary);
3002 writeU16(os, TOCLIENT_ACCESS_DENIED);
3003 os<<serializeWideString(reason);
3006 std::string s = os.str();
3007 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3009 m_clients.send(peer_id, 0, data, true);
3012 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3013 v3f camera_point_target)
3015 DSTACK(__FUNCTION_NAME);
3016 std::ostringstream os(std::ios_base::binary);
3018 writeU16(os, TOCLIENT_DEATHSCREEN);
3019 writeU8(os, set_camera_point_target);
3020 writeV3F1000(os, camera_point_target);
3023 std::string s = os.str();
3024 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3026 m_clients.send(peer_id, 0, data, true);
3029 void Server::SendItemDef(u16 peer_id,
3030 IItemDefManager *itemdef, u16 protocol_version)
3032 DSTACK(__FUNCTION_NAME);
3033 std::ostringstream os(std::ios_base::binary);
3037 u32 length of the next item
3038 zlib-compressed serialized ItemDefManager
3040 writeU16(os, TOCLIENT_ITEMDEF);
3041 std::ostringstream tmp_os(std::ios::binary);
3042 itemdef->serialize(tmp_os, protocol_version);
3043 std::ostringstream tmp_os2(std::ios::binary);
3044 compressZlib(tmp_os.str(), tmp_os2);
3045 os<<serializeLongString(tmp_os2.str());
3048 std::string s = os.str();
3049 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3050 <<"): size="<<s.size()<<std::endl;
3051 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3053 m_clients.send(peer_id, 0, data, true);
3056 void Server::SendNodeDef(u16 peer_id,
3057 INodeDefManager *nodedef, u16 protocol_version)
3059 DSTACK(__FUNCTION_NAME);
3060 std::ostringstream os(std::ios_base::binary);
3064 u32 length of the next item
3065 zlib-compressed serialized NodeDefManager
3067 writeU16(os, TOCLIENT_NODEDEF);
3068 std::ostringstream tmp_os(std::ios::binary);
3069 nodedef->serialize(tmp_os, protocol_version);
3070 std::ostringstream tmp_os2(std::ios::binary);
3071 compressZlib(tmp_os.str(), tmp_os2);
3072 os<<serializeLongString(tmp_os2.str());
3075 std::string s = os.str();
3076 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3077 <<"): size="<<s.size()<<std::endl;
3078 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3080 m_clients.send(peer_id, 0, data, true);
3084 Non-static send methods
3087 void Server::SendInventory(u16 peer_id)
3089 DSTACK(__FUNCTION_NAME);
3091 PlayerSAO *playersao = getPlayerSAO(peer_id);
3094 playersao->m_inventory_not_sent = false;
3100 std::ostringstream os;
3101 playersao->getInventory()->serialize(os);
3103 std::string s = os.str();
3105 SharedBuffer<u8> data(s.size()+2);
3106 writeU16(&data[0], TOCLIENT_INVENTORY);
3107 memcpy(&data[2], s.c_str(), s.size());
3110 m_clients.send(peer_id, 0, data, true);
3113 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3115 DSTACK(__FUNCTION_NAME);
3117 std::ostringstream os(std::ios_base::binary);
3121 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3122 os.write((char*)buf, 2);
3125 writeU16(buf, message.size());
3126 os.write((char*)buf, 2);
3129 for(u32 i=0; i<message.size(); i++)
3133 os.write((char*)buf, 2);
3137 std::string s = os.str();
3138 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3140 if (peer_id != PEER_ID_INEXISTENT)
3143 m_clients.send(peer_id, 0, data, true);
3147 m_clients.sendToAll(0,data,true);
3151 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3152 const std::string &formname)
3154 DSTACK(__FUNCTION_NAME);
3156 std::ostringstream os(std::ios_base::binary);
3160 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3161 os.write((char*)buf, 2);
3162 os<<serializeLongString(formspec);
3163 os<<serializeString(formname);
3166 std::string s = os.str();
3167 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3169 m_clients.send(peer_id, 0, data, true);
3172 // Spawns a particle on peer with peer_id
3173 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3174 float expirationtime, float size, bool collisiondetection,
3175 bool vertical, std::string texture)
3177 DSTACK(__FUNCTION_NAME);
3179 std::ostringstream os(std::ios_base::binary);
3180 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3181 writeV3F1000(os, pos);
3182 writeV3F1000(os, velocity);
3183 writeV3F1000(os, acceleration);
3184 writeF1000(os, expirationtime);
3185 writeF1000(os, size);
3186 writeU8(os, collisiondetection);
3187 os<<serializeLongString(texture);
3188 writeU8(os, vertical);
3191 std::string s = os.str();
3192 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3194 if (peer_id != PEER_ID_INEXISTENT)
3197 m_clients.send(peer_id, 0, data, true);
3201 m_clients.sendToAll(0,data,true);
3205 // Adds a ParticleSpawner on peer with peer_id
3206 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3207 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3208 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3210 DSTACK(__FUNCTION_NAME);
3212 std::ostringstream os(std::ios_base::binary);
3213 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3215 writeU16(os, amount);
3216 writeF1000(os, spawntime);
3217 writeV3F1000(os, minpos);
3218 writeV3F1000(os, maxpos);
3219 writeV3F1000(os, minvel);
3220 writeV3F1000(os, maxvel);
3221 writeV3F1000(os, minacc);
3222 writeV3F1000(os, maxacc);
3223 writeF1000(os, minexptime);
3224 writeF1000(os, maxexptime);
3225 writeF1000(os, minsize);
3226 writeF1000(os, maxsize);
3227 writeU8(os, collisiondetection);
3228 os<<serializeLongString(texture);
3230 writeU8(os, vertical);
3233 std::string s = os.str();
3234 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3236 if (peer_id != PEER_ID_INEXISTENT)
3239 m_clients.send(peer_id, 0, data, true);
3242 m_clients.sendToAll(0,data,true);
3246 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3248 DSTACK(__FUNCTION_NAME);
3250 std::ostringstream os(std::ios_base::binary);
3251 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3256 std::string s = os.str();
3257 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3259 if (peer_id != PEER_ID_INEXISTENT) {
3261 m_clients.send(peer_id, 0, data, true);
3264 m_clients.sendToAll(0,data,true);
3269 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3271 std::ostringstream os(std::ios_base::binary);
3274 writeU16(os, TOCLIENT_HUDADD);
3276 writeU8(os, (u8)form->type);
3277 writeV2F1000(os, form->pos);
3278 os << serializeString(form->name);
3279 writeV2F1000(os, form->scale);
3280 os << serializeString(form->text);
3281 writeU32(os, form->number);
3282 writeU32(os, form->item);
3283 writeU32(os, form->dir);
3284 writeV2F1000(os, form->align);
3285 writeV2F1000(os, form->offset);
3286 writeV3F1000(os, form->world_pos);
3287 writeV2S32(os,form->size);
3290 std::string s = os.str();
3291 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3293 m_clients.send(peer_id, 1, data, true);
3296 void Server::SendHUDRemove(u16 peer_id, u32 id)
3298 std::ostringstream os(std::ios_base::binary);
3301 writeU16(os, TOCLIENT_HUDRM);
3305 std::string s = os.str();
3306 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3309 m_clients.send(peer_id, 1, data, true);
3312 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3314 std::ostringstream os(std::ios_base::binary);
3317 writeU16(os, TOCLIENT_HUDCHANGE);
3319 writeU8(os, (u8)stat);
3322 case HUD_STAT_SCALE:
3323 case HUD_STAT_ALIGN:
3324 case HUD_STAT_OFFSET:
3325 writeV2F1000(os, *(v2f *)value);
3329 os << serializeString(*(std::string *)value);
3331 case HUD_STAT_WORLD_POS:
3332 writeV3F1000(os, *(v3f *)value);
3335 writeV2S32(os,*(v2s32 *)value);
3337 case HUD_STAT_NUMBER:
3341 writeU32(os, *(u32 *)value);
3346 std::string s = os.str();
3347 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3349 m_clients.send(peer_id, 0, data, true);
3352 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3354 std::ostringstream os(std::ios_base::binary);
3357 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3358 writeU32(os, flags);
3362 std::string s = os.str();
3363 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3365 m_clients.send(peer_id, 0, data, true);
3368 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3370 std::ostringstream os(std::ios_base::binary);
3373 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3374 writeU16(os, param);
3375 os<<serializeString(value);
3378 std::string s = os.str();
3379 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3381 m_clients.send(peer_id, 0, data, true);
3384 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3385 const std::string &type, const std::vector<std::string> ¶ms)
3387 std::ostringstream os(std::ios_base::binary);
3390 writeU16(os, TOCLIENT_SET_SKY);
3391 writeARGB8(os, bgcolor);
3392 os<<serializeString(type);
3393 writeU16(os, params.size());
3394 for(size_t i=0; i<params.size(); i++)
3395 os<<serializeString(params[i]);
3398 std::string s = os.str();
3399 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3401 m_clients.send(peer_id, 0, data, true);
3404 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3407 std::ostringstream os(std::ios_base::binary);
3410 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3411 writeU8(os, do_override);
3412 writeU16(os, ratio*65535);
3415 std::string s = os.str();
3416 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3418 m_clients.send(peer_id, 0, data, true);
3421 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3423 DSTACK(__FUNCTION_NAME);
3426 SharedBuffer<u8> data(2+2+4);
3427 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3428 writeU16(&data[2], time);
3429 writeF1000(&data[4], time_speed);
3431 if (peer_id == PEER_ID_INEXISTENT) {
3432 m_clients.sendToAll(0,data,true);
3436 m_clients.send(peer_id, 0, data, true);
3440 void Server::SendPlayerHP(u16 peer_id)
3442 DSTACK(__FUNCTION_NAME);
3443 PlayerSAO *playersao = getPlayerSAO(peer_id);
3445 playersao->m_hp_not_sent = false;
3446 SendHP(peer_id, playersao->getHP());
3447 m_script->player_event(playersao,"health_changed");
3449 // Send to other clients
3450 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3451 ActiveObjectMessage aom(playersao->getId(), true, str);
3452 playersao->m_messages_out.push_back(aom);
3455 void Server::SendPlayerBreath(u16 peer_id)
3457 DSTACK(__FUNCTION_NAME);
3458 PlayerSAO *playersao = getPlayerSAO(peer_id);
3460 playersao->m_breath_not_sent = false;
3461 m_script->player_event(playersao,"breath_changed");
3462 SendBreath(peer_id, playersao->getBreath());
3465 void Server::SendMovePlayer(u16 peer_id)
3467 DSTACK(__FUNCTION_NAME);
3468 Player *player = m_env->getPlayer(peer_id);
3471 std::ostringstream os(std::ios_base::binary);
3472 writeU16(os, TOCLIENT_MOVE_PLAYER);
3473 writeV3F1000(os, player->getPosition());
3474 writeF1000(os, player->getPitch());
3475 writeF1000(os, player->getYaw());
3478 v3f pos = player->getPosition();
3479 f32 pitch = player->getPitch();
3480 f32 yaw = player->getYaw();
3481 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3482 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3489 std::string s = os.str();
3490 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3492 m_clients.send(peer_id, 0, data, true);
3495 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3497 std::ostringstream os(std::ios_base::binary);
3499 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3500 writeV2S32(os, animation_frames[0]);
3501 writeV2S32(os, animation_frames[1]);
3502 writeV2S32(os, animation_frames[2]);
3503 writeV2S32(os, animation_frames[3]);
3504 writeF1000(os, animation_speed);
3507 std::string s = os.str();
3508 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3510 m_clients.send(peer_id, 0, data, true);
3513 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3515 std::ostringstream os(std::ios_base::binary);
3517 writeU16(os, TOCLIENT_EYE_OFFSET);
3518 writeV3F1000(os, first);
3519 writeV3F1000(os, third);
3522 std::string s = os.str();
3523 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3525 m_clients.send(peer_id, 0, data, true);
3527 void Server::SendPlayerPrivileges(u16 peer_id)
3529 Player *player = m_env->getPlayer(peer_id);
3531 if(player->peer_id == PEER_ID_INEXISTENT)
3534 std::set<std::string> privs;
3535 m_script->getAuth(player->getName(), NULL, &privs);
3537 std::ostringstream os(std::ios_base::binary);
3538 writeU16(os, TOCLIENT_PRIVILEGES);
3539 writeU16(os, privs.size());
3540 for(std::set<std::string>::const_iterator i = privs.begin();
3541 i != privs.end(); i++){
3542 os<<serializeString(*i);
3546 std::string s = os.str();
3547 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3549 m_clients.send(peer_id, 0, data, true);
3552 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3554 Player *player = m_env->getPlayer(peer_id);
3556 if(player->peer_id == PEER_ID_INEXISTENT)
3559 std::ostringstream os(std::ios_base::binary);
3560 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3561 os<<serializeLongString(player->inventory_formspec);
3564 std::string s = os.str();
3565 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3567 m_clients.send(peer_id, 0, data, true);
3570 s32 Server::playSound(const SimpleSoundSpec &spec,
3571 const ServerSoundParams ¶ms)
3573 // Find out initial position of sound
3574 bool pos_exists = false;
3575 v3f pos = params.getPos(m_env, &pos_exists);
3576 // If position is not found while it should be, cancel sound
3577 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3580 // Filter destination clients
3581 std::list<u16> dst_clients;
3582 if(params.to_player != "")
3584 Player *player = m_env->getPlayer(params.to_player.c_str());
3586 infostream<<"Server::playSound: Player \""<<params.to_player
3587 <<"\" not found"<<std::endl;
3590 if(player->peer_id == PEER_ID_INEXISTENT){
3591 infostream<<"Server::playSound: Player \""<<params.to_player
3592 <<"\" not connected"<<std::endl;
3595 dst_clients.push_back(player->peer_id);
3599 std::list<u16> clients = m_clients.getClientIDs();
3601 for(std::list<u16>::iterator
3602 i = clients.begin(); i != clients.end(); ++i)
3604 Player *player = m_env->getPlayer(*i);
3608 if(player->getPosition().getDistanceFrom(pos) >
3609 params.max_hear_distance)
3612 dst_clients.push_back(*i);
3615 if(dst_clients.size() == 0)
3619 s32 id = m_next_sound_id++;
3620 // The sound will exist as a reference in m_playing_sounds
3621 m_playing_sounds[id] = ServerPlayingSound();
3622 ServerPlayingSound &psound = m_playing_sounds[id];
3623 psound.params = params;
3624 for(std::list<u16>::iterator i = dst_clients.begin();
3625 i != dst_clients.end(); i++)
3626 psound.clients.insert(*i);
3628 std::ostringstream os(std::ios_base::binary);
3629 writeU16(os, TOCLIENT_PLAY_SOUND);
3631 os<<serializeString(spec.name);
3632 writeF1000(os, spec.gain * params.gain);
3633 writeU8(os, params.type);
3634 writeV3F1000(os, pos);
3635 writeU16(os, params.object);
3636 writeU8(os, params.loop);
3638 std::string s = os.str();
3639 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3641 for(std::list<u16>::iterator i = dst_clients.begin();
3642 i != dst_clients.end(); i++){
3644 m_clients.send(*i, 0, data, true);
3648 void Server::stopSound(s32 handle)
3650 // Get sound reference
3651 std::map<s32, ServerPlayingSound>::iterator i =
3652 m_playing_sounds.find(handle);
3653 if(i == m_playing_sounds.end())
3655 ServerPlayingSound &psound = i->second;
3657 std::ostringstream os(std::ios_base::binary);
3658 writeU16(os, TOCLIENT_STOP_SOUND);
3659 writeS32(os, handle);
3661 std::string s = os.str();
3662 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3664 for(std::set<u16>::iterator i = psound.clients.begin();
3665 i != psound.clients.end(); i++){
3667 m_clients.send(*i, 0, data, true);
3669 // Remove sound reference
3670 m_playing_sounds.erase(i);
3673 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3674 std::list<u16> *far_players, float far_d_nodes)
3676 float maxd = far_d_nodes*BS;
3677 v3f p_f = intToFloat(p, BS);
3681 SharedBuffer<u8> reply(replysize);
3682 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3683 writeS16(&reply[2], p.X);
3684 writeS16(&reply[4], p.Y);
3685 writeS16(&reply[6], p.Z);
3687 std::list<u16> clients = m_clients.getClientIDs();
3688 for(std::list<u16>::iterator
3689 i = clients.begin();
3690 i != clients.end(); ++i)
3695 Player *player = m_env->getPlayer(*i);
3698 // If player is far away, only set modified blocks not sent
3699 v3f player_pos = player->getPosition();
3700 if(player_pos.getDistanceFrom(p_f) > maxd)
3702 far_players->push_back(*i);
3709 m_clients.send(*i, 0, reply, true);
3713 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3714 std::list<u16> *far_players, float far_d_nodes,
3715 bool remove_metadata)
3717 float maxd = far_d_nodes*BS;
3718 v3f p_f = intToFloat(p, BS);
3720 std::list<u16> clients = m_clients.getClientIDs();
3721 for(std::list<u16>::iterator
3722 i = clients.begin();
3723 i != clients.end(); ++i)
3729 Player *player = m_env->getPlayer(*i);
3732 // If player is far away, only set modified blocks not sent
3733 v3f player_pos = player->getPosition();
3734 if(player_pos.getDistanceFrom(p_f) > maxd)
3736 far_players->push_back(*i);
3741 SharedBuffer<u8> reply(0);
3743 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3747 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3748 reply = SharedBuffer<u8>(replysize);
3749 writeU16(&reply[0], TOCLIENT_ADDNODE);
3750 writeS16(&reply[2], p.X);
3751 writeS16(&reply[4], p.Y);
3752 writeS16(&reply[6], p.Z);
3753 n.serialize(&reply[8], client->serialization_version);
3754 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3755 writeU8(&reply[index], remove_metadata ? 0 : 1);
3757 if (!remove_metadata) {
3758 if (client->net_proto_version <= 21) {
3759 // Old clients always clear metadata; fix it
3760 // by sending the full block again.
3761 client->SetBlockNotSent(p);
3768 if (reply.getSize() > 0)
3769 m_clients.send(*i, 0, reply, true);
3773 void Server::setBlockNotSent(v3s16 p)
3775 std::list<u16> clients = m_clients.getClientIDs();
3777 for(std::list<u16>::iterator
3778 i = clients.begin();
3779 i != clients.end(); ++i)
3781 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3782 client->SetBlockNotSent(p);
3787 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3789 DSTACK(__FUNCTION_NAME);
3791 v3s16 p = block->getPos();
3795 bool completely_air = true;
3796 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3797 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3798 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3800 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3802 completely_air = false;
3803 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3808 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3810 infostream<<"[completely air] ";
3811 infostream<<std::endl;
3815 Create a packet with the block in the right format
3818 std::ostringstream os(std::ios_base::binary);
3819 block->serialize(os, ver, false);
3820 block->serializeNetworkSpecific(os, net_proto_version);
3821 std::string s = os.str();
3822 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3824 u32 replysize = 8 + blockdata.getSize();
3825 SharedBuffer<u8> reply(replysize);
3826 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3827 writeS16(&reply[2], p.X);
3828 writeS16(&reply[4], p.Y);
3829 writeS16(&reply[6], p.Z);
3830 memcpy(&reply[8], *blockdata, blockdata.getSize());
3832 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3833 <<": \tpacket size: "<<replysize<<std::endl;*/
3838 m_clients.send(peer_id, 2, reply, true);
3841 void Server::SendBlocks(float dtime)
3843 DSTACK(__FUNCTION_NAME);
3845 JMutexAutoLock envlock(m_env_mutex);
3846 //TODO check if one big lock could be faster then multiple small ones
3848 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3850 std::vector<PrioritySortedBlockTransfer> queue;
3852 s32 total_sending = 0;
3855 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3857 std::list<u16> clients = m_clients.getClientIDs();
3860 for(std::list<u16>::iterator
3861 i = clients.begin();
3862 i != clients.end(); ++i)
3864 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3869 total_sending += client->SendingCount();
3870 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3876 // Lowest priority number comes first.
3877 // Lowest is most important.
3878 std::sort(queue.begin(), queue.end());
3881 for(u32 i=0; i<queue.size(); i++)
3883 //TODO: Calculate limit dynamically
3884 if(total_sending >= g_settings->getS32
3885 ("max_simultaneous_block_sends_server_total"))
3888 PrioritySortedBlockTransfer q = queue[i];
3890 MapBlock *block = NULL;
3893 block = m_env->getMap().getBlockNoCreate(q.pos);
3895 catch(InvalidPositionException &e)
3900 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3905 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3907 client->SentBlock(q.pos);
3913 void Server::fillMediaCache()
3915 DSTACK(__FUNCTION_NAME);
3917 infostream<<"Server: Calculating media file checksums"<<std::endl;
3919 // Collect all media file paths
3920 std::list<std::string> paths;
3921 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3922 i != m_mods.end(); i++){
3923 const ModSpec &mod = *i;
3924 paths.push_back(mod.path + DIR_DELIM + "textures");
3925 paths.push_back(mod.path + DIR_DELIM + "sounds");
3926 paths.push_back(mod.path + DIR_DELIM + "media");
3927 paths.push_back(mod.path + DIR_DELIM + "models");
3929 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3931 // Collect media file information from paths into cache
3932 for(std::list<std::string>::iterator i = paths.begin();
3933 i != paths.end(); i++)
3935 std::string mediapath = *i;
3936 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3937 for(u32 j=0; j<dirlist.size(); j++){
3938 if(dirlist[j].dir) // Ignode dirs
3940 std::string filename = dirlist[j].name;
3941 // If name contains illegal characters, ignore the file
3942 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3943 infostream<<"Server: ignoring illegal file name: \""
3944 <<filename<<"\""<<std::endl;
3947 // If name is not in a supported format, ignore it
3948 const char *supported_ext[] = {
3949 ".png", ".jpg", ".bmp", ".tga",
3950 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3952 ".x", ".b3d", ".md2", ".obj",
3955 if(removeStringEnd(filename, supported_ext) == ""){
3956 infostream<<"Server: ignoring unsupported file extension: \""
3957 <<filename<<"\""<<std::endl;
3960 // Ok, attempt to load the file and add to cache
3961 std::string filepath = mediapath + DIR_DELIM + filename;
3963 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3964 if(fis.good() == false){
3965 errorstream<<"Server::fillMediaCache(): Could not open \""
3966 <<filename<<"\" for reading"<<std::endl;
3969 std::ostringstream tmp_os(std::ios_base::binary);
3973 fis.read(buf, 1024);
3974 std::streamsize len = fis.gcount();
3975 tmp_os.write(buf, len);
3984 errorstream<<"Server::fillMediaCache(): Failed to read \""
3985 <<filename<<"\""<<std::endl;
3988 if(tmp_os.str().length() == 0){
3989 errorstream<<"Server::fillMediaCache(): Empty file \""
3990 <<filepath<<"\""<<std::endl;
3995 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3997 unsigned char *digest = sha1.getDigest();
3998 std::string sha1_base64 = base64_encode(digest, 20);
3999 std::string sha1_hex = hex_encode((char*)digest, 20);
4003 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4004 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4009 struct SendableMediaAnnouncement
4012 std::string sha1_digest;
4014 SendableMediaAnnouncement(const std::string &name_="",
4015 const std::string &sha1_digest_=""):
4017 sha1_digest(sha1_digest_)
4021 void Server::sendMediaAnnouncement(u16 peer_id)
4023 DSTACK(__FUNCTION_NAME);
4025 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4028 std::list<SendableMediaAnnouncement> file_announcements;
4030 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4031 i != m_media.end(); i++){
4033 file_announcements.push_back(
4034 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4038 std::ostringstream os(std::ios_base::binary);
4046 u16 length of sha1_digest
4051 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4052 writeU16(os, file_announcements.size());
4054 for(std::list<SendableMediaAnnouncement>::iterator
4055 j = file_announcements.begin();
4056 j != file_announcements.end(); ++j){
4057 os<<serializeString(j->name);
4058 os<<serializeString(j->sha1_digest);
4060 os<<serializeString(g_settings->get("remote_media"));
4063 std::string s = os.str();
4064 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4067 m_clients.send(peer_id, 0, data, true);
4070 struct SendableMedia
4076 SendableMedia(const std::string &name_="", const std::string &path_="",
4077 const std::string &data_=""):
4084 void Server::sendRequestedMedia(u16 peer_id,
4085 const std::list<std::string> &tosend)
4087 DSTACK(__FUNCTION_NAME);
4089 verbosestream<<"Server::sendRequestedMedia(): "
4090 <<"Sending files to client"<<std::endl;
4094 // Put 5kB in one bunch (this is not accurate)
4095 u32 bytes_per_bunch = 5000;
4097 std::vector< std::list<SendableMedia> > file_bunches;
4098 file_bunches.push_back(std::list<SendableMedia>());
4100 u32 file_size_bunch_total = 0;
4102 for(std::list<std::string>::const_iterator i = tosend.begin();
4103 i != tosend.end(); ++i)
4105 const std::string &name = *i;
4107 if(m_media.find(name) == m_media.end()){
4108 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4109 <<"unknown file \""<<(name)<<"\""<<std::endl;
4113 //TODO get path + name
4114 std::string tpath = m_media[name].path;
4117 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4118 if(fis.good() == false){
4119 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4120 <<tpath<<"\" for reading"<<std::endl;
4123 std::ostringstream tmp_os(std::ios_base::binary);
4127 fis.read(buf, 1024);
4128 std::streamsize len = fis.gcount();
4129 tmp_os.write(buf, len);
4130 file_size_bunch_total += len;
4139 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4140 <<name<<"\""<<std::endl;
4143 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4144 <<tname<<"\""<<std::endl;*/
4146 file_bunches[file_bunches.size()-1].push_back(
4147 SendableMedia(name, tpath, tmp_os.str()));
4149 // Start next bunch if got enough data
4150 if(file_size_bunch_total >= bytes_per_bunch){
4151 file_bunches.push_back(std::list<SendableMedia>());
4152 file_size_bunch_total = 0;
4157 /* Create and send packets */
4159 u32 num_bunches = file_bunches.size();
4160 for(u32 i=0; i<num_bunches; i++)
4162 std::ostringstream os(std::ios_base::binary);
4166 u16 total number of texture bunches
4167 u16 index of this bunch
4168 u32 number of files in this bunch
4177 writeU16(os, TOCLIENT_MEDIA);
4178 writeU16(os, num_bunches);
4180 writeU32(os, file_bunches[i].size());
4182 for(std::list<SendableMedia>::iterator
4183 j = file_bunches[i].begin();
4184 j != file_bunches[i].end(); ++j){
4185 os<<serializeString(j->name);
4186 os<<serializeLongString(j->data);
4190 std::string s = os.str();
4191 verbosestream<<"Server::sendRequestedMedia(): bunch "
4192 <<i<<"/"<<num_bunches
4193 <<" files="<<file_bunches[i].size()
4194 <<" size=" <<s.size()<<std::endl;
4195 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4197 m_clients.send(peer_id, 2, data, true);
4201 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4203 if(m_detached_inventories.count(name) == 0){
4204 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4207 Inventory *inv = m_detached_inventories[name];
4209 std::ostringstream os(std::ios_base::binary);
4210 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4211 os<<serializeString(name);
4215 std::string s = os.str();
4216 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4218 if (peer_id != PEER_ID_INEXISTENT)
4221 m_clients.send(peer_id, 0, data, true);
4225 m_clients.sendToAll(0,data,true);
4229 void Server::sendDetachedInventories(u16 peer_id)
4231 DSTACK(__FUNCTION_NAME);
4233 for(std::map<std::string, Inventory*>::iterator
4234 i = m_detached_inventories.begin();
4235 i != m_detached_inventories.end(); i++){
4236 const std::string &name = i->first;
4237 //Inventory *inv = i->second;
4238 sendDetachedInventory(name, peer_id);
4246 void Server::DiePlayer(u16 peer_id)
4248 DSTACK(__FUNCTION_NAME);
4250 PlayerSAO *playersao = getPlayerSAO(peer_id);
4253 infostream<<"Server::DiePlayer(): Player "
4254 <<playersao->getPlayer()->getName()
4255 <<" dies"<<std::endl;
4257 playersao->setHP(0);
4259 // Trigger scripted stuff
4260 m_script->on_dieplayer(playersao);
4262 SendPlayerHP(peer_id);
4263 SendDeathscreen(peer_id, false, v3f(0,0,0));
4266 void Server::RespawnPlayer(u16 peer_id)
4268 DSTACK(__FUNCTION_NAME);
4270 PlayerSAO *playersao = getPlayerSAO(peer_id);
4273 infostream<<"Server::RespawnPlayer(): Player "
4274 <<playersao->getPlayer()->getName()
4275 <<" respawns"<<std::endl;
4277 playersao->setHP(PLAYER_MAX_HP);
4279 bool repositioned = m_script->on_respawnplayer(playersao);
4281 v3f pos = findSpawnPos(m_env->getServerMap());
4282 playersao->setPos(pos);
4286 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4288 DSTACK(__FUNCTION_NAME);
4290 SendAccessDenied(peer_id, reason);
4291 m_clients.event(peer_id,SetDenied);
4292 m_con.DisconnectPeer(peer_id);
4295 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4297 DSTACK(__FUNCTION_NAME);
4298 std::wstring message;
4301 Clear references to playing sounds
4303 for(std::map<s32, ServerPlayingSound>::iterator
4304 i = m_playing_sounds.begin();
4305 i != m_playing_sounds.end();)
4307 ServerPlayingSound &psound = i->second;
4308 psound.clients.erase(peer_id);
4309 if(psound.clients.size() == 0)
4310 m_playing_sounds.erase(i++);
4315 Player *player = m_env->getPlayer(peer_id);
4317 // Collect information about leaving in chat
4319 if(player != NULL && reason != CDR_DENY)
4321 std::wstring name = narrow_to_wide(player->getName());
4324 message += L" left the game.";
4325 if(reason == CDR_TIMEOUT)
4326 message += L" (timed out)";
4330 /* Run scripts and remove from environment */
4334 PlayerSAO *playersao = player->getPlayerSAO();
4337 m_script->on_leaveplayer(playersao);
4339 playersao->disconnected();
4347 if(player != NULL && reason != CDR_DENY)
4349 std::ostringstream os(std::ios_base::binary);
4350 std::list<u16> clients = m_clients.getClientIDs();
4352 for(std::list<u16>::iterator
4353 i = clients.begin();
4354 i != clients.end(); ++i)
4357 Player *player = m_env->getPlayer(*i);
4360 // Get name of player
4361 os<<player->getName()<<" ";
4364 actionstream<<player->getName()<<" "
4365 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4366 <<" List of players: "<<os.str()<<std::endl;
4370 JMutexAutoLock env_lock(m_env_mutex);
4371 m_clients.DeleteClient(peer_id);
4375 // Send leave chat message to all remaining clients
4376 if(message.length() != 0)
4377 SendChatMessage(PEER_ID_INEXISTENT,message);
4380 void Server::UpdateCrafting(u16 peer_id)
4382 DSTACK(__FUNCTION_NAME);
4384 Player* player = m_env->getPlayer(peer_id);
4387 // Get a preview for crafting
4389 InventoryLocation loc;
4390 loc.setPlayer(player->getName());
4391 getCraftingResult(&player->inventory, preview, false, this);
4392 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4394 // Put the new preview in
4395 InventoryList *plist = player->inventory.getList("craftpreview");
4397 assert(plist->getSize() >= 1);
4398 plist->changeItem(0, preview);
4401 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4403 RemoteClient *client = getClientNoEx(peer_id,state_min);
4405 throw ClientNotFoundException("Client not found");
4409 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4411 return m_clients.getClientNoEx(peer_id, state_min);
4414 std::string Server::getPlayerName(u16 peer_id)
4416 Player *player = m_env->getPlayer(peer_id);
4418 return "[id="+itos(peer_id)+"]";
4419 return player->getName();
4422 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4424 Player *player = m_env->getPlayer(peer_id);
4427 return player->getPlayerSAO();
4430 std::wstring Server::getStatusString()
4432 std::wostringstream os(std::ios_base::binary);
4435 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4437 os<<L", uptime="<<m_uptime.get();
4439 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4440 // Information about clients
4443 std::list<u16> clients = m_clients.getClientIDs();
4444 for(std::list<u16>::iterator i = clients.begin();
4445 i != clients.end(); ++i)
4448 Player *player = m_env->getPlayer(*i);
4449 // Get name of player
4450 std::wstring name = L"unknown";
4452 name = narrow_to_wide(player->getName());
4453 // Add name to information string
4461 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4462 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4463 if(g_settings->get("motd") != "")
4464 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4468 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4470 std::set<std::string> privs;
4471 m_script->getAuth(name, NULL, &privs);
4475 bool Server::checkPriv(const std::string &name, const std::string &priv)
4477 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4478 return (privs.count(priv) != 0);
4481 void Server::reportPrivsModified(const std::string &name)
4484 std::list<u16> clients = m_clients.getClientIDs();
4485 for(std::list<u16>::iterator
4486 i = clients.begin();
4487 i != clients.end(); ++i){
4488 Player *player = m_env->getPlayer(*i);
4489 reportPrivsModified(player->getName());
4492 Player *player = m_env->getPlayer(name.c_str());
4495 SendPlayerPrivileges(player->peer_id);
4496 PlayerSAO *sao = player->getPlayerSAO();
4499 sao->updatePrivileges(
4500 getPlayerEffectivePrivs(name),
4505 void Server::reportInventoryFormspecModified(const std::string &name)
4507 Player *player = m_env->getPlayer(name.c_str());
4510 SendPlayerInventoryFormspec(player->peer_id);
4513 void Server::setIpBanned(const std::string &ip, const std::string &name)
4515 m_banmanager->add(ip, name);
4518 void Server::unsetIpBanned(const std::string &ip_or_name)
4520 m_banmanager->remove(ip_or_name);
4523 std::string Server::getBanDescription(const std::string &ip_or_name)
4525 return m_banmanager->getBanDescription(ip_or_name);
4528 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4530 Player *player = m_env->getPlayer(name);
4534 if (player->peer_id == PEER_ID_INEXISTENT)
4537 SendChatMessage(player->peer_id, msg);
4540 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4542 Player *player = m_env->getPlayer(playername);
4546 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4550 SendShowFormspecMessage(player->peer_id, formspec, formname);
4554 u32 Server::hudAdd(Player *player, HudElement *form) {
4558 u32 id = player->getFreeHudID();
4559 if (id < player->hud.size())
4560 player->hud[id] = form;
4562 player->hud.push_back(form);
4564 SendHUDAdd(player->peer_id, id, form);
4568 bool Server::hudRemove(Player *player, u32 id) {
4569 if (!player || id >= player->hud.size() || !player->hud[id])
4572 delete player->hud[id];
4573 player->hud[id] = NULL;
4575 SendHUDRemove(player->peer_id, id);
4579 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4583 SendHUDChange(player->peer_id, id, stat, data);
4587 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4591 SendHUDSetFlags(player->peer_id, flags, mask);
4593 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4597 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4600 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4603 std::ostringstream os(std::ios::binary);
4604 writeS32(os, hotbar_itemcount);
4605 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4609 void Server::hudSetHotbarImage(Player *player, std::string name) {
4613 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4616 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4620 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4623 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4628 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4632 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4637 SendEyeOffset(player->peer_id, first, third);
4641 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4642 const std::string &type, const std::vector<std::string> ¶ms)
4647 SendSetSky(player->peer_id, bgcolor, type, params);
4651 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4657 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4661 void Server::notifyPlayers(const std::wstring &msg)
4663 SendChatMessage(PEER_ID_INEXISTENT,msg);
4666 void Server::spawnParticle(const char *playername, v3f pos,
4667 v3f velocity, v3f acceleration,
4668 float expirationtime, float size, bool
4669 collisiondetection, bool vertical, std::string texture)
4671 Player *player = m_env->getPlayer(playername);
4674 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4675 expirationtime, size, collisiondetection, vertical, texture);
4678 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4679 float expirationtime, float size,
4680 bool collisiondetection, bool vertical, std::string texture)
4682 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4683 expirationtime, size, collisiondetection, vertical, texture);
4686 u32 Server::addParticleSpawner(const char *playername,
4687 u16 amount, float spawntime,
4688 v3f minpos, v3f maxpos,
4689 v3f minvel, v3f maxvel,
4690 v3f minacc, v3f maxacc,
4691 float minexptime, float maxexptime,
4692 float minsize, float maxsize,
4693 bool collisiondetection, bool vertical, std::string texture)
4695 Player *player = m_env->getPlayer(playername);
4700 for(;;) // look for unused particlespawner id
4703 if (std::find(m_particlespawner_ids.begin(),
4704 m_particlespawner_ids.end(), id)
4705 == m_particlespawner_ids.end())
4707 m_particlespawner_ids.push_back(id);
4712 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4713 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4714 minexptime, maxexptime, minsize, maxsize,
4715 collisiondetection, vertical, texture, id);
4720 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4721 v3f minpos, v3f maxpos,
4722 v3f minvel, v3f maxvel,
4723 v3f minacc, v3f maxacc,
4724 float minexptime, float maxexptime,
4725 float minsize, float maxsize,
4726 bool collisiondetection, bool vertical, std::string texture)
4729 for(;;) // look for unused particlespawner id
4732 if (std::find(m_particlespawner_ids.begin(),
4733 m_particlespawner_ids.end(), id)
4734 == m_particlespawner_ids.end())
4736 m_particlespawner_ids.push_back(id);
4741 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4742 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4743 minexptime, maxexptime, minsize, maxsize,
4744 collisiondetection, vertical, texture, id);
4749 void Server::deleteParticleSpawner(const char *playername, u32 id)
4751 Player *player = m_env->getPlayer(playername);
4755 m_particlespawner_ids.erase(
4756 std::remove(m_particlespawner_ids.begin(),
4757 m_particlespawner_ids.end(), id),
4758 m_particlespawner_ids.end());
4759 SendDeleteParticleSpawner(player->peer_id, id);
4762 void Server::deleteParticleSpawnerAll(u32 id)
4764 m_particlespawner_ids.erase(
4765 std::remove(m_particlespawner_ids.begin(),
4766 m_particlespawner_ids.end(), id),
4767 m_particlespawner_ids.end());
4768 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4771 Inventory* Server::createDetachedInventory(const std::string &name)
4773 if(m_detached_inventories.count(name) > 0){
4774 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4775 delete m_detached_inventories[name];
4777 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4779 Inventory *inv = new Inventory(m_itemdef);
4781 m_detached_inventories[name] = inv;
4782 //TODO find a better way to do this
4783 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4790 BoolScopeSet(bool *dst, bool val):
4793 m_orig_state = *m_dst;
4798 *m_dst = m_orig_state;
4805 // actions: time-reversed list
4806 // Return value: success/failure
4807 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4808 std::list<std::string> *log)
4810 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4811 ServerMap *map = (ServerMap*)(&m_env->getMap());
4812 // Disable rollback report sink while reverting
4813 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4815 // Fail if no actions to handle
4816 if(actions.empty()){
4817 log->push_back("Nothing to do.");
4824 for(std::list<RollbackAction>::const_iterator
4825 i = actions.begin();
4826 i != actions.end(); i++)
4828 const RollbackAction &action = *i;
4830 bool success = action.applyRevert(map, this, this);
4833 std::ostringstream os;
4834 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4835 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4837 log->push_back(os.str());
4839 std::ostringstream os;
4840 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4841 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4843 log->push_back(os.str());
4847 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4848 <<" failed"<<std::endl;
4850 // Call it done if less than half failed
4851 return num_failed <= num_tried/2;
4854 // IGameDef interface
4856 IItemDefManager* Server::getItemDefManager()
4860 INodeDefManager* Server::getNodeDefManager()
4864 ICraftDefManager* Server::getCraftDefManager()
4868 ITextureSource* Server::getTextureSource()
4872 IShaderSource* Server::getShaderSource()
4876 u16 Server::allocateUnknownNodeId(const std::string &name)
4878 return m_nodedef->allocateDummy(name);
4880 ISoundManager* Server::getSoundManager()
4882 return &dummySoundManager;
4884 MtEventManager* Server::getEventManager()
4888 IRollbackReportSink* Server::getRollbackReportSink()
4890 if(!m_enable_rollback_recording)
4892 if(!m_rollback_sink_enabled)
4897 IWritableItemDefManager* Server::getWritableItemDefManager()
4901 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4905 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4910 const ModSpec* Server::getModSpec(const std::string &modname)
4912 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4913 i != m_mods.end(); i++){
4914 const ModSpec &mod = *i;
4915 if(mod.name == modname)
4920 void Server::getModNames(std::list<std::string> &modlist)
4922 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4924 modlist.push_back(i->name);
4927 std::string Server::getBuiltinLuaPath()
4929 return porting::path_share + DIR_DELIM + "builtin";
4932 v3f findSpawnPos(ServerMap &map)
4934 //return v3f(50,50,50)*BS;
4939 nodepos = v2s16(0,0);
4944 s16 water_level = map.getWaterLevel();
4946 // Try to find a good place a few times
4947 for(s32 i=0; i<1000; i++)
4950 // We're going to try to throw the player to this position
4951 v2s16 nodepos2d = v2s16(
4952 -range + (myrand() % (range * 2)),
4953 -range + (myrand() % (range * 2)));
4955 // Get ground height at point
4956 s16 groundheight = map.findGroundLevel(nodepos2d);
4957 if (groundheight <= water_level) // Don't go underwater
4959 if (groundheight > water_level + 6) // Don't go to high places
4962 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4963 bool is_good = false;
4965 for (s32 i = 0; i < 10; i++) {
4966 v3s16 blockpos = getNodeBlockPos(nodepos);
4967 map.emergeBlock(blockpos, true);
4968 content_t c = map.getNodeNoEx(nodepos).getContent();
4969 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4971 if (air_count >= 2){
4979 // Found a good place
4980 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4986 return intToFloat(nodepos, BS);
4989 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4991 RemotePlayer *player = NULL;
4992 bool newplayer = false;
4995 Try to get an existing player
4997 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4999 // If player is already connected, cancel
5000 if(player != NULL && player->peer_id != 0)
5002 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5007 If player with the wanted peer_id already exists, cancel.
5009 if(m_env->getPlayer(peer_id) != NULL)
5011 infostream<<"emergePlayer(): Player with wrong name but same"
5012 " peer_id already exists"<<std::endl;
5017 Create a new player if it doesn't exist yet
5022 player = new RemotePlayer(this);
5023 player->updateName(name);
5025 /* Set player position */
5026 infostream<<"Server: Finding spawn place for player \""
5027 <<name<<"\""<<std::endl;
5028 v3f pos = findSpawnPos(m_env->getServerMap());
5029 player->setPosition(pos);
5031 /* Add player to environment */
5032 m_env->addPlayer(player);
5036 Create a new player active object
5038 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5039 getPlayerEffectivePrivs(player->getName()),
5042 /* Clean up old HUD elements from previous sessions */
5043 player->hud.clear();
5045 /* Add object to environment */
5046 m_env->addActiveObject(playersao);
5050 m_script->on_newplayer(playersao);
5055 void dedicated_server_loop(Server &server, bool &kill)
5057 DSTACK(__FUNCTION_NAME);
5059 verbosestream<<"dedicated_server_loop()"<<std::endl;
5061 IntervalLimiter m_profiler_interval;
5065 float steplen = g_settings->getFloat("dedicated_server_step");
5066 // This is kind of a hack but can be done like this
5067 // because server.step() is very light
5069 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5070 sleep_ms((int)(steplen*1000.0));
5072 server.step(steplen);
5074 if(server.getShutdownRequested() || kill)
5076 infostream<<"Dedicated server quitting"<<std::endl;
5078 if(g_settings->getBool("server_announce") == true)
5079 ServerList::sendAnnounce("delete");
5087 float profiler_print_interval =
5088 g_settings->getFloat("profiler_print_interval");
5089 if(profiler_print_interval != 0)
5091 if(m_profiler_interval.step(steplen, profiler_print_interval))
5093 infostream<<"Profiler:"<<std::endl;
5094 g_profiler->print(infostream);
5095 g_profiler->clear();