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;
297 // Path to builtin.lua
298 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
301 JMutexAutoLock envlock(m_env_mutex);
303 // Initialize scripting
304 infostream<<"Server: Initializing Lua"<<std::endl;
306 m_script = new GameScripting(this);
309 // Load and run builtin.lua
310 infostream<<"Server: Loading builtin.lua [\""
311 <<builtinpath<<"\"]"<<std::endl;
312 bool success = m_script->loadMod(builtinpath, "__builtin");
314 errorstream<<"Server: Failed to load and run "
315 <<builtinpath<<std::endl;
316 throw ModError("Failed to load and run "+builtinpath);
319 infostream<<"Server: Loading mods: ";
320 for(std::vector<ModSpec>::iterator i = m_mods.begin();
321 i != m_mods.end(); i++){
322 const ModSpec &mod = *i;
323 infostream<<mod.name<<" ";
325 infostream<<std::endl;
326 // Load and run "mod" scripts
327 for(std::vector<ModSpec>::iterator i = m_mods.begin();
328 i != m_mods.end(); i++){
329 const ModSpec &mod = *i;
330 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
331 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
332 <<scriptpath<<"\"]"<<std::endl;
333 bool success = m_script->loadMod(scriptpath, mod.name);
335 errorstream<<"Server: Failed to load and run "
336 <<scriptpath<<std::endl;
337 throw ModError("Failed to load and run "+scriptpath);
341 // Read Textures and calculate sha1 sums
344 // Apply item aliases in the node definition manager
345 m_nodedef->updateAliases(m_itemdef);
347 // Load the mapgen params from global settings now after any
348 // initial overrides have been set by the mods
349 m_emerge->loadMapgenParams();
351 // Initialize Environment
352 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
353 m_env = new ServerEnvironment(servermap, m_script, this);
355 m_clients.setEnv(m_env);
357 // Run some callbacks after the MG params have been set up but before activation
358 m_script->environment_OnMapgenInit(&m_emerge->params);
360 // Initialize mapgens
361 m_emerge->initMapgens();
363 // Give environment reference to scripting api
364 m_script->initializeEnvironment(m_env);
366 // Register us to receive map edit events
367 servermap->addEventReceiver(this);
369 // If file exists, load environment metadata
370 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
372 infostream<<"Server: Loading environment metadata"<<std::endl;
373 m_env->loadMeta(m_path_world);
377 infostream<<"Server: Loading players"<<std::endl;
378 m_env->deSerializePlayers(m_path_world);
381 Add some test ActiveBlockModifiers to environment
383 add_legacy_abms(m_env, m_nodedef);
385 m_liquid_transform_every = g_settings->getFloat("liquid_update");
390 infostream<<"Server destructing"<<std::endl;
393 Send shutdown message
396 std::wstring line = L"*** Server shutting down";
397 SendChatMessage(PEER_ID_INEXISTENT, line);
401 JMutexAutoLock envlock(m_env_mutex);
404 Execute script shutdown hooks
406 m_script->on_shutdown();
410 JMutexAutoLock envlock(m_env_mutex);
415 infostream<<"Server: Saving players"<<std::endl;
416 m_env->serializePlayers(m_path_world);
419 Save environment metadata
421 infostream<<"Server: Saving environment metadata"<<std::endl;
422 m_env->saveMeta(m_path_world);
431 // stop all emerge threads before deleting players that may have
432 // requested blocks to be emerged
433 m_emerge->stopThreads();
435 // Delete things in the reverse order of creation
438 // N.B. the EmergeManager should be deleted after the Environment since Map
439 // depends on EmergeManager to write its current params to the map meta
448 // Deinitialize scripting
449 infostream<<"Server: Deinitializing scripting"<<std::endl;
452 // Delete detached inventories
454 for(std::map<std::string, Inventory*>::iterator
455 i = m_detached_inventories.begin();
456 i != m_detached_inventories.end(); i++){
462 void Server::start(Address bind_addr)
464 DSTACK(__FUNCTION_NAME);
465 infostream<<"Starting server on "
466 << bind_addr.serializeString() <<"..."<<std::endl;
468 // Stop thread if already running
471 // Initialize connection
472 m_con.SetTimeoutMs(30);
473 m_con.Serve(bind_addr);
478 // ASCII art for the win!
480 <<" .__ __ __ "<<std::endl
481 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
482 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
483 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
484 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
485 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
486 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
487 actionstream<<"Server for gameid=\""<<m_gamespec.id
488 <<"\" listening on "<<bind_addr.serializeString()<<":"
489 <<bind_addr.getPort() << "."<<std::endl;
494 DSTACK(__FUNCTION_NAME);
496 infostream<<"Server: Stopping and waiting threads"<<std::endl;
498 // Stop threads (set run=false first so both start stopping)
500 //m_emergethread.setRun(false);
502 //m_emergethread.stop();
504 infostream<<"Server: Threads stopped"<<std::endl;
507 void Server::step(float dtime)
509 DSTACK(__FUNCTION_NAME);
514 JMutexAutoLock lock(m_step_dtime_mutex);
515 m_step_dtime += dtime;
517 // Throw if fatal error occurred in thread
518 std::string async_err = m_async_fatal_error.get();
520 throw ServerError(async_err);
524 void Server::AsyncRunStep(bool initial_step)
526 DSTACK(__FUNCTION_NAME);
528 g_profiler->add("Server::AsyncRunStep (num)", 1);
532 JMutexAutoLock lock1(m_step_dtime_mutex);
533 dtime = m_step_dtime;
537 // Send blocks to clients
541 if((dtime < 0.001) && (initial_step == false))
544 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
546 //infostream<<"Server steps "<<dtime<<std::endl;
547 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
550 JMutexAutoLock lock1(m_step_dtime_mutex);
551 m_step_dtime -= dtime;
558 m_uptime.set(m_uptime.get() + dtime);
564 Update time of day and overall game time
567 JMutexAutoLock envlock(m_env_mutex);
569 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
572 Send to clients at constant intervals
575 m_time_of_day_send_timer -= dtime;
576 if(m_time_of_day_send_timer < 0.0)
578 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
579 u16 time = m_env->getTimeOfDay();
580 float time_speed = g_settings->getFloat("time_speed");
581 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
586 JMutexAutoLock lock(m_env_mutex);
587 // Figure out and report maximum lag to environment
588 float max_lag = m_env->getMaxLagEstimate();
589 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
591 if(dtime > 0.1 && dtime > max_lag * 2.0)
592 infostream<<"Server: Maximum lag peaked to "<<dtime
596 m_env->reportMaxLagEstimate(max_lag);
598 ScopeProfiler sp(g_profiler, "SEnv step");
599 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
603 const float map_timer_and_unload_dtime = 2.92;
604 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
606 JMutexAutoLock lock(m_env_mutex);
607 // Run Map's timers and unload unused data
608 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
609 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
610 g_settings->getFloat("server_unload_unused_data_timeout"));
621 JMutexAutoLock lock(m_env_mutex);
623 std::list<u16> clientids = m_clients.getClientIDs();
625 ScopeProfiler sp(g_profiler, "Server: handle players");
627 for(std::list<u16>::iterator
628 i = clientids.begin();
629 i != clientids.end(); ++i)
631 PlayerSAO *playersao = getPlayerSAO(*i);
632 if(playersao == NULL)
636 Handle player HPs (die if hp=0)
638 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
640 if(playersao->getHP() == 0)
647 Send player breath if changed
649 if(playersao->m_breath_not_sent){
650 SendPlayerBreath(*i);
654 Send player inventories if necessary
656 if(playersao->m_moved){
658 playersao->m_moved = false;
660 if(playersao->m_inventory_not_sent){
667 /* Transform liquids */
668 m_liquid_transform_timer += dtime;
669 if(m_liquid_transform_timer >= m_liquid_transform_every)
671 m_liquid_transform_timer -= m_liquid_transform_every;
673 JMutexAutoLock lock(m_env_mutex);
675 ScopeProfiler sp(g_profiler, "Server: liquid transform");
677 std::map<v3s16, MapBlock*> modified_blocks;
678 m_env->getMap().transformLiquids(modified_blocks);
683 core::map<v3s16, MapBlock*> lighting_modified_blocks;
684 ServerMap &map = ((ServerMap&)m_env->getMap());
685 map.updateLighting(modified_blocks, lighting_modified_blocks);
687 // Add blocks modified by lighting to modified_blocks
688 for(core::map<v3s16, MapBlock*>::Iterator
689 i = lighting_modified_blocks.getIterator();
690 i.atEnd() == false; i++)
692 MapBlock *block = i.getNode()->getValue();
693 modified_blocks.insert(block->getPos(), block);
697 Set the modified blocks unsent for all the clients
699 if(modified_blocks.size() > 0)
701 SetBlocksNotSent(modified_blocks);
704 m_clients.step(dtime);
706 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
708 // send masterserver announce
710 float &counter = m_masterserver_timer;
711 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
712 g_settings->getBool("server_announce") == true)
714 ServerList::sendAnnounce(!counter ? "start" : "update",
715 m_clients.getPlayerNames(),
717 m_env->getGameTime(),
728 Check added and deleted active objects
731 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
732 JMutexAutoLock envlock(m_env_mutex);
735 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
736 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
738 // Radius inside which objects are active
739 s16 radius = g_settings->getS16("active_object_send_range_blocks");
740 radius *= MAP_BLOCKSIZE;
742 for(std::map<u16, RemoteClient*>::iterator
744 i != clients.end(); ++i)
746 RemoteClient *client = i->second;
748 // If definitions and textures have not been sent, don't
749 // send objects either
750 if (client->getState() < DefinitionsSent)
753 Player *player = m_env->getPlayer(client->peer_id);
756 // This can happen if the client timeouts somehow
757 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
759 <<" has no associated player"<<std::endl;*/
762 v3s16 pos = floatToInt(player->getPosition(), BS);
764 std::set<u16> removed_objects;
765 std::set<u16> added_objects;
766 m_env->getRemovedActiveObjects(pos, radius,
767 client->m_known_objects, removed_objects);
768 m_env->getAddedActiveObjects(pos, radius,
769 client->m_known_objects, added_objects);
771 // Ignore if nothing happened
772 if(removed_objects.size() == 0 && added_objects.size() == 0)
774 //infostream<<"active objects: none changed"<<std::endl;
778 std::string data_buffer;
782 // Handle removed objects
783 writeU16((u8*)buf, removed_objects.size());
784 data_buffer.append(buf, 2);
785 for(std::set<u16>::iterator
786 i = removed_objects.begin();
787 i != removed_objects.end(); ++i)
791 ServerActiveObject* obj = m_env->getActiveObject(id);
793 // Add to data buffer for sending
794 writeU16((u8*)buf, id);
795 data_buffer.append(buf, 2);
797 // Remove from known objects
798 client->m_known_objects.erase(id);
800 if(obj && obj->m_known_by_count > 0)
801 obj->m_known_by_count--;
804 // Handle added objects
805 writeU16((u8*)buf, added_objects.size());
806 data_buffer.append(buf, 2);
807 for(std::set<u16>::iterator
808 i = added_objects.begin();
809 i != added_objects.end(); ++i)
813 ServerActiveObject* obj = m_env->getActiveObject(id);
816 u8 type = ACTIVEOBJECT_TYPE_INVALID;
818 infostream<<"WARNING: "<<__FUNCTION_NAME
819 <<": NULL object"<<std::endl;
821 type = obj->getSendType();
823 // Add to data buffer for sending
824 writeU16((u8*)buf, id);
825 data_buffer.append(buf, 2);
826 writeU8((u8*)buf, type);
827 data_buffer.append(buf, 1);
830 data_buffer.append(serializeLongString(
831 obj->getClientInitializationData(client->net_proto_version)));
833 data_buffer.append(serializeLongString(""));
835 // Add to known objects
836 client->m_known_objects.insert(id);
839 obj->m_known_by_count++;
843 SharedBuffer<u8> reply(2 + data_buffer.size());
844 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
845 memcpy((char*)&reply[2], data_buffer.c_str(),
848 m_clients.send(client->peer_id, 0, reply, true);
850 verbosestream<<"Server: Sent object remove/add: "
851 <<removed_objects.size()<<" removed, "
852 <<added_objects.size()<<" added, "
853 <<"packet size is "<<reply.getSize()<<std::endl;
858 Collect a list of all the objects known by the clients
859 and report it back to the environment.
862 core::map<u16, bool> all_known_objects;
864 for(core::map<u16, RemoteClient*>::Iterator
865 i = m_clients.getIterator();
866 i.atEnd() == false; i++)
868 RemoteClient *client = i.getNode()->getValue();
869 // Go through all known objects of client
870 for(core::map<u16, bool>::Iterator
871 i = client->m_known_objects.getIterator();
872 i.atEnd()==false; i++)
874 u16 id = i.getNode()->getKey();
875 all_known_objects[id] = true;
879 m_env->setKnownActiveObjects(whatever);
888 JMutexAutoLock envlock(m_env_mutex);
889 ScopeProfiler sp(g_profiler, "Server: sending object messages");
892 // Value = data sent by object
893 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
895 // Get active object messages from environment
898 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
902 std::list<ActiveObjectMessage>* message_list = NULL;
903 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
904 n = buffered_messages.find(aom.id);
905 if(n == buffered_messages.end())
907 message_list = new std::list<ActiveObjectMessage>;
908 buffered_messages[aom.id] = message_list;
912 message_list = n->second;
914 message_list->push_back(aom);
918 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
919 // Route data to every client
920 for(std::map<u16, RemoteClient*>::iterator
922 i != clients.end(); ++i)
924 RemoteClient *client = i->second;
925 std::string reliable_data;
926 std::string unreliable_data;
927 // Go through all objects in message buffer
928 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
929 j = buffered_messages.begin();
930 j != buffered_messages.end(); ++j)
932 // If object is not known by client, skip it
934 if(client->m_known_objects.find(id) == client->m_known_objects.end())
936 // Get message list of object
937 std::list<ActiveObjectMessage>* list = j->second;
938 // Go through every message
939 for(std::list<ActiveObjectMessage>::iterator
940 k = list->begin(); k != list->end(); ++k)
942 // Compose the full new data with header
943 ActiveObjectMessage aom = *k;
944 std::string new_data;
947 writeU16((u8*)&buf[0], aom.id);
948 new_data.append(buf, 2);
950 new_data += serializeString(aom.datastring);
951 // Add data to buffer
953 reliable_data += new_data;
955 unreliable_data += new_data;
959 reliable_data and unreliable_data are now ready.
962 if(reliable_data.size() > 0)
964 SharedBuffer<u8> reply(2 + reliable_data.size());
965 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
966 memcpy((char*)&reply[2], reliable_data.c_str(),
967 reliable_data.size());
969 m_clients.send(client->peer_id, 0, reply, true);
971 if(unreliable_data.size() > 0)
973 SharedBuffer<u8> reply(2 + unreliable_data.size());
974 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
975 memcpy((char*)&reply[2], unreliable_data.c_str(),
976 unreliable_data.size());
977 // Send as unreliable
978 m_clients.send(client->peer_id, 1, reply, false);
981 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
983 infostream<<"Server: Size of object message data: "
984 <<"reliable: "<<reliable_data.size()
985 <<", unreliable: "<<unreliable_data.size()
991 // Clear buffered_messages
992 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
993 i = buffered_messages.begin();
994 i != buffered_messages.end(); ++i)
1001 Send queued-for-sending map edit events.
1004 // We will be accessing the environment
1005 JMutexAutoLock lock(m_env_mutex);
1007 // Don't send too many at a time
1010 // Single change sending is disabled if queue size is not small
1011 bool disable_single_change_sending = false;
1012 if(m_unsent_map_edit_queue.size() >= 4)
1013 disable_single_change_sending = true;
1015 int event_count = m_unsent_map_edit_queue.size();
1017 // We'll log the amount of each
1020 while(m_unsent_map_edit_queue.size() != 0)
1022 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1024 // Players far away from the change are stored here.
1025 // Instead of sending the changes, MapBlocks are set not sent
1027 std::list<u16> far_players;
1029 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1031 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1032 prof.add("MEET_ADDNODE", 1);
1033 if(disable_single_change_sending)
1034 sendAddNode(event->p, event->n, event->already_known_by_peer,
1035 &far_players, 5, event->type == MEET_ADDNODE);
1037 sendAddNode(event->p, event->n, event->already_known_by_peer,
1038 &far_players, 30, event->type == MEET_ADDNODE);
1040 else if(event->type == MEET_REMOVENODE)
1042 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1043 prof.add("MEET_REMOVENODE", 1);
1044 if(disable_single_change_sending)
1045 sendRemoveNode(event->p, event->already_known_by_peer,
1048 sendRemoveNode(event->p, event->already_known_by_peer,
1051 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1053 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1054 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1055 setBlockNotSent(event->p);
1057 else if(event->type == MEET_OTHER)
1059 infostream<<"Server: MEET_OTHER"<<std::endl;
1060 prof.add("MEET_OTHER", 1);
1061 for(std::set<v3s16>::iterator
1062 i = event->modified_blocks.begin();
1063 i != event->modified_blocks.end(); ++i)
1065 setBlockNotSent(*i);
1070 prof.add("unknown", 1);
1071 infostream<<"WARNING: Server: Unknown MapEditEvent "
1072 <<((u32)event->type)<<std::endl;
1076 Set blocks not sent to far players
1078 if(far_players.size() > 0)
1080 // Convert list format to that wanted by SetBlocksNotSent
1081 std::map<v3s16, MapBlock*> modified_blocks2;
1082 for(std::set<v3s16>::iterator
1083 i = event->modified_blocks.begin();
1084 i != event->modified_blocks.end(); ++i)
1086 modified_blocks2[*i] =
1087 m_env->getMap().getBlockNoCreateNoEx(*i);
1089 // Set blocks not sent
1090 for(std::list<u16>::iterator
1091 i = far_players.begin();
1092 i != far_players.end(); ++i)
1095 RemoteClient *client = getClient(peer_id);
1098 client->SetBlocksNotSent(modified_blocks2);
1104 /*// Don't send too many at a time
1106 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1110 if(event_count >= 5){
1111 infostream<<"Server: MapEditEvents:"<<std::endl;
1112 prof.print(infostream);
1113 } else if(event_count != 0){
1114 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1115 prof.print(verbosestream);
1121 Trigger emergethread (it somehow gets to a non-triggered but
1122 bysy state sometimes)
1125 float &counter = m_emergethread_trigger_timer;
1131 m_emerge->startThreads();
1133 // Update m_enable_rollback_recording here too
1134 m_enable_rollback_recording =
1135 g_settings->getBool("enable_rollback_recording");
1139 // Save map, players and auth stuff
1141 float &counter = m_savemap_timer;
1143 if(counter >= g_settings->getFloat("server_map_save_interval"))
1146 JMutexAutoLock lock(m_env_mutex);
1148 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1151 if(m_banmanager->isModified())
1152 m_banmanager->save();
1154 // Save changed parts of map
1155 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1158 m_env->serializePlayers(m_path_world);
1160 // Save environment metadata
1161 m_env->saveMeta(m_path_world);
1166 void Server::Receive()
1168 DSTACK(__FUNCTION_NAME);
1169 SharedBuffer<u8> data;
1173 datasize = m_con.Receive(peer_id,data);
1174 ProcessData(*data, datasize, peer_id);
1176 catch(con::InvalidIncomingDataException &e)
1178 infostream<<"Server::Receive(): "
1179 "InvalidIncomingDataException: what()="
1180 <<e.what()<<std::endl;
1182 catch(con::PeerNotFoundException &e)
1184 //NOTE: This is not needed anymore
1186 // The peer has been disconnected.
1187 // Find the associated player and remove it.
1189 /*JMutexAutoLock envlock(m_env_mutex);
1191 infostream<<"ServerThread: peer_id="<<peer_id
1192 <<" has apparently closed connection. "
1193 <<"Removing player."<<std::endl;
1195 m_env->removePlayer(peer_id);*/
1197 catch(ClientStateError &e)
1199 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1200 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1201 L"Try reconnecting or updating your client");
1205 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1207 std::string playername = "";
1208 PlayerSAO *playersao = NULL;
1210 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
1211 if (client != NULL) {
1212 playername = client->getName();
1213 playersao = emergePlayer(playername.c_str(), peer_id);
1217 RemotePlayer *player =
1218 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1220 // If failed, cancel
1221 if((playersao == NULL) || (player == NULL))
1223 if(player && player->peer_id != 0){
1224 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1225 <<" (player allocated to an another client)"<<std::endl;
1226 DenyAccess(peer_id, L"Another client is connected with this "
1227 L"name. If your client closed unexpectedly, try again in "
1230 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1232 DenyAccess(peer_id, L"Could not allocate player.");
1238 Send complete position information
1240 SendMovePlayer(peer_id);
1243 SendPlayerPrivileges(peer_id);
1245 // Send inventory formspec
1246 SendPlayerInventoryFormspec(peer_id);
1249 UpdateCrafting(peer_id);
1250 SendInventory(peer_id);
1253 if(g_settings->getBool("enable_damage"))
1254 SendPlayerHP(peer_id);
1257 SendPlayerBreath(peer_id);
1259 // Show death screen if necessary
1261 SendDeathscreen(peer_id, false, v3f(0,0,0));
1263 // Note things in chat if not in simple singleplayer mode
1264 if(!m_simple_singleplayer_mode)
1266 // Send information about server to player in chat
1267 SendChatMessage(peer_id, getStatusString());
1269 // Send information about joining in chat
1271 std::wstring name = L"unknown";
1272 Player *player = m_env->getPlayer(peer_id);
1274 name = narrow_to_wide(player->getName());
1276 std::wstring message;
1279 message += L" joined the game.";
1280 SendChatMessage(PEER_ID_INEXISTENT,message);
1284 actionstream<<player->getName() <<" joins game. " << std::endl;
1289 std::vector<std::string> names = m_clients.getPlayerNames();
1291 actionstream<<player->getName() <<" joins game. List of players: ";
1293 for (std::vector<std::string>::iterator i = names.begin();
1294 i != names.end(); i++)
1296 actionstream << *i << " ";
1299 actionstream<<std::endl;
1304 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1306 DSTACK(__FUNCTION_NAME);
1307 // Environment is locked first.
1308 JMutexAutoLock envlock(m_env_mutex);
1310 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1314 Address address = getPeerAddress(peer_id);
1315 addr_s = address.serializeString();
1317 // drop player if is ip is banned
1318 if(m_banmanager->isIpBanned(addr_s)){
1319 std::string ban_name = m_banmanager->getBanName(addr_s);
1320 infostream<<"Server: A banned client tried to connect from "
1321 <<addr_s<<"; banned name was "
1322 <<ban_name<<std::endl;
1323 // This actually doesn't seem to transfer to the client
1324 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1325 +narrow_to_wide(ban_name));
1329 catch(con::PeerNotFoundException &e)
1331 errorstream<<"Server::ProcessData(): Cancelling: peer "
1332 <<peer_id<<" not found"<<std::endl;
1342 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1344 if(command == TOSERVER_INIT)
1346 // [0] u16 TOSERVER_INIT
1347 // [2] u8 SER_FMT_VER_HIGHEST_READ
1348 // [3] u8[20] player_name
1349 // [23] u8[28] password <--- can be sent without this, from old versions
1351 if(datasize < 2+1+PLAYERNAME_SIZE)
1354 RemoteClient* client = getClient(peer_id,Created);
1356 // If net_proto_version is set, this client has already been handled
1357 if(client->getState() > Created)
1359 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1360 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1364 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1365 <<peer_id<<")"<<std::endl;
1367 // Do not allow multiple players in simple singleplayer mode.
1368 // This isn't a perfect way to do it, but will suffice for now
1369 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1370 infostream<<"Server: Not allowing another client ("<<addr_s
1371 <<") to connect in simple singleplayer mode"<<std::endl;
1372 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1376 // First byte after command is maximum supported
1377 // serialization version
1378 u8 client_max = data[2];
1379 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1380 // Use the highest version supported by both
1381 u8 deployed = std::min(client_max, our_max);
1382 // If it's lower than the lowest supported, give up.
1383 if(deployed < SER_FMT_VER_LOWEST)
1384 deployed = SER_FMT_VER_INVALID;
1386 if(deployed == SER_FMT_VER_INVALID)
1388 actionstream<<"Server: A mismatched client tried to connect from "
1389 <<addr_s<<std::endl;
1390 infostream<<"Server: Cannot negotiate serialization version with "
1391 <<addr_s<<std::endl;
1392 DenyAccess(peer_id, std::wstring(
1393 L"Your client's version is not supported.\n"
1394 L"Server version is ")
1395 + narrow_to_wide(minetest_version_simple) + L"."
1400 client->setPendingSerializationVersion(deployed);
1403 Read and check network protocol version
1406 u16 min_net_proto_version = 0;
1407 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1408 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1410 // Use same version as minimum and maximum if maximum version field
1411 // doesn't exist (backwards compatibility)
1412 u16 max_net_proto_version = min_net_proto_version;
1413 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1414 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1416 // Start with client's maximum version
1417 u16 net_proto_version = max_net_proto_version;
1419 // Figure out a working version if it is possible at all
1420 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1421 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1423 // If maximum is larger than our maximum, go with our maximum
1424 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1425 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1426 // Else go with client's maximum
1428 net_proto_version = max_net_proto_version;
1431 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1432 <<min_net_proto_version<<", max: "<<max_net_proto_version
1433 <<", chosen: "<<net_proto_version<<std::endl;
1435 client->net_proto_version = net_proto_version;
1437 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1438 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1440 actionstream<<"Server: A mismatched client tried to connect from "
1441 <<addr_s<<std::endl;
1442 DenyAccess(peer_id, std::wstring(
1443 L"Your client's version is not supported.\n"
1444 L"Server version is ")
1445 + narrow_to_wide(minetest_version_simple) + L",\n"
1446 + L"server's PROTOCOL_VERSION is "
1447 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1449 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1450 + L", client's PROTOCOL_VERSION is "
1451 + narrow_to_wide(itos(min_net_proto_version))
1453 + narrow_to_wide(itos(max_net_proto_version))
1458 if(g_settings->getBool("strict_protocol_version_checking"))
1460 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1462 actionstream<<"Server: A mismatched (strict) client tried to "
1463 <<"connect from "<<addr_s<<std::endl;
1464 DenyAccess(peer_id, std::wstring(
1465 L"Your client's version is not supported.\n"
1466 L"Server version is ")
1467 + narrow_to_wide(minetest_version_simple) + L",\n"
1468 + L"server's PROTOCOL_VERSION (strict) is "
1469 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1470 + L", client's PROTOCOL_VERSION is "
1471 + narrow_to_wide(itos(min_net_proto_version))
1473 + narrow_to_wide(itos(max_net_proto_version))
1484 char playername[PLAYERNAME_SIZE];
1485 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1487 playername[i] = data[3+i];
1489 playername[PLAYERNAME_SIZE-1] = 0;
1491 if(playername[0]=='\0')
1493 actionstream<<"Server: Player with an empty name "
1494 <<"tried to connect from "<<addr_s<<std::endl;
1495 DenyAccess(peer_id, L"Empty name");
1499 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1501 actionstream<<"Server: Player with an invalid name "
1502 <<"tried to connect from "<<addr_s<<std::endl;
1503 DenyAccess(peer_id, L"Name contains unallowed characters");
1507 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1509 actionstream<<"Server: Player with the name \"singleplayer\" "
1510 <<"tried to connect from "<<addr_s<<std::endl;
1511 DenyAccess(peer_id, L"Name is not allowed");
1517 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1519 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1520 <<"tried to connect from "<<addr_s<<" "
1521 <<"but it was disallowed for the following reason: "
1522 <<reason<<std::endl;
1523 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1528 infostream<<"Server: New connection: \""<<playername<<"\" from "
1529 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1532 char given_password[PASSWORD_SIZE];
1533 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1535 // old version - assume blank password
1536 given_password[0] = 0;
1540 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1542 given_password[i] = data[23+i];
1544 given_password[PASSWORD_SIZE-1] = 0;
1547 if(!base64_is_valid(given_password)){
1548 actionstream<<"Server: "<<playername
1549 <<" supplied invalid password hash"<<std::endl;
1550 DenyAccess(peer_id, L"Invalid password hash");
1554 // Enforce user limit.
1555 // Don't enforce for users that have some admin right
1556 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1557 !checkPriv(playername, "server") &&
1558 !checkPriv(playername, "ban") &&
1559 !checkPriv(playername, "privs") &&
1560 !checkPriv(playername, "password") &&
1561 playername != g_settings->get("name"))
1563 actionstream<<"Server: "<<playername<<" tried to join, but there"
1564 <<" are already max_users="
1565 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1566 DenyAccess(peer_id, L"Too many users.");
1570 std::string checkpwd; // Password hash to check against
1571 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1573 // If no authentication info exists for user, create it
1575 if(!isSingleplayer() &&
1576 g_settings->getBool("disallow_empty_password") &&
1577 std::string(given_password) == ""){
1578 actionstream<<"Server: "<<playername
1579 <<" supplied empty password"<<std::endl;
1580 DenyAccess(peer_id, L"Empty passwords are "
1581 L"disallowed. Set a password and try again.");
1584 std::wstring raw_default_password =
1585 narrow_to_wide(g_settings->get("default_password"));
1586 std::string initial_password =
1587 translatePassword(playername, raw_default_password);
1589 // If default_password is empty, allow any initial password
1590 if (raw_default_password.length() == 0)
1591 initial_password = given_password;
1593 m_script->createAuth(playername, initial_password);
1596 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1599 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1600 <<" (auth handler does not work?)"<<std::endl;
1601 DenyAccess(peer_id, L"Not allowed to login");
1605 if(given_password != checkpwd){
1606 actionstream<<"Server: "<<playername<<" supplied wrong password"
1608 DenyAccess(peer_id, L"Wrong password");
1612 RemotePlayer *player =
1613 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1615 if(player && player->peer_id != 0){
1616 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1617 <<" (player allocated to an another client)"<<std::endl;
1618 DenyAccess(peer_id, L"Another client is connected with this "
1619 L"name. If your client closed unexpectedly, try again in "
1623 m_clients.setPlayerName(peer_id,playername);
1626 Answer with a TOCLIENT_INIT
1629 SharedBuffer<u8> reply(2+1+6+8+4);
1630 writeU16(&reply[0], TOCLIENT_INIT);
1631 writeU8(&reply[2], deployed);
1632 //send dummy pos for legacy reasons only
1633 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1634 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1635 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1638 m_clients.send(peer_id, 0, reply, true);
1639 m_clients.event(peer_id, Init);
1645 if(command == TOSERVER_INIT2)
1648 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1649 <<peer_id<<std::endl;
1651 m_clients.event(peer_id, GotInit2);
1652 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1655 ///// begin compatibility code
1656 PlayerSAO* playersao = NULL;
1657 if (protocol_version <= 22) {
1658 playersao = StageTwoClientInit(peer_id);
1660 if (playersao == NULL) {
1662 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1663 << peer_id << std::endl;
1667 ///// end compatibility code
1670 Send some initialization data
1673 infostream<<"Server: Sending content to "
1674 <<getPlayerName(peer_id)<<std::endl;
1676 // Send player movement settings
1677 SendMovement(peer_id);
1679 // Send item definitions
1680 SendItemDef(peer_id, m_itemdef, protocol_version);
1682 // Send node definitions
1683 SendNodeDef(peer_id, m_nodedef, protocol_version);
1685 m_clients.event(peer_id, SetDefinitionsSent);
1687 // Send media announcement
1688 sendMediaAnnouncement(peer_id);
1690 // Send detached inventories
1691 sendDetachedInventories(peer_id);
1694 u16 time = m_env->getTimeOfDay();
1695 float time_speed = g_settings->getFloat("time_speed");
1696 SendTimeOfDay(peer_id, time, time_speed);
1698 ///// begin compatibility code
1699 if (protocol_version <= 22) {
1700 m_clients.event(peer_id, SetClientReady);
1701 m_script->on_joinplayer(playersao);
1703 ///// end compatibility code
1705 // Warnings about protocol version can be issued here
1706 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1708 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1709 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1715 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1716 u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1718 if(peer_ser_ver == SER_FMT_VER_INVALID)
1720 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1721 " serialization format invalid or not initialized."
1722 " Skipping incoming command="<<command<<std::endl;
1726 /* Handle commands relate to client startup */
1727 if(command == TOSERVER_REQUEST_MEDIA) {
1728 std::string datastring((char*)&data[2], datasize-2);
1729 std::istringstream is(datastring, std::ios_base::binary);
1731 std::list<std::string> tosend;
1732 u16 numfiles = readU16(is);
1734 infostream<<"Sending "<<numfiles<<" files to "
1735 <<getPlayerName(peer_id)<<std::endl;
1736 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1738 for(int i = 0; i < numfiles; i++) {
1739 std::string name = deSerializeString(is);
1740 tosend.push_back(name);
1741 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1745 sendRequestedMedia(peer_id, tosend);
1748 else if(command == TOSERVER_RECEIVED_MEDIA) {
1751 else if(command == TOSERVER_CLIENT_READY) {
1752 // clients <= protocol version 22 did not send ready message,
1753 // they're already initialized
1754 assert(peer_proto_ver > 22);
1756 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1758 if (playersao == NULL) {
1760 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1761 << peer_id << std::endl;
1769 m_clients.setClientVersion(
1771 data[2], data[3], data[4],
1772 std::string((char*) &data[8],(u16) data[6]));
1774 m_clients.event(peer_id, SetClientReady);
1775 m_script->on_joinplayer(playersao);
1778 else if(command == TOSERVER_GOTBLOCKS)
1791 u16 count = data[2];
1792 for(u16 i=0; i<count; i++)
1794 if((s16)datasize < 2+1+(i+1)*6)
1795 throw con::InvalidIncomingDataException
1796 ("GOTBLOCKS length is too short");
1797 v3s16 p = readV3S16(&data[2+1+i*6]);
1798 /*infostream<<"Server: GOTBLOCKS ("
1799 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1800 RemoteClient *client = getClient(peer_id);
1801 client->GotBlock(p);
1806 if (m_clients.getClientState(peer_id) < Active)
1808 if (command == TOSERVER_PLAYERPOS) return;
1810 errorstream<<"Got packet command: " << command << " for peer id "
1811 << peer_id << " but client isn't active yet. Dropping packet "
1816 Player *player = m_env->getPlayer(peer_id);
1818 errorstream<<"Server::ProcessData(): Cancelling: "
1819 "No player for peer_id="<<peer_id
1824 PlayerSAO *playersao = player->getPlayerSAO();
1825 if(playersao == NULL){
1826 errorstream<<"Server::ProcessData(): Cancelling: "
1827 "No player object for peer_id="<<peer_id
1832 if(command == TOSERVER_PLAYERPOS)
1834 if(datasize < 2+12+12+4+4)
1838 v3s32 ps = readV3S32(&data[start+2]);
1839 v3s32 ss = readV3S32(&data[start+2+12]);
1840 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1841 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1843 if(datasize >= 2+12+12+4+4+4)
1844 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1845 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1846 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1847 pitch = wrapDegrees(pitch);
1848 yaw = wrapDegrees(yaw);
1850 player->setPosition(position);
1851 player->setSpeed(speed);
1852 player->setPitch(pitch);
1853 player->setYaw(yaw);
1854 player->keyPressed=keyPressed;
1855 player->control.up = (bool)(keyPressed&1);
1856 player->control.down = (bool)(keyPressed&2);
1857 player->control.left = (bool)(keyPressed&4);
1858 player->control.right = (bool)(keyPressed&8);
1859 player->control.jump = (bool)(keyPressed&16);
1860 player->control.aux1 = (bool)(keyPressed&32);
1861 player->control.sneak = (bool)(keyPressed&64);
1862 player->control.LMB = (bool)(keyPressed&128);
1863 player->control.RMB = (bool)(keyPressed&256);
1865 bool cheated = playersao->checkMovementCheat();
1868 m_script->on_cheat(playersao, "moved_too_fast");
1871 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1872 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1873 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1875 else if(command == TOSERVER_DELETEDBLOCKS)
1888 u16 count = data[2];
1889 for(u16 i=0; i<count; i++)
1891 if((s16)datasize < 2+1+(i+1)*6)
1892 throw con::InvalidIncomingDataException
1893 ("DELETEDBLOCKS length is too short");
1894 v3s16 p = readV3S16(&data[2+1+i*6]);
1895 /*infostream<<"Server: DELETEDBLOCKS ("
1896 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1897 RemoteClient *client = getClient(peer_id);
1898 client->SetBlockNotSent(p);
1901 else if(command == TOSERVER_CLICK_OBJECT)
1903 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1906 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1908 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1911 else if(command == TOSERVER_GROUND_ACTION)
1913 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1917 else if(command == TOSERVER_RELEASE)
1919 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1922 else if(command == TOSERVER_SIGNTEXT)
1924 infostream<<"Server: SIGNTEXT not supported anymore"
1928 else if(command == TOSERVER_SIGNNODETEXT)
1930 infostream<<"Server: SIGNNODETEXT not supported anymore"
1934 else if(command == TOSERVER_INVENTORY_ACTION)
1936 // Strip command and create a stream
1937 std::string datastring((char*)&data[2], datasize-2);
1938 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1939 std::istringstream is(datastring, std::ios_base::binary);
1941 InventoryAction *a = InventoryAction::deSerialize(is);
1944 infostream<<"TOSERVER_INVENTORY_ACTION: "
1945 <<"InventoryAction::deSerialize() returned NULL"
1950 // If something goes wrong, this player is to blame
1951 RollbackScopeActor rollback_scope(m_rollback,
1952 std::string("player:")+player->getName());
1955 Note: Always set inventory not sent, to repair cases
1956 where the client made a bad prediction.
1960 Handle restrictions and special cases of the move action
1962 if(a->getType() == IACTION_MOVE)
1964 IMoveAction *ma = (IMoveAction*)a;
1966 ma->from_inv.applyCurrentPlayer(player->getName());
1967 ma->to_inv.applyCurrentPlayer(player->getName());
1969 setInventoryModified(ma->from_inv);
1970 setInventoryModified(ma->to_inv);
1972 bool from_inv_is_current_player =
1973 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1974 (ma->from_inv.name == player->getName());
1976 bool to_inv_is_current_player =
1977 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1978 (ma->to_inv.name == player->getName());
1981 Disable moving items out of craftpreview
1983 if(ma->from_list == "craftpreview")
1985 infostream<<"Ignoring IMoveAction from "
1986 <<(ma->from_inv.dump())<<":"<<ma->from_list
1987 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1988 <<" because src is "<<ma->from_list<<std::endl;
1994 Disable moving items into craftresult and craftpreview
1996 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1998 infostream<<"Ignoring IMoveAction from "
1999 <<(ma->from_inv.dump())<<":"<<ma->from_list
2000 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2001 <<" because dst is "<<ma->to_list<<std::endl;
2006 // Disallow moving items in elsewhere than player's inventory
2007 // if not allowed to interact
2008 if(!checkPriv(player->getName(), "interact") &&
2009 (!from_inv_is_current_player ||
2010 !to_inv_is_current_player))
2012 infostream<<"Cannot move outside of player's inventory: "
2013 <<"No interact privilege"<<std::endl;
2019 Handle restrictions and special cases of the drop action
2021 else if(a->getType() == IACTION_DROP)
2023 IDropAction *da = (IDropAction*)a;
2025 da->from_inv.applyCurrentPlayer(player->getName());
2027 setInventoryModified(da->from_inv);
2030 Disable dropping items out of craftpreview
2032 if(da->from_list == "craftpreview")
2034 infostream<<"Ignoring IDropAction from "
2035 <<(da->from_inv.dump())<<":"<<da->from_list
2036 <<" because src is "<<da->from_list<<std::endl;
2041 // Disallow dropping items if not allowed to interact
2042 if(!checkPriv(player->getName(), "interact"))
2049 Handle restrictions and special cases of the craft action
2051 else if(a->getType() == IACTION_CRAFT)
2053 ICraftAction *ca = (ICraftAction*)a;
2055 ca->craft_inv.applyCurrentPlayer(player->getName());
2057 setInventoryModified(ca->craft_inv);
2059 //bool craft_inv_is_current_player =
2060 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2061 // (ca->craft_inv.name == player->getName());
2063 // Disallow crafting if not allowed to interact
2064 if(!checkPriv(player->getName(), "interact"))
2066 infostream<<"Cannot craft: "
2067 <<"No interact privilege"<<std::endl;
2074 a->apply(this, playersao, this);
2078 else if(command == TOSERVER_CHAT_MESSAGE)
2086 std::string datastring((char*)&data[2], datasize-2);
2087 std::istringstream is(datastring, std::ios_base::binary);
2090 is.read((char*)buf, 2);
2091 u16 len = readU16(buf);
2093 std::wstring message;
2094 for(u16 i=0; i<len; i++)
2096 is.read((char*)buf, 2);
2097 message += (wchar_t)readU16(buf);
2100 // If something goes wrong, this player is to blame
2101 RollbackScopeActor rollback_scope(m_rollback,
2102 std::string("player:")+player->getName());
2104 // Get player name of this client
2105 std::wstring name = narrow_to_wide(player->getName());
2108 bool ate = m_script->on_chat_message(player->getName(),
2109 wide_to_narrow(message));
2110 // If script ate the message, don't proceed
2114 // Line to send to players
2116 // Whether to send to the player that sent the line
2117 bool send_to_sender_only = false;
2119 // Commands are implemented in Lua, so only catch invalid
2120 // commands that were not "eaten" and send an error back
2121 if(message[0] == L'/')
2123 message = message.substr(1);
2124 send_to_sender_only = true;
2125 if(message.length() == 0)
2126 line += L"-!- Empty command";
2128 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2132 if(checkPriv(player->getName(), "shout")){
2138 line += L"-!- You don't have permission to shout.";
2139 send_to_sender_only = true;
2146 Send the message to sender
2148 if (send_to_sender_only)
2150 SendChatMessage(peer_id, line);
2153 Send the message to others
2157 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2159 std::list<u16> clients = m_clients.getClientIDs();
2161 for(std::list<u16>::iterator
2162 i = clients.begin();
2163 i != clients.end(); ++i)
2166 SendChatMessage(*i, line);
2171 else if(command == TOSERVER_DAMAGE)
2173 std::string datastring((char*)&data[2], datasize-2);
2174 std::istringstream is(datastring, std::ios_base::binary);
2175 u8 damage = readU8(is);
2177 if(g_settings->getBool("enable_damage"))
2179 actionstream<<player->getName()<<" damaged by "
2180 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2183 playersao->setHP(playersao->getHP() - damage);
2185 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2188 if(playersao->m_hp_not_sent)
2189 SendPlayerHP(peer_id);
2192 else if(command == TOSERVER_BREATH)
2194 std::string datastring((char*)&data[2], datasize-2);
2195 std::istringstream is(datastring, std::ios_base::binary);
2196 u16 breath = readU16(is);
2197 playersao->setBreath(breath);
2199 else if(command == TOSERVER_PASSWORD)
2202 [0] u16 TOSERVER_PASSWORD
2203 [2] u8[28] old password
2204 [30] u8[28] new password
2207 if(datasize != 2+PASSWORD_SIZE*2)
2209 /*char password[PASSWORD_SIZE];
2210 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2211 password[i] = data[2+i];
2212 password[PASSWORD_SIZE-1] = 0;*/
2214 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2222 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2224 char c = data[2+PASSWORD_SIZE+i];
2230 if(!base64_is_valid(newpwd)){
2231 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2232 // Wrong old password supplied!!
2233 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2237 infostream<<"Server: Client requests a password change from "
2238 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2240 std::string playername = player->getName();
2242 std::string checkpwd;
2243 m_script->getAuth(playername, &checkpwd, NULL);
2245 if(oldpwd != checkpwd)
2247 infostream<<"Server: invalid old password"<<std::endl;
2248 // Wrong old password supplied!!
2249 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2253 bool success = m_script->setPassword(playername, newpwd);
2255 actionstream<<player->getName()<<" changes password"<<std::endl;
2256 SendChatMessage(peer_id, L"Password change successful.");
2258 actionstream<<player->getName()<<" tries to change password but "
2259 <<"it fails"<<std::endl;
2260 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2263 else if(command == TOSERVER_PLAYERITEM)
2268 u16 item = readU16(&data[2]);
2269 playersao->setWieldIndex(item);
2271 else if(command == TOSERVER_RESPAWN)
2273 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2276 RespawnPlayer(peer_id);
2278 actionstream<<player->getName()<<" respawns at "
2279 <<PP(player->getPosition()/BS)<<std::endl;
2281 // ActiveObject is added to environment in AsyncRunStep after
2282 // the previous addition has been succesfully removed
2284 else if(command == TOSERVER_INTERACT)
2286 std::string datastring((char*)&data[2], datasize-2);
2287 std::istringstream is(datastring, std::ios_base::binary);
2293 [5] u32 length of the next item
2294 [9] serialized PointedThing
2296 0: start digging (from undersurface) or use
2297 1: stop digging (all parameters ignored)
2298 2: digging completed
2299 3: place block or item (to abovesurface)
2302 u8 action = readU8(is);
2303 u16 item_i = readU16(is);
2304 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2305 PointedThing pointed;
2306 pointed.deSerialize(tmp_is);
2308 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2309 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2313 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2314 <<" tried to interact, but is dead!"<<std::endl;
2318 v3f player_pos = playersao->getLastGoodPosition();
2320 // Update wielded item
2321 playersao->setWieldIndex(item_i);
2323 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2324 v3s16 p_under = pointed.node_undersurface;
2325 v3s16 p_above = pointed.node_abovesurface;
2327 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2328 ServerActiveObject *pointed_object = NULL;
2329 if(pointed.type == POINTEDTHING_OBJECT)
2331 pointed_object = m_env->getActiveObject(pointed.object_id);
2332 if(pointed_object == NULL)
2334 verbosestream<<"TOSERVER_INTERACT: "
2335 "pointed object is NULL"<<std::endl;
2341 v3f pointed_pos_under = player_pos;
2342 v3f pointed_pos_above = player_pos;
2343 if(pointed.type == POINTEDTHING_NODE)
2345 pointed_pos_under = intToFloat(p_under, BS);
2346 pointed_pos_above = intToFloat(p_above, BS);
2348 else if(pointed.type == POINTEDTHING_OBJECT)
2350 pointed_pos_under = pointed_object->getBasePosition();
2351 pointed_pos_above = pointed_pos_under;
2355 Check that target is reasonably close
2356 (only when digging or placing things)
2358 if(action == 0 || action == 2 || action == 3)
2360 float d = player_pos.getDistanceFrom(pointed_pos_under);
2361 float max_d = BS * 14; // Just some large enough value
2363 actionstream<<"Player "<<player->getName()
2364 <<" tried to access "<<pointed.dump()
2366 <<"d="<<d<<", max_d="<<max_d
2367 <<". ignoring."<<std::endl;
2368 // Re-send block to revert change on client-side
2369 RemoteClient *client = getClient(peer_id);
2370 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2371 client->SetBlockNotSent(blockpos);
2373 m_script->on_cheat(playersao, "interacted_too_far");
2380 Make sure the player is allowed to do it
2382 if(!checkPriv(player->getName(), "interact"))
2384 actionstream<<player->getName()<<" attempted to interact with "
2385 <<pointed.dump()<<" without 'interact' privilege"
2387 // Re-send block to revert change on client-side
2388 RemoteClient *client = getClient(peer_id);
2389 // Digging completed -> under
2391 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2392 client->SetBlockNotSent(blockpos);
2394 // Placement -> above
2396 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2397 client->SetBlockNotSent(blockpos);
2403 If something goes wrong, this player is to blame
2405 RollbackScopeActor rollback_scope(m_rollback,
2406 std::string("player:")+player->getName());
2409 0: start digging or punch object
2413 if(pointed.type == POINTEDTHING_NODE)
2416 NOTE: This can be used in the future to check if
2417 somebody is cheating, by checking the timing.
2419 MapNode n(CONTENT_IGNORE);
2422 n = m_env->getMap().getNode(p_under);
2424 catch(InvalidPositionException &e)
2426 infostream<<"Server: Not punching: Node not found."
2427 <<" Adding block to emerge queue."
2429 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2431 if(n.getContent() != CONTENT_IGNORE)
2432 m_script->node_on_punch(p_under, n, playersao, pointed);
2434 playersao->noCheatDigStart(p_under);
2436 else if(pointed.type == POINTEDTHING_OBJECT)
2438 // Skip if object has been removed
2439 if(pointed_object->m_removed)
2442 actionstream<<player->getName()<<" punches object "
2443 <<pointed.object_id<<": "
2444 <<pointed_object->getDescription()<<std::endl;
2446 ItemStack punchitem = playersao->getWieldedItem();
2447 ToolCapabilities toolcap =
2448 punchitem.getToolCapabilities(m_itemdef);
2449 v3f dir = (pointed_object->getBasePosition() -
2450 (player->getPosition() + player->getEyeOffset())
2452 float time_from_last_punch =
2453 playersao->resetTimeFromLastPunch();
2454 pointed_object->punch(dir, &toolcap, playersao,
2455 time_from_last_punch);
2463 else if(action == 1)
2468 2: Digging completed
2470 else if(action == 2)
2472 // Only digging of nodes
2473 if(pointed.type == POINTEDTHING_NODE)
2475 MapNode n(CONTENT_IGNORE);
2478 n = m_env->getMap().getNode(p_under);
2480 catch(InvalidPositionException &e)
2482 infostream<<"Server: Not finishing digging: Node not found."
2483 <<" Adding block to emerge queue."
2485 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2488 /* Cheat prevention */
2489 bool is_valid_dig = true;
2490 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2492 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2493 float nocheat_t = playersao->getNoCheatDigTime();
2494 playersao->noCheatDigEnd();
2495 // If player didn't start digging this, ignore dig
2496 if(nocheat_p != p_under){
2497 infostream<<"Server: NoCheat: "<<player->getName()
2498 <<" started digging "
2499 <<PP(nocheat_p)<<" and completed digging "
2500 <<PP(p_under)<<"; not digging."<<std::endl;
2501 is_valid_dig = false;
2503 m_script->on_cheat(playersao, "finished_unknown_dig");
2505 // Get player's wielded item
2506 ItemStack playeritem;
2507 InventoryList *mlist = playersao->getInventory()->getList("main");
2509 playeritem = mlist->getItem(playersao->getWieldIndex());
2510 ToolCapabilities playeritem_toolcap =
2511 playeritem.getToolCapabilities(m_itemdef);
2512 // Get diggability and expected digging time
2513 DigParams params = getDigParams(m_nodedef->get(n).groups,
2514 &playeritem_toolcap);
2515 // If can't dig, try hand
2516 if(!params.diggable){
2517 const ItemDefinition &hand = m_itemdef->get("");
2518 const ToolCapabilities *tp = hand.tool_capabilities;
2520 params = getDigParams(m_nodedef->get(n).groups, tp);
2522 // If can't dig, ignore dig
2523 if(!params.diggable){
2524 infostream<<"Server: NoCheat: "<<player->getName()
2525 <<" completed digging "<<PP(p_under)
2526 <<", which is not diggable with tool. not digging."
2528 is_valid_dig = false;
2530 m_script->on_cheat(playersao, "dug_unbreakable");
2532 // Check digging time
2533 // If already invalidated, we don't have to
2535 // Well not our problem then
2537 // Clean and long dig
2538 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2539 // All is good, but grab time from pool; don't care if
2540 // it's actually available
2541 playersao->getDigPool().grab(params.time);
2543 // Short or laggy dig
2544 // Try getting the time from pool
2545 else if(playersao->getDigPool().grab(params.time)){
2550 infostream<<"Server: NoCheat: "<<player->getName()
2551 <<" completed digging "<<PP(p_under)
2552 <<"too fast; not digging."<<std::endl;
2553 is_valid_dig = false;
2555 m_script->on_cheat(playersao, "dug_too_fast");
2559 /* Actually dig node */
2561 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2562 m_script->node_on_dig(p_under, n, playersao);
2564 // Send unusual result (that is, node not being removed)
2565 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2567 // Re-send block to revert change on client-side
2568 RemoteClient *client = getClient(peer_id);
2569 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2570 client->SetBlockNotSent(blockpos);
2576 3: place block or right-click object
2578 else if(action == 3)
2580 ItemStack item = playersao->getWieldedItem();
2582 // Reset build time counter
2583 if(pointed.type == POINTEDTHING_NODE &&
2584 item.getDefinition(m_itemdef).type == ITEM_NODE)
2585 getClient(peer_id)->m_time_from_building = 0.0;
2587 if(pointed.type == POINTEDTHING_OBJECT)
2589 // Right click object
2591 // Skip if object has been removed
2592 if(pointed_object->m_removed)
2595 actionstream<<player->getName()<<" right-clicks object "
2596 <<pointed.object_id<<": "
2597 <<pointed_object->getDescription()<<std::endl;
2600 pointed_object->rightClick(playersao);
2602 else if(m_script->item_OnPlace(
2603 item, playersao, pointed))
2605 // Placement was handled in lua
2607 // Apply returned ItemStack
2608 playersao->setWieldedItem(item);
2611 // If item has node placement prediction, always send the
2612 // blocks to make sure the client knows what exactly happened
2613 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2614 RemoteClient *client = getClient(peer_id);
2615 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2616 client->SetBlockNotSent(blockpos);
2617 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2618 if(blockpos2 != blockpos){
2619 client->SetBlockNotSent(blockpos2);
2627 else if(action == 4)
2629 ItemStack item = playersao->getWieldedItem();
2631 actionstream<<player->getName()<<" uses "<<item.name
2632 <<", pointing at "<<pointed.dump()<<std::endl;
2634 if(m_script->item_OnUse(
2635 item, playersao, pointed))
2637 // Apply returned ItemStack
2638 playersao->setWieldedItem(item);
2645 Catch invalid actions
2649 infostream<<"WARNING: Server: Invalid action "
2650 <<action<<std::endl;
2653 else if(command == TOSERVER_REMOVED_SOUNDS)
2655 std::string datastring((char*)&data[2], datasize-2);
2656 std::istringstream is(datastring, std::ios_base::binary);
2658 int num = readU16(is);
2659 for(int k=0; k<num; k++){
2660 s32 id = readS32(is);
2661 std::map<s32, ServerPlayingSound>::iterator i =
2662 m_playing_sounds.find(id);
2663 if(i == m_playing_sounds.end())
2665 ServerPlayingSound &psound = i->second;
2666 psound.clients.erase(peer_id);
2667 if(psound.clients.size() == 0)
2668 m_playing_sounds.erase(i++);
2671 else if(command == TOSERVER_NODEMETA_FIELDS)
2673 std::string datastring((char*)&data[2], datasize-2);
2674 std::istringstream is(datastring, std::ios_base::binary);
2676 v3s16 p = readV3S16(is);
2677 std::string formname = deSerializeString(is);
2678 int num = readU16(is);
2679 std::map<std::string, std::string> fields;
2680 for(int k=0; k<num; k++){
2681 std::string fieldname = deSerializeString(is);
2682 std::string fieldvalue = deSerializeLongString(is);
2683 fields[fieldname] = fieldvalue;
2686 // If something goes wrong, this player is to blame
2687 RollbackScopeActor rollback_scope(m_rollback,
2688 std::string("player:")+player->getName());
2690 // Check the target node for rollback data; leave others unnoticed
2691 RollbackNode rn_old(&m_env->getMap(), p, this);
2693 m_script->node_on_receive_fields(p, formname, fields,playersao);
2695 // Report rollback data
2696 RollbackNode rn_new(&m_env->getMap(), p, this);
2697 if(rollback() && rn_new != rn_old){
2698 RollbackAction action;
2699 action.setSetNode(p, rn_old, rn_new);
2700 rollback()->reportAction(action);
2703 else if(command == TOSERVER_INVENTORY_FIELDS)
2705 std::string datastring((char*)&data[2], datasize-2);
2706 std::istringstream is(datastring, std::ios_base::binary);
2708 std::string formname = deSerializeString(is);
2709 int num = readU16(is);
2710 std::map<std::string, std::string> fields;
2711 for(int k=0; k<num; k++){
2712 std::string fieldname = deSerializeString(is);
2713 std::string fieldvalue = deSerializeLongString(is);
2714 fields[fieldname] = fieldvalue;
2717 m_script->on_playerReceiveFields(playersao, formname, fields);
2721 infostream<<"Server::ProcessData(): Ignoring "
2722 "unknown command "<<command<<std::endl;
2726 catch(SendFailedException &e)
2728 errorstream<<"Server::ProcessData(): SendFailedException: "
2734 void Server::setTimeOfDay(u32 time)
2736 m_env->setTimeOfDay(time);
2737 m_time_of_day_send_timer = 0;
2740 void Server::onMapEditEvent(MapEditEvent *event)
2742 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2743 if(m_ignore_map_edit_events)
2745 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2747 MapEditEvent *e = event->clone();
2748 m_unsent_map_edit_queue.push_back(e);
2751 Inventory* Server::getInventory(const InventoryLocation &loc)
2754 case InventoryLocation::UNDEFINED:
2757 case InventoryLocation::CURRENT_PLAYER:
2760 case InventoryLocation::PLAYER:
2762 Player *player = m_env->getPlayer(loc.name.c_str());
2765 PlayerSAO *playersao = player->getPlayerSAO();
2768 return playersao->getInventory();
2771 case InventoryLocation::NODEMETA:
2773 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2776 return meta->getInventory();
2779 case InventoryLocation::DETACHED:
2781 if(m_detached_inventories.count(loc.name) == 0)
2783 return m_detached_inventories[loc.name];
2791 void Server::setInventoryModified(const InventoryLocation &loc)
2794 case InventoryLocation::UNDEFINED:
2797 case InventoryLocation::PLAYER:
2799 Player *player = m_env->getPlayer(loc.name.c_str());
2802 PlayerSAO *playersao = player->getPlayerSAO();
2805 playersao->m_inventory_not_sent = true;
2806 playersao->m_wielded_item_not_sent = true;
2809 case InventoryLocation::NODEMETA:
2811 v3s16 blockpos = getNodeBlockPos(loc.p);
2813 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2815 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2817 setBlockNotSent(blockpos);
2820 case InventoryLocation::DETACHED:
2822 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2830 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2832 std::list<u16> clients = m_clients.getClientIDs();
2834 // Set the modified blocks unsent for all the clients
2835 for (std::list<u16>::iterator
2836 i = clients.begin();
2837 i != clients.end(); ++i) {
2838 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2840 client->SetBlocksNotSent(block);
2845 void Server::peerAdded(con::Peer *peer)
2847 DSTACK(__FUNCTION_NAME);
2848 verbosestream<<"Server::peerAdded(): peer->id="
2849 <<peer->id<<std::endl;
2852 c.type = con::PEER_ADDED;
2853 c.peer_id = peer->id;
2855 m_peer_change_queue.push_back(c);
2858 void Server::deletingPeer(con::Peer *peer, bool timeout)
2860 DSTACK(__FUNCTION_NAME);
2861 verbosestream<<"Server::deletingPeer(): peer->id="
2862 <<peer->id<<", timeout="<<timeout<<std::endl;
2864 m_clients.event(peer->id,Disconnect);
2866 c.type = con::PEER_REMOVED;
2867 c.peer_id = peer->id;
2868 c.timeout = timeout;
2869 m_peer_change_queue.push_back(c);
2872 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2874 *retval = m_con.getPeerStat(peer_id,type);
2875 if (*retval == -1) return false;
2879 bool Server::getClientInfo(
2888 std::string* vers_string
2891 *state = m_clients.getClientState(peer_id);
2893 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2898 *uptime = client->uptime();
2899 *ser_vers = client->serialization_version;
2900 *prot_vers = client->net_proto_version;
2902 *major = client->getMajor();
2903 *minor = client->getMinor();
2904 *patch = client->getPatch();
2905 *vers_string = client->getPatch();
2912 void Server::handlePeerChanges()
2914 while(m_peer_change_queue.size() > 0)
2916 con::PeerChange c = m_peer_change_queue.pop_front();
2918 verbosestream<<"Server: Handling peer change: "
2919 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2924 case con::PEER_ADDED:
2925 m_clients.CreateClient(c.peer_id);
2928 case con::PEER_REMOVED:
2929 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2933 assert("Invalid peer change event received!" == 0);
2939 void Server::SendMovement(u16 peer_id)
2941 DSTACK(__FUNCTION_NAME);
2942 std::ostringstream os(std::ios_base::binary);
2944 writeU16(os, TOCLIENT_MOVEMENT);
2945 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2946 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2947 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2948 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2949 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2950 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2951 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2952 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2953 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2954 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2955 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2956 writeF1000(os, g_settings->getFloat("movement_gravity"));
2959 std::string s = os.str();
2960 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2962 m_clients.send(peer_id, 0, data, true);
2965 void Server::SendHP(u16 peer_id, u8 hp)
2967 DSTACK(__FUNCTION_NAME);
2968 std::ostringstream os(std::ios_base::binary);
2970 writeU16(os, TOCLIENT_HP);
2974 std::string s = os.str();
2975 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2977 m_clients.send(peer_id, 0, data, true);
2980 void Server::SendBreath(u16 peer_id, u16 breath)
2982 DSTACK(__FUNCTION_NAME);
2983 std::ostringstream os(std::ios_base::binary);
2985 writeU16(os, TOCLIENT_BREATH);
2986 writeU16(os, breath);
2989 std::string s = os.str();
2990 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2992 m_clients.send(peer_id, 0, data, true);
2995 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2997 DSTACK(__FUNCTION_NAME);
2998 std::ostringstream os(std::ios_base::binary);
3000 writeU16(os, TOCLIENT_ACCESS_DENIED);
3001 os<<serializeWideString(reason);
3004 std::string s = os.str();
3005 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3007 m_clients.send(peer_id, 0, data, true);
3010 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3011 v3f camera_point_target)
3013 DSTACK(__FUNCTION_NAME);
3014 std::ostringstream os(std::ios_base::binary);
3016 writeU16(os, TOCLIENT_DEATHSCREEN);
3017 writeU8(os, set_camera_point_target);
3018 writeV3F1000(os, camera_point_target);
3021 std::string s = os.str();
3022 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3024 m_clients.send(peer_id, 0, data, true);
3027 void Server::SendItemDef(u16 peer_id,
3028 IItemDefManager *itemdef, u16 protocol_version)
3030 DSTACK(__FUNCTION_NAME);
3031 std::ostringstream os(std::ios_base::binary);
3035 u32 length of the next item
3036 zlib-compressed serialized ItemDefManager
3038 writeU16(os, TOCLIENT_ITEMDEF);
3039 std::ostringstream tmp_os(std::ios::binary);
3040 itemdef->serialize(tmp_os, protocol_version);
3041 std::ostringstream tmp_os2(std::ios::binary);
3042 compressZlib(tmp_os.str(), tmp_os2);
3043 os<<serializeLongString(tmp_os2.str());
3046 std::string s = os.str();
3047 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3048 <<"): size="<<s.size()<<std::endl;
3049 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3051 m_clients.send(peer_id, 0, data, true);
3054 void Server::SendNodeDef(u16 peer_id,
3055 INodeDefManager *nodedef, u16 protocol_version)
3057 DSTACK(__FUNCTION_NAME);
3058 std::ostringstream os(std::ios_base::binary);
3062 u32 length of the next item
3063 zlib-compressed serialized NodeDefManager
3065 writeU16(os, TOCLIENT_NODEDEF);
3066 std::ostringstream tmp_os(std::ios::binary);
3067 nodedef->serialize(tmp_os, protocol_version);
3068 std::ostringstream tmp_os2(std::ios::binary);
3069 compressZlib(tmp_os.str(), tmp_os2);
3070 os<<serializeLongString(tmp_os2.str());
3073 std::string s = os.str();
3074 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3075 <<"): size="<<s.size()<<std::endl;
3076 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3078 m_clients.send(peer_id, 0, data, true);
3082 Non-static send methods
3085 void Server::SendInventory(u16 peer_id)
3087 DSTACK(__FUNCTION_NAME);
3089 PlayerSAO *playersao = getPlayerSAO(peer_id);
3092 playersao->m_inventory_not_sent = false;
3098 std::ostringstream os;
3099 playersao->getInventory()->serialize(os);
3101 std::string s = os.str();
3103 SharedBuffer<u8> data(s.size()+2);
3104 writeU16(&data[0], TOCLIENT_INVENTORY);
3105 memcpy(&data[2], s.c_str(), s.size());
3108 m_clients.send(peer_id, 0, data, true);
3111 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3113 DSTACK(__FUNCTION_NAME);
3115 std::ostringstream os(std::ios_base::binary);
3119 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3120 os.write((char*)buf, 2);
3123 writeU16(buf, message.size());
3124 os.write((char*)buf, 2);
3127 for(u32 i=0; i<message.size(); i++)
3131 os.write((char*)buf, 2);
3135 std::string s = os.str();
3136 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3138 if (peer_id != PEER_ID_INEXISTENT)
3141 m_clients.send(peer_id, 0, data, true);
3145 m_clients.sendToAll(0,data,true);
3149 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3150 const std::string &formname)
3152 DSTACK(__FUNCTION_NAME);
3154 std::ostringstream os(std::ios_base::binary);
3158 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3159 os.write((char*)buf, 2);
3160 os<<serializeLongString(formspec);
3161 os<<serializeString(formname);
3164 std::string s = os.str();
3165 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3167 m_clients.send(peer_id, 0, data, true);
3170 // Spawns a particle on peer with peer_id
3171 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3172 float expirationtime, float size, bool collisiondetection,
3173 bool vertical, std::string texture)
3175 DSTACK(__FUNCTION_NAME);
3177 std::ostringstream os(std::ios_base::binary);
3178 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3179 writeV3F1000(os, pos);
3180 writeV3F1000(os, velocity);
3181 writeV3F1000(os, acceleration);
3182 writeF1000(os, expirationtime);
3183 writeF1000(os, size);
3184 writeU8(os, collisiondetection);
3185 os<<serializeLongString(texture);
3186 writeU8(os, vertical);
3189 std::string s = os.str();
3190 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3192 if (peer_id != PEER_ID_INEXISTENT)
3195 m_clients.send(peer_id, 0, data, true);
3199 m_clients.sendToAll(0,data,true);
3203 // Adds a ParticleSpawner on peer with peer_id
3204 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3205 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3206 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3208 DSTACK(__FUNCTION_NAME);
3210 std::ostringstream os(std::ios_base::binary);
3211 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3213 writeU16(os, amount);
3214 writeF1000(os, spawntime);
3215 writeV3F1000(os, minpos);
3216 writeV3F1000(os, maxpos);
3217 writeV3F1000(os, minvel);
3218 writeV3F1000(os, maxvel);
3219 writeV3F1000(os, minacc);
3220 writeV3F1000(os, maxacc);
3221 writeF1000(os, minexptime);
3222 writeF1000(os, maxexptime);
3223 writeF1000(os, minsize);
3224 writeF1000(os, maxsize);
3225 writeU8(os, collisiondetection);
3226 os<<serializeLongString(texture);
3228 writeU8(os, vertical);
3231 std::string s = os.str();
3232 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3234 if (peer_id != PEER_ID_INEXISTENT)
3237 m_clients.send(peer_id, 0, data, true);
3240 m_clients.sendToAll(0,data,true);
3244 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3246 DSTACK(__FUNCTION_NAME);
3248 std::ostringstream os(std::ios_base::binary);
3249 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3254 std::string s = os.str();
3255 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3257 if (peer_id != PEER_ID_INEXISTENT) {
3259 m_clients.send(peer_id, 0, data, true);
3262 m_clients.sendToAll(0,data,true);
3267 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3269 std::ostringstream os(std::ios_base::binary);
3272 writeU16(os, TOCLIENT_HUDADD);
3274 writeU8(os, (u8)form->type);
3275 writeV2F1000(os, form->pos);
3276 os << serializeString(form->name);
3277 writeV2F1000(os, form->scale);
3278 os << serializeString(form->text);
3279 writeU32(os, form->number);
3280 writeU32(os, form->item);
3281 writeU32(os, form->dir);
3282 writeV2F1000(os, form->align);
3283 writeV2F1000(os, form->offset);
3284 writeV3F1000(os, form->world_pos);
3287 std::string s = os.str();
3288 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3290 m_clients.send(peer_id, 1, data, true);
3293 void Server::SendHUDRemove(u16 peer_id, u32 id)
3295 std::ostringstream os(std::ios_base::binary);
3298 writeU16(os, TOCLIENT_HUDRM);
3302 std::string s = os.str();
3303 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3306 m_clients.send(peer_id, 1, data, true);
3309 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3311 std::ostringstream os(std::ios_base::binary);
3314 writeU16(os, TOCLIENT_HUDCHANGE);
3316 writeU8(os, (u8)stat);
3319 case HUD_STAT_SCALE:
3320 case HUD_STAT_ALIGN:
3321 case HUD_STAT_OFFSET:
3322 writeV2F1000(os, *(v2f *)value);
3326 os << serializeString(*(std::string *)value);
3328 case HUD_STAT_WORLD_POS:
3329 writeV3F1000(os, *(v3f *)value);
3331 case HUD_STAT_NUMBER:
3335 writeU32(os, *(u32 *)value);
3340 std::string s = os.str();
3341 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3343 m_clients.send(peer_id, 0, data, true);
3346 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3348 std::ostringstream os(std::ios_base::binary);
3351 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3352 writeU32(os, flags);
3356 std::string s = os.str();
3357 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3359 m_clients.send(peer_id, 0, data, true);
3362 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3364 std::ostringstream os(std::ios_base::binary);
3367 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3368 writeU16(os, param);
3369 os<<serializeString(value);
3372 std::string s = os.str();
3373 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3375 m_clients.send(peer_id, 0, data, true);
3378 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3379 const std::string &type, const std::vector<std::string> ¶ms)
3381 std::ostringstream os(std::ios_base::binary);
3384 writeU16(os, TOCLIENT_SET_SKY);
3385 writeARGB8(os, bgcolor);
3386 os<<serializeString(type);
3387 writeU16(os, params.size());
3388 for(size_t i=0; i<params.size(); i++)
3389 os<<serializeString(params[i]);
3392 std::string s = os.str();
3393 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3395 m_clients.send(peer_id, 0, data, true);
3398 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3401 std::ostringstream os(std::ios_base::binary);
3404 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3405 writeU8(os, do_override);
3406 writeU16(os, ratio*65535);
3409 std::string s = os.str();
3410 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3412 m_clients.send(peer_id, 0, data, true);
3415 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3417 DSTACK(__FUNCTION_NAME);
3420 SharedBuffer<u8> data(2+2+4);
3421 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3422 writeU16(&data[2], time);
3423 writeF1000(&data[4], time_speed);
3425 if (peer_id == PEER_ID_INEXISTENT) {
3426 m_clients.sendToAll(0,data,true);
3430 m_clients.send(peer_id, 0, data, true);
3434 void Server::SendPlayerHP(u16 peer_id)
3436 DSTACK(__FUNCTION_NAME);
3437 PlayerSAO *playersao = getPlayerSAO(peer_id);
3439 playersao->m_hp_not_sent = false;
3440 SendHP(peer_id, playersao->getHP());
3442 // Send to other clients
3443 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3444 ActiveObjectMessage aom(playersao->getId(), true, str);
3445 playersao->m_messages_out.push_back(aom);
3448 void Server::SendPlayerBreath(u16 peer_id)
3450 DSTACK(__FUNCTION_NAME);
3451 PlayerSAO *playersao = getPlayerSAO(peer_id);
3453 playersao->m_breath_not_sent = false;
3454 SendBreath(peer_id, playersao->getBreath());
3457 void Server::SendMovePlayer(u16 peer_id)
3459 DSTACK(__FUNCTION_NAME);
3460 Player *player = m_env->getPlayer(peer_id);
3463 std::ostringstream os(std::ios_base::binary);
3464 writeU16(os, TOCLIENT_MOVE_PLAYER);
3465 writeV3F1000(os, player->getPosition());
3466 writeF1000(os, player->getPitch());
3467 writeF1000(os, player->getYaw());
3470 v3f pos = player->getPosition();
3471 f32 pitch = player->getPitch();
3472 f32 yaw = player->getYaw();
3473 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3474 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3481 std::string s = os.str();
3482 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3484 m_clients.send(peer_id, 0, data, true);
3487 void Server::SendLocalPlayerAnimations(u16 peer_id, v2f animation_frames[4], f32 animation_speed)
3489 std::ostringstream os(std::ios_base::binary);
3491 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3492 writeV2F1000(os, animation_frames[0]);
3493 writeV2F1000(os, animation_frames[1]);
3494 writeV2F1000(os, animation_frames[2]);
3495 writeV2F1000(os, animation_frames[3]);
3496 writeF1000(os, animation_speed);
3499 std::string s = os.str();
3500 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3502 m_clients.send(peer_id, 0, data, true);
3505 void Server::SendPlayerPrivileges(u16 peer_id)
3507 Player *player = m_env->getPlayer(peer_id);
3509 if(player->peer_id == PEER_ID_INEXISTENT)
3512 std::set<std::string> privs;
3513 m_script->getAuth(player->getName(), NULL, &privs);
3515 std::ostringstream os(std::ios_base::binary);
3516 writeU16(os, TOCLIENT_PRIVILEGES);
3517 writeU16(os, privs.size());
3518 for(std::set<std::string>::const_iterator i = privs.begin();
3519 i != privs.end(); i++){
3520 os<<serializeString(*i);
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);
3530 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3532 Player *player = m_env->getPlayer(peer_id);
3534 if(player->peer_id == PEER_ID_INEXISTENT)
3537 std::ostringstream os(std::ios_base::binary);
3538 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3539 os<<serializeLongString(player->inventory_formspec);
3542 std::string s = os.str();
3543 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3545 m_clients.send(peer_id, 0, data, true);
3548 s32 Server::playSound(const SimpleSoundSpec &spec,
3549 const ServerSoundParams ¶ms)
3551 // Find out initial position of sound
3552 bool pos_exists = false;
3553 v3f pos = params.getPos(m_env, &pos_exists);
3554 // If position is not found while it should be, cancel sound
3555 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3558 // Filter destination clients
3559 std::list<u16> dst_clients;
3560 if(params.to_player != "")
3562 Player *player = m_env->getPlayer(params.to_player.c_str());
3564 infostream<<"Server::playSound: Player \""<<params.to_player
3565 <<"\" not found"<<std::endl;
3568 if(player->peer_id == PEER_ID_INEXISTENT){
3569 infostream<<"Server::playSound: Player \""<<params.to_player
3570 <<"\" not connected"<<std::endl;
3573 dst_clients.push_back(player->peer_id);
3577 std::list<u16> clients = m_clients.getClientIDs();
3579 for(std::list<u16>::iterator
3580 i = clients.begin(); i != clients.end(); ++i)
3582 Player *player = m_env->getPlayer(*i);
3586 if(player->getPosition().getDistanceFrom(pos) >
3587 params.max_hear_distance)
3590 dst_clients.push_back(*i);
3593 if(dst_clients.size() == 0)
3597 s32 id = m_next_sound_id++;
3598 // The sound will exist as a reference in m_playing_sounds
3599 m_playing_sounds[id] = ServerPlayingSound();
3600 ServerPlayingSound &psound = m_playing_sounds[id];
3601 psound.params = params;
3602 for(std::list<u16>::iterator i = dst_clients.begin();
3603 i != dst_clients.end(); i++)
3604 psound.clients.insert(*i);
3606 std::ostringstream os(std::ios_base::binary);
3607 writeU16(os, TOCLIENT_PLAY_SOUND);
3609 os<<serializeString(spec.name);
3610 writeF1000(os, spec.gain * params.gain);
3611 writeU8(os, params.type);
3612 writeV3F1000(os, pos);
3613 writeU16(os, params.object);
3614 writeU8(os, params.loop);
3616 std::string s = os.str();
3617 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3619 for(std::list<u16>::iterator i = dst_clients.begin();
3620 i != dst_clients.end(); i++){
3622 m_clients.send(*i, 0, data, true);
3626 void Server::stopSound(s32 handle)
3628 // Get sound reference
3629 std::map<s32, ServerPlayingSound>::iterator i =
3630 m_playing_sounds.find(handle);
3631 if(i == m_playing_sounds.end())
3633 ServerPlayingSound &psound = i->second;
3635 std::ostringstream os(std::ios_base::binary);
3636 writeU16(os, TOCLIENT_STOP_SOUND);
3637 writeS32(os, handle);
3639 std::string s = os.str();
3640 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3642 for(std::set<u16>::iterator i = psound.clients.begin();
3643 i != psound.clients.end(); i++){
3645 m_clients.send(*i, 0, data, true);
3647 // Remove sound reference
3648 m_playing_sounds.erase(i);
3651 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3652 std::list<u16> *far_players, float far_d_nodes)
3654 float maxd = far_d_nodes*BS;
3655 v3f p_f = intToFloat(p, BS);
3659 SharedBuffer<u8> reply(replysize);
3660 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3661 writeS16(&reply[2], p.X);
3662 writeS16(&reply[4], p.Y);
3663 writeS16(&reply[6], p.Z);
3665 std::list<u16> clients = m_clients.getClientIDs();
3666 for(std::list<u16>::iterator
3667 i = clients.begin();
3668 i != clients.end(); ++i)
3673 Player *player = m_env->getPlayer(*i);
3676 // If player is far away, only set modified blocks not sent
3677 v3f player_pos = player->getPosition();
3678 if(player_pos.getDistanceFrom(p_f) > maxd)
3680 far_players->push_back(*i);
3687 m_clients.send(*i, 0, reply, true);
3691 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3692 std::list<u16> *far_players, float far_d_nodes,
3693 bool remove_metadata)
3695 float maxd = far_d_nodes*BS;
3696 v3f p_f = intToFloat(p, BS);
3698 std::list<u16> clients = m_clients.getClientIDs();
3699 for(std::list<u16>::iterator
3700 i = clients.begin();
3701 i != clients.end(); ++i)
3707 Player *player = m_env->getPlayer(*i);
3710 // If player is far away, only set modified blocks not sent
3711 v3f player_pos = player->getPosition();
3712 if(player_pos.getDistanceFrom(p_f) > maxd)
3714 far_players->push_back(*i);
3719 SharedBuffer<u8> reply(0);
3721 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3725 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3726 reply = SharedBuffer<u8>(replysize);
3727 writeU16(&reply[0], TOCLIENT_ADDNODE);
3728 writeS16(&reply[2], p.X);
3729 writeS16(&reply[4], p.Y);
3730 writeS16(&reply[6], p.Z);
3731 n.serialize(&reply[8], client->serialization_version);
3732 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3733 writeU8(&reply[index], remove_metadata ? 0 : 1);
3735 if (!remove_metadata) {
3736 if (client->net_proto_version <= 21) {
3737 // Old clients always clear metadata; fix it
3738 // by sending the full block again.
3739 client->SetBlockNotSent(p);
3746 if (reply.getSize() > 0)
3747 m_clients.send(*i, 0, reply, true);
3751 void Server::setBlockNotSent(v3s16 p)
3753 std::list<u16> clients = m_clients.getClientIDs();
3755 for(std::list<u16>::iterator
3756 i = clients.begin();
3757 i != clients.end(); ++i)
3759 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3760 client->SetBlockNotSent(p);
3765 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3767 DSTACK(__FUNCTION_NAME);
3769 v3s16 p = block->getPos();
3773 bool completely_air = true;
3774 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3775 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3776 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3778 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3780 completely_air = false;
3781 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3786 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3788 infostream<<"[completely air] ";
3789 infostream<<std::endl;
3793 Create a packet with the block in the right format
3796 std::ostringstream os(std::ios_base::binary);
3797 block->serialize(os, ver, false);
3798 block->serializeNetworkSpecific(os, net_proto_version);
3799 std::string s = os.str();
3800 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3802 u32 replysize = 8 + blockdata.getSize();
3803 SharedBuffer<u8> reply(replysize);
3804 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3805 writeS16(&reply[2], p.X);
3806 writeS16(&reply[4], p.Y);
3807 writeS16(&reply[6], p.Z);
3808 memcpy(&reply[8], *blockdata, blockdata.getSize());
3810 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3811 <<": \tpacket size: "<<replysize<<std::endl;*/
3816 m_clients.send(peer_id, 2, reply, true);
3819 void Server::SendBlocks(float dtime)
3821 DSTACK(__FUNCTION_NAME);
3823 JMutexAutoLock envlock(m_env_mutex);
3824 //TODO check if one big lock could be faster then multiple small ones
3826 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3828 std::vector<PrioritySortedBlockTransfer> queue;
3830 s32 total_sending = 0;
3833 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3835 std::list<u16> clients = m_clients.getClientIDs();
3838 for(std::list<u16>::iterator
3839 i = clients.begin();
3840 i != clients.end(); ++i)
3842 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3847 total_sending += client->SendingCount();
3848 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3854 // Lowest priority number comes first.
3855 // Lowest is most important.
3856 std::sort(queue.begin(), queue.end());
3859 for(u32 i=0; i<queue.size(); i++)
3861 //TODO: Calculate limit dynamically
3862 if(total_sending >= g_settings->getS32
3863 ("max_simultaneous_block_sends_server_total"))
3866 PrioritySortedBlockTransfer q = queue[i];
3868 MapBlock *block = NULL;
3871 block = m_env->getMap().getBlockNoCreate(q.pos);
3873 catch(InvalidPositionException &e)
3878 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3883 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3885 client->SentBlock(q.pos);
3891 void Server::fillMediaCache()
3893 DSTACK(__FUNCTION_NAME);
3895 infostream<<"Server: Calculating media file checksums"<<std::endl;
3897 // Collect all media file paths
3898 std::list<std::string> paths;
3899 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3900 i != m_mods.end(); i++){
3901 const ModSpec &mod = *i;
3902 paths.push_back(mod.path + DIR_DELIM + "textures");
3903 paths.push_back(mod.path + DIR_DELIM + "sounds");
3904 paths.push_back(mod.path + DIR_DELIM + "media");
3905 paths.push_back(mod.path + DIR_DELIM + "models");
3907 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3909 // Collect media file information from paths into cache
3910 for(std::list<std::string>::iterator i = paths.begin();
3911 i != paths.end(); i++)
3913 std::string mediapath = *i;
3914 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3915 for(u32 j=0; j<dirlist.size(); j++){
3916 if(dirlist[j].dir) // Ignode dirs
3918 std::string filename = dirlist[j].name;
3919 // If name contains illegal characters, ignore the file
3920 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3921 infostream<<"Server: ignoring illegal file name: \""
3922 <<filename<<"\""<<std::endl;
3925 // If name is not in a supported format, ignore it
3926 const char *supported_ext[] = {
3927 ".png", ".jpg", ".bmp", ".tga",
3928 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3930 ".x", ".b3d", ".md2", ".obj",
3933 if(removeStringEnd(filename, supported_ext) == ""){
3934 infostream<<"Server: ignoring unsupported file extension: \""
3935 <<filename<<"\""<<std::endl;
3938 // Ok, attempt to load the file and add to cache
3939 std::string filepath = mediapath + DIR_DELIM + filename;
3941 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3942 if(fis.good() == false){
3943 errorstream<<"Server::fillMediaCache(): Could not open \""
3944 <<filename<<"\" for reading"<<std::endl;
3947 std::ostringstream tmp_os(std::ios_base::binary);
3951 fis.read(buf, 1024);
3952 std::streamsize len = fis.gcount();
3953 tmp_os.write(buf, len);
3962 errorstream<<"Server::fillMediaCache(): Failed to read \""
3963 <<filename<<"\""<<std::endl;
3966 if(tmp_os.str().length() == 0){
3967 errorstream<<"Server::fillMediaCache(): Empty file \""
3968 <<filepath<<"\""<<std::endl;
3973 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3975 unsigned char *digest = sha1.getDigest();
3976 std::string sha1_base64 = base64_encode(digest, 20);
3977 std::string sha1_hex = hex_encode((char*)digest, 20);
3981 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3982 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3987 struct SendableMediaAnnouncement
3990 std::string sha1_digest;
3992 SendableMediaAnnouncement(const std::string &name_="",
3993 const std::string &sha1_digest_=""):
3995 sha1_digest(sha1_digest_)
3999 void Server::sendMediaAnnouncement(u16 peer_id)
4001 DSTACK(__FUNCTION_NAME);
4003 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4006 std::list<SendableMediaAnnouncement> file_announcements;
4008 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4009 i != m_media.end(); i++){
4011 file_announcements.push_back(
4012 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4016 std::ostringstream os(std::ios_base::binary);
4024 u16 length of sha1_digest
4029 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4030 writeU16(os, file_announcements.size());
4032 for(std::list<SendableMediaAnnouncement>::iterator
4033 j = file_announcements.begin();
4034 j != file_announcements.end(); ++j){
4035 os<<serializeString(j->name);
4036 os<<serializeString(j->sha1_digest);
4038 os<<serializeString(g_settings->get("remote_media"));
4041 std::string s = os.str();
4042 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4045 m_clients.send(peer_id, 0, data, true);
4048 struct SendableMedia
4054 SendableMedia(const std::string &name_="", const std::string &path_="",
4055 const std::string &data_=""):
4062 void Server::sendRequestedMedia(u16 peer_id,
4063 const std::list<std::string> &tosend)
4065 DSTACK(__FUNCTION_NAME);
4067 verbosestream<<"Server::sendRequestedMedia(): "
4068 <<"Sending files to client"<<std::endl;
4072 // Put 5kB in one bunch (this is not accurate)
4073 u32 bytes_per_bunch = 5000;
4075 std::vector< std::list<SendableMedia> > file_bunches;
4076 file_bunches.push_back(std::list<SendableMedia>());
4078 u32 file_size_bunch_total = 0;
4080 for(std::list<std::string>::const_iterator i = tosend.begin();
4081 i != tosend.end(); ++i)
4083 const std::string &name = *i;
4085 if(m_media.find(name) == m_media.end()){
4086 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4087 <<"unknown file \""<<(name)<<"\""<<std::endl;
4091 //TODO get path + name
4092 std::string tpath = m_media[name].path;
4095 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4096 if(fis.good() == false){
4097 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4098 <<tpath<<"\" for reading"<<std::endl;
4101 std::ostringstream tmp_os(std::ios_base::binary);
4105 fis.read(buf, 1024);
4106 std::streamsize len = fis.gcount();
4107 tmp_os.write(buf, len);
4108 file_size_bunch_total += len;
4117 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4118 <<name<<"\""<<std::endl;
4121 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4122 <<tname<<"\""<<std::endl;*/
4124 file_bunches[file_bunches.size()-1].push_back(
4125 SendableMedia(name, tpath, tmp_os.str()));
4127 // Start next bunch if got enough data
4128 if(file_size_bunch_total >= bytes_per_bunch){
4129 file_bunches.push_back(std::list<SendableMedia>());
4130 file_size_bunch_total = 0;
4135 /* Create and send packets */
4137 u32 num_bunches = file_bunches.size();
4138 for(u32 i=0; i<num_bunches; i++)
4140 std::ostringstream os(std::ios_base::binary);
4144 u16 total number of texture bunches
4145 u16 index of this bunch
4146 u32 number of files in this bunch
4155 writeU16(os, TOCLIENT_MEDIA);
4156 writeU16(os, num_bunches);
4158 writeU32(os, file_bunches[i].size());
4160 for(std::list<SendableMedia>::iterator
4161 j = file_bunches[i].begin();
4162 j != file_bunches[i].end(); ++j){
4163 os<<serializeString(j->name);
4164 os<<serializeLongString(j->data);
4168 std::string s = os.str();
4169 verbosestream<<"Server::sendRequestedMedia(): bunch "
4170 <<i<<"/"<<num_bunches
4171 <<" files="<<file_bunches[i].size()
4172 <<" size=" <<s.size()<<std::endl;
4173 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4175 m_clients.send(peer_id, 2, data, true);
4179 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4181 if(m_detached_inventories.count(name) == 0){
4182 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4185 Inventory *inv = m_detached_inventories[name];
4187 std::ostringstream os(std::ios_base::binary);
4188 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4189 os<<serializeString(name);
4193 std::string s = os.str();
4194 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4196 if (peer_id != PEER_ID_INEXISTENT)
4199 m_clients.send(peer_id, 0, data, true);
4203 m_clients.sendToAll(0,data,true);
4207 void Server::sendDetachedInventories(u16 peer_id)
4209 DSTACK(__FUNCTION_NAME);
4211 for(std::map<std::string, Inventory*>::iterator
4212 i = m_detached_inventories.begin();
4213 i != m_detached_inventories.end(); i++){
4214 const std::string &name = i->first;
4215 //Inventory *inv = i->second;
4216 sendDetachedInventory(name, peer_id);
4224 void Server::DiePlayer(u16 peer_id)
4226 DSTACK(__FUNCTION_NAME);
4228 PlayerSAO *playersao = getPlayerSAO(peer_id);
4231 infostream<<"Server::DiePlayer(): Player "
4232 <<playersao->getPlayer()->getName()
4233 <<" dies"<<std::endl;
4235 playersao->setHP(0);
4237 // Trigger scripted stuff
4238 m_script->on_dieplayer(playersao);
4240 SendPlayerHP(peer_id);
4241 SendDeathscreen(peer_id, false, v3f(0,0,0));
4244 void Server::RespawnPlayer(u16 peer_id)
4246 DSTACK(__FUNCTION_NAME);
4248 PlayerSAO *playersao = getPlayerSAO(peer_id);
4251 infostream<<"Server::RespawnPlayer(): Player "
4252 <<playersao->getPlayer()->getName()
4253 <<" respawns"<<std::endl;
4255 playersao->setHP(PLAYER_MAX_HP);
4257 bool repositioned = m_script->on_respawnplayer(playersao);
4259 v3f pos = findSpawnPos(m_env->getServerMap());
4260 playersao->setPos(pos);
4264 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4266 DSTACK(__FUNCTION_NAME);
4268 SendAccessDenied(peer_id, reason);
4269 m_clients.event(peer_id,SetDenied);
4270 m_con.DisconnectPeer(peer_id);
4273 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4275 DSTACK(__FUNCTION_NAME);
4276 std::wstring message;
4279 Clear references to playing sounds
4281 for(std::map<s32, ServerPlayingSound>::iterator
4282 i = m_playing_sounds.begin();
4283 i != m_playing_sounds.end();)
4285 ServerPlayingSound &psound = i->second;
4286 psound.clients.erase(peer_id);
4287 if(psound.clients.size() == 0)
4288 m_playing_sounds.erase(i++);
4293 Player *player = m_env->getPlayer(peer_id);
4295 // Collect information about leaving in chat
4297 if(player != NULL && reason != CDR_DENY)
4299 std::wstring name = narrow_to_wide(player->getName());
4302 message += L" left the game.";
4303 if(reason == CDR_TIMEOUT)
4304 message += L" (timed out)";
4308 /* Run scripts and remove from environment */
4312 PlayerSAO *playersao = player->getPlayerSAO();
4315 m_script->on_leaveplayer(playersao);
4317 playersao->disconnected();
4325 if(player != NULL && reason != CDR_DENY)
4327 std::ostringstream os(std::ios_base::binary);
4328 std::list<u16> clients = m_clients.getClientIDs();
4330 for(std::list<u16>::iterator
4331 i = clients.begin();
4332 i != clients.end(); ++i)
4335 Player *player = m_env->getPlayer(*i);
4338 // Get name of player
4339 os<<player->getName()<<" ";
4342 actionstream<<player->getName()<<" "
4343 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4344 <<" List of players: "<<os.str()<<std::endl;
4348 JMutexAutoLock env_lock(m_env_mutex);
4349 m_clients.DeleteClient(peer_id);
4353 // Send leave chat message to all remaining clients
4354 if(message.length() != 0)
4355 SendChatMessage(PEER_ID_INEXISTENT,message);
4358 void Server::UpdateCrafting(u16 peer_id)
4360 DSTACK(__FUNCTION_NAME);
4362 Player* player = m_env->getPlayer(peer_id);
4365 // Get a preview for crafting
4367 InventoryLocation loc;
4368 loc.setPlayer(player->getName());
4369 getCraftingResult(&player->inventory, preview, false, this);
4370 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4372 // Put the new preview in
4373 InventoryList *plist = player->inventory.getList("craftpreview");
4375 assert(plist->getSize() >= 1);
4376 plist->changeItem(0, preview);
4379 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4381 RemoteClient *client = getClientNoEx(peer_id,state_min);
4383 throw ClientNotFoundException("Client not found");
4387 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4389 return m_clients.getClientNoEx(peer_id, state_min);
4392 std::string Server::getPlayerName(u16 peer_id)
4394 Player *player = m_env->getPlayer(peer_id);
4396 return "[id="+itos(peer_id)+"]";
4397 return player->getName();
4400 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4402 Player *player = m_env->getPlayer(peer_id);
4405 return player->getPlayerSAO();
4408 std::wstring Server::getStatusString()
4410 std::wostringstream os(std::ios_base::binary);
4413 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4415 os<<L", uptime="<<m_uptime.get();
4417 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4418 // Information about clients
4421 std::list<u16> clients = m_clients.getClientIDs();
4422 for(std::list<u16>::iterator i = clients.begin();
4423 i != clients.end(); ++i)
4426 Player *player = m_env->getPlayer(*i);
4427 // Get name of player
4428 std::wstring name = L"unknown";
4430 name = narrow_to_wide(player->getName());
4431 // Add name to information string
4439 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4440 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4441 if(g_settings->get("motd") != "")
4442 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4446 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4448 std::set<std::string> privs;
4449 m_script->getAuth(name, NULL, &privs);
4453 bool Server::checkPriv(const std::string &name, const std::string &priv)
4455 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4456 return (privs.count(priv) != 0);
4459 void Server::reportPrivsModified(const std::string &name)
4462 std::list<u16> clients = m_clients.getClientIDs();
4463 for(std::list<u16>::iterator
4464 i = clients.begin();
4465 i != clients.end(); ++i){
4466 Player *player = m_env->getPlayer(*i);
4467 reportPrivsModified(player->getName());
4470 Player *player = m_env->getPlayer(name.c_str());
4473 SendPlayerPrivileges(player->peer_id);
4474 PlayerSAO *sao = player->getPlayerSAO();
4477 sao->updatePrivileges(
4478 getPlayerEffectivePrivs(name),
4483 void Server::reportInventoryFormspecModified(const std::string &name)
4485 Player *player = m_env->getPlayer(name.c_str());
4488 SendPlayerInventoryFormspec(player->peer_id);
4491 void Server::setIpBanned(const std::string &ip, const std::string &name)
4493 m_banmanager->add(ip, name);
4496 void Server::unsetIpBanned(const std::string &ip_or_name)
4498 m_banmanager->remove(ip_or_name);
4501 std::string Server::getBanDescription(const std::string &ip_or_name)
4503 return m_banmanager->getBanDescription(ip_or_name);
4506 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4508 Player *player = m_env->getPlayer(name);
4512 if (player->peer_id == PEER_ID_INEXISTENT)
4515 SendChatMessage(player->peer_id, msg);
4518 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4520 Player *player = m_env->getPlayer(playername);
4524 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4528 SendShowFormspecMessage(player->peer_id, formspec, formname);
4532 u32 Server::hudAdd(Player *player, HudElement *form) {
4536 u32 id = player->getFreeHudID();
4537 if (id < player->hud.size())
4538 player->hud[id] = form;
4540 player->hud.push_back(form);
4542 SendHUDAdd(player->peer_id, id, form);
4546 bool Server::hudRemove(Player *player, u32 id) {
4547 if (!player || id >= player->hud.size() || !player->hud[id])
4550 delete player->hud[id];
4551 player->hud[id] = NULL;
4553 SendHUDRemove(player->peer_id, id);
4557 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4561 SendHUDChange(player->peer_id, id, stat, data);
4565 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4569 SendHUDSetFlags(player->peer_id, flags, mask);
4573 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4576 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4579 std::ostringstream os(std::ios::binary);
4580 writeS32(os, hotbar_itemcount);
4581 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4585 void Server::hudSetHotbarImage(Player *player, std::string name) {
4589 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4592 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4596 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4599 bool Server::setLocalPlayerAnimations(Player *player, v2f animation_frames[4], f32 frame_speed)
4604 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4608 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4609 const std::string &type, const std::vector<std::string> ¶ms)
4614 SendSetSky(player->peer_id, bgcolor, type, params);
4618 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4624 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4628 void Server::notifyPlayers(const std::wstring &msg)
4630 SendChatMessage(PEER_ID_INEXISTENT,msg);
4633 void Server::spawnParticle(const char *playername, v3f pos,
4634 v3f velocity, v3f acceleration,
4635 float expirationtime, float size, bool
4636 collisiondetection, bool vertical, std::string texture)
4638 Player *player = m_env->getPlayer(playername);
4641 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4642 expirationtime, size, collisiondetection, vertical, texture);
4645 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4646 float expirationtime, float size,
4647 bool collisiondetection, bool vertical, std::string texture)
4649 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4650 expirationtime, size, collisiondetection, vertical, texture);
4653 u32 Server::addParticleSpawner(const char *playername,
4654 u16 amount, float spawntime,
4655 v3f minpos, v3f maxpos,
4656 v3f minvel, v3f maxvel,
4657 v3f minacc, v3f maxacc,
4658 float minexptime, float maxexptime,
4659 float minsize, float maxsize,
4660 bool collisiondetection, bool vertical, std::string texture)
4662 Player *player = m_env->getPlayer(playername);
4667 for(;;) // look for unused particlespawner id
4670 if (std::find(m_particlespawner_ids.begin(),
4671 m_particlespawner_ids.end(), id)
4672 == m_particlespawner_ids.end())
4674 m_particlespawner_ids.push_back(id);
4679 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4680 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4681 minexptime, maxexptime, minsize, maxsize,
4682 collisiondetection, vertical, texture, id);
4687 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4688 v3f minpos, v3f maxpos,
4689 v3f minvel, v3f maxvel,
4690 v3f minacc, v3f maxacc,
4691 float minexptime, float maxexptime,
4692 float minsize, float maxsize,
4693 bool collisiondetection, bool vertical, std::string texture)
4696 for(;;) // look for unused particlespawner id
4699 if (std::find(m_particlespawner_ids.begin(),
4700 m_particlespawner_ids.end(), id)
4701 == m_particlespawner_ids.end())
4703 m_particlespawner_ids.push_back(id);
4708 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4709 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4710 minexptime, maxexptime, minsize, maxsize,
4711 collisiondetection, vertical, texture, id);
4716 void Server::deleteParticleSpawner(const char *playername, u32 id)
4718 Player *player = m_env->getPlayer(playername);
4722 m_particlespawner_ids.erase(
4723 std::remove(m_particlespawner_ids.begin(),
4724 m_particlespawner_ids.end(), id),
4725 m_particlespawner_ids.end());
4726 SendDeleteParticleSpawner(player->peer_id, id);
4729 void Server::deleteParticleSpawnerAll(u32 id)
4731 m_particlespawner_ids.erase(
4732 std::remove(m_particlespawner_ids.begin(),
4733 m_particlespawner_ids.end(), id),
4734 m_particlespawner_ids.end());
4735 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4738 Inventory* Server::createDetachedInventory(const std::string &name)
4740 if(m_detached_inventories.count(name) > 0){
4741 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4742 delete m_detached_inventories[name];
4744 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4746 Inventory *inv = new Inventory(m_itemdef);
4748 m_detached_inventories[name] = inv;
4749 //TODO find a better way to do this
4750 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4757 BoolScopeSet(bool *dst, bool val):
4760 m_orig_state = *m_dst;
4765 *m_dst = m_orig_state;
4772 // actions: time-reversed list
4773 // Return value: success/failure
4774 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4775 std::list<std::string> *log)
4777 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4778 ServerMap *map = (ServerMap*)(&m_env->getMap());
4779 // Disable rollback report sink while reverting
4780 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4782 // Fail if no actions to handle
4783 if(actions.empty()){
4784 log->push_back("Nothing to do.");
4791 for(std::list<RollbackAction>::const_iterator
4792 i = actions.begin();
4793 i != actions.end(); i++)
4795 const RollbackAction &action = *i;
4797 bool success = action.applyRevert(map, this, this);
4800 std::ostringstream os;
4801 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4802 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4804 log->push_back(os.str());
4806 std::ostringstream os;
4807 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4808 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4810 log->push_back(os.str());
4814 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4815 <<" failed"<<std::endl;
4817 // Call it done if less than half failed
4818 return num_failed <= num_tried/2;
4821 // IGameDef interface
4823 IItemDefManager* Server::getItemDefManager()
4827 INodeDefManager* Server::getNodeDefManager()
4831 ICraftDefManager* Server::getCraftDefManager()
4835 ITextureSource* Server::getTextureSource()
4839 IShaderSource* Server::getShaderSource()
4843 u16 Server::allocateUnknownNodeId(const std::string &name)
4845 return m_nodedef->allocateDummy(name);
4847 ISoundManager* Server::getSoundManager()
4849 return &dummySoundManager;
4851 MtEventManager* Server::getEventManager()
4855 IRollbackReportSink* Server::getRollbackReportSink()
4857 if(!m_enable_rollback_recording)
4859 if(!m_rollback_sink_enabled)
4864 IWritableItemDefManager* Server::getWritableItemDefManager()
4868 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4872 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4877 const ModSpec* Server::getModSpec(const std::string &modname)
4879 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4880 i != m_mods.end(); i++){
4881 const ModSpec &mod = *i;
4882 if(mod.name == modname)
4887 void Server::getModNames(std::list<std::string> &modlist)
4889 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4891 modlist.push_back(i->name);
4894 std::string Server::getBuiltinLuaPath()
4896 return porting::path_share + DIR_DELIM + "builtin";
4899 v3f findSpawnPos(ServerMap &map)
4901 //return v3f(50,50,50)*BS;
4906 nodepos = v2s16(0,0);
4911 s16 water_level = map.getWaterLevel();
4913 // Try to find a good place a few times
4914 for(s32 i=0; i<1000; i++)
4917 // We're going to try to throw the player to this position
4918 v2s16 nodepos2d = v2s16(
4919 -range + (myrand() % (range * 2)),
4920 -range + (myrand() % (range * 2)));
4922 // Get ground height at point
4923 s16 groundheight = map.findGroundLevel(nodepos2d);
4924 if (groundheight <= water_level) // Don't go underwater
4926 if (groundheight > water_level + 6) // Don't go to high places
4929 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4930 bool is_good = false;
4932 for (s32 i = 0; i < 10; i++) {
4933 v3s16 blockpos = getNodeBlockPos(nodepos);
4934 map.emergeBlock(blockpos, true);
4935 content_t c = map.getNodeNoEx(nodepos).getContent();
4936 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4938 if (air_count >= 2){
4946 // Found a good place
4947 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4953 return intToFloat(nodepos, BS);
4956 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4958 RemotePlayer *player = NULL;
4959 bool newplayer = false;
4962 Try to get an existing player
4964 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4966 // If player is already connected, cancel
4967 if(player != NULL && player->peer_id != 0)
4969 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4974 If player with the wanted peer_id already exists, cancel.
4976 if(m_env->getPlayer(peer_id) != NULL)
4978 infostream<<"emergePlayer(): Player with wrong name but same"
4979 " peer_id already exists"<<std::endl;
4984 Create a new player if it doesn't exist yet
4989 player = new RemotePlayer(this);
4990 player->updateName(name);
4992 /* Set player position */
4993 infostream<<"Server: Finding spawn place for player \""
4994 <<name<<"\""<<std::endl;
4995 v3f pos = findSpawnPos(m_env->getServerMap());
4996 player->setPosition(pos);
4998 /* Add player to environment */
4999 m_env->addPlayer(player);
5003 Create a new player active object
5005 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5006 getPlayerEffectivePrivs(player->getName()),
5009 /* Clean up old HUD elements from previous sessions */
5010 player->hud.clear();
5012 /* Add object to environment */
5013 m_env->addActiveObject(playersao);
5017 m_script->on_newplayer(playersao);
5022 void dedicated_server_loop(Server &server, bool &kill)
5024 DSTACK(__FUNCTION_NAME);
5026 verbosestream<<"dedicated_server_loop()"<<std::endl;
5028 IntervalLimiter m_profiler_interval;
5032 float steplen = g_settings->getFloat("dedicated_server_step");
5033 // This is kind of a hack but can be done like this
5034 // because server.step() is very light
5036 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5037 sleep_ms((int)(steplen*1000.0));
5039 server.step(steplen);
5041 if(server.getShutdownRequested() || kill)
5043 infostream<<"Dedicated server quitting"<<std::endl;
5045 if(g_settings->getBool("server_announce") == true)
5046 ServerList::sendAnnounce("delete");
5054 float profiler_print_interval =
5055 g_settings->getFloat("profiler_print_interval");
5056 if(profiler_print_interval != 0)
5058 if(m_profiler_interval.step(steplen, profiler_print_interval))
5060 infostream<<"Profiler:"<<std::endl;
5061 g_profiler->print(infostream);
5062 g_profiler->clear();