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