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::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3507 std::ostringstream os(std::ios_base::binary);
3509 writeU16(os, TOCLIENT_EYE_OFFSET);
3510 writeV3F1000(os, first);
3511 writeV3F1000(os, third);
3514 std::string s = os.str();
3515 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3517 m_clients.send(peer_id, 0, data, true);
3519 void Server::SendPlayerPrivileges(u16 peer_id)
3521 Player *player = m_env->getPlayer(peer_id);
3523 if(player->peer_id == PEER_ID_INEXISTENT)
3526 std::set<std::string> privs;
3527 m_script->getAuth(player->getName(), NULL, &privs);
3529 std::ostringstream os(std::ios_base::binary);
3530 writeU16(os, TOCLIENT_PRIVILEGES);
3531 writeU16(os, privs.size());
3532 for(std::set<std::string>::const_iterator i = privs.begin();
3533 i != privs.end(); i++){
3534 os<<serializeString(*i);
3538 std::string s = os.str();
3539 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3541 m_clients.send(peer_id, 0, data, true);
3544 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3546 Player *player = m_env->getPlayer(peer_id);
3548 if(player->peer_id == PEER_ID_INEXISTENT)
3551 std::ostringstream os(std::ios_base::binary);
3552 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3553 os<<serializeLongString(player->inventory_formspec);
3556 std::string s = os.str();
3557 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3559 m_clients.send(peer_id, 0, data, true);
3562 s32 Server::playSound(const SimpleSoundSpec &spec,
3563 const ServerSoundParams ¶ms)
3565 // Find out initial position of sound
3566 bool pos_exists = false;
3567 v3f pos = params.getPos(m_env, &pos_exists);
3568 // If position is not found while it should be, cancel sound
3569 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3572 // Filter destination clients
3573 std::list<u16> dst_clients;
3574 if(params.to_player != "")
3576 Player *player = m_env->getPlayer(params.to_player.c_str());
3578 infostream<<"Server::playSound: Player \""<<params.to_player
3579 <<"\" not found"<<std::endl;
3582 if(player->peer_id == PEER_ID_INEXISTENT){
3583 infostream<<"Server::playSound: Player \""<<params.to_player
3584 <<"\" not connected"<<std::endl;
3587 dst_clients.push_back(player->peer_id);
3591 std::list<u16> clients = m_clients.getClientIDs();
3593 for(std::list<u16>::iterator
3594 i = clients.begin(); i != clients.end(); ++i)
3596 Player *player = m_env->getPlayer(*i);
3600 if(player->getPosition().getDistanceFrom(pos) >
3601 params.max_hear_distance)
3604 dst_clients.push_back(*i);
3607 if(dst_clients.size() == 0)
3611 s32 id = m_next_sound_id++;
3612 // The sound will exist as a reference in m_playing_sounds
3613 m_playing_sounds[id] = ServerPlayingSound();
3614 ServerPlayingSound &psound = m_playing_sounds[id];
3615 psound.params = params;
3616 for(std::list<u16>::iterator i = dst_clients.begin();
3617 i != dst_clients.end(); i++)
3618 psound.clients.insert(*i);
3620 std::ostringstream os(std::ios_base::binary);
3621 writeU16(os, TOCLIENT_PLAY_SOUND);
3623 os<<serializeString(spec.name);
3624 writeF1000(os, spec.gain * params.gain);
3625 writeU8(os, params.type);
3626 writeV3F1000(os, pos);
3627 writeU16(os, params.object);
3628 writeU8(os, params.loop);
3630 std::string s = os.str();
3631 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3633 for(std::list<u16>::iterator i = dst_clients.begin();
3634 i != dst_clients.end(); i++){
3636 m_clients.send(*i, 0, data, true);
3640 void Server::stopSound(s32 handle)
3642 // Get sound reference
3643 std::map<s32, ServerPlayingSound>::iterator i =
3644 m_playing_sounds.find(handle);
3645 if(i == m_playing_sounds.end())
3647 ServerPlayingSound &psound = i->second;
3649 std::ostringstream os(std::ios_base::binary);
3650 writeU16(os, TOCLIENT_STOP_SOUND);
3651 writeS32(os, handle);
3653 std::string s = os.str();
3654 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3656 for(std::set<u16>::iterator i = psound.clients.begin();
3657 i != psound.clients.end(); i++){
3659 m_clients.send(*i, 0, data, true);
3661 // Remove sound reference
3662 m_playing_sounds.erase(i);
3665 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3666 std::list<u16> *far_players, float far_d_nodes)
3668 float maxd = far_d_nodes*BS;
3669 v3f p_f = intToFloat(p, BS);
3673 SharedBuffer<u8> reply(replysize);
3674 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3675 writeS16(&reply[2], p.X);
3676 writeS16(&reply[4], p.Y);
3677 writeS16(&reply[6], p.Z);
3679 std::list<u16> clients = m_clients.getClientIDs();
3680 for(std::list<u16>::iterator
3681 i = clients.begin();
3682 i != clients.end(); ++i)
3687 Player *player = m_env->getPlayer(*i);
3690 // If player is far away, only set modified blocks not sent
3691 v3f player_pos = player->getPosition();
3692 if(player_pos.getDistanceFrom(p_f) > maxd)
3694 far_players->push_back(*i);
3701 m_clients.send(*i, 0, reply, true);
3705 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3706 std::list<u16> *far_players, float far_d_nodes,
3707 bool remove_metadata)
3709 float maxd = far_d_nodes*BS;
3710 v3f p_f = intToFloat(p, BS);
3712 std::list<u16> clients = m_clients.getClientIDs();
3713 for(std::list<u16>::iterator
3714 i = clients.begin();
3715 i != clients.end(); ++i)
3721 Player *player = m_env->getPlayer(*i);
3724 // If player is far away, only set modified blocks not sent
3725 v3f player_pos = player->getPosition();
3726 if(player_pos.getDistanceFrom(p_f) > maxd)
3728 far_players->push_back(*i);
3733 SharedBuffer<u8> reply(0);
3735 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3739 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3740 reply = SharedBuffer<u8>(replysize);
3741 writeU16(&reply[0], TOCLIENT_ADDNODE);
3742 writeS16(&reply[2], p.X);
3743 writeS16(&reply[4], p.Y);
3744 writeS16(&reply[6], p.Z);
3745 n.serialize(&reply[8], client->serialization_version);
3746 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3747 writeU8(&reply[index], remove_metadata ? 0 : 1);
3749 if (!remove_metadata) {
3750 if (client->net_proto_version <= 21) {
3751 // Old clients always clear metadata; fix it
3752 // by sending the full block again.
3753 client->SetBlockNotSent(p);
3760 if (reply.getSize() > 0)
3761 m_clients.send(*i, 0, reply, true);
3765 void Server::setBlockNotSent(v3s16 p)
3767 std::list<u16> clients = m_clients.getClientIDs();
3769 for(std::list<u16>::iterator
3770 i = clients.begin();
3771 i != clients.end(); ++i)
3773 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3774 client->SetBlockNotSent(p);
3779 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3781 DSTACK(__FUNCTION_NAME);
3783 v3s16 p = block->getPos();
3787 bool completely_air = true;
3788 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3789 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3790 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3792 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3794 completely_air = false;
3795 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3800 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3802 infostream<<"[completely air] ";
3803 infostream<<std::endl;
3807 Create a packet with the block in the right format
3810 std::ostringstream os(std::ios_base::binary);
3811 block->serialize(os, ver, false);
3812 block->serializeNetworkSpecific(os, net_proto_version);
3813 std::string s = os.str();
3814 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3816 u32 replysize = 8 + blockdata.getSize();
3817 SharedBuffer<u8> reply(replysize);
3818 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3819 writeS16(&reply[2], p.X);
3820 writeS16(&reply[4], p.Y);
3821 writeS16(&reply[6], p.Z);
3822 memcpy(&reply[8], *blockdata, blockdata.getSize());
3824 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3825 <<": \tpacket size: "<<replysize<<std::endl;*/
3830 m_clients.send(peer_id, 2, reply, true);
3833 void Server::SendBlocks(float dtime)
3835 DSTACK(__FUNCTION_NAME);
3837 JMutexAutoLock envlock(m_env_mutex);
3838 //TODO check if one big lock could be faster then multiple small ones
3840 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3842 std::vector<PrioritySortedBlockTransfer> queue;
3844 s32 total_sending = 0;
3847 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3849 std::list<u16> clients = m_clients.getClientIDs();
3852 for(std::list<u16>::iterator
3853 i = clients.begin();
3854 i != clients.end(); ++i)
3856 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3861 total_sending += client->SendingCount();
3862 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3868 // Lowest priority number comes first.
3869 // Lowest is most important.
3870 std::sort(queue.begin(), queue.end());
3873 for(u32 i=0; i<queue.size(); i++)
3875 //TODO: Calculate limit dynamically
3876 if(total_sending >= g_settings->getS32
3877 ("max_simultaneous_block_sends_server_total"))
3880 PrioritySortedBlockTransfer q = queue[i];
3882 MapBlock *block = NULL;
3885 block = m_env->getMap().getBlockNoCreate(q.pos);
3887 catch(InvalidPositionException &e)
3892 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3897 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3899 client->SentBlock(q.pos);
3905 void Server::fillMediaCache()
3907 DSTACK(__FUNCTION_NAME);
3909 infostream<<"Server: Calculating media file checksums"<<std::endl;
3911 // Collect all media file paths
3912 std::list<std::string> paths;
3913 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3914 i != m_mods.end(); i++){
3915 const ModSpec &mod = *i;
3916 paths.push_back(mod.path + DIR_DELIM + "textures");
3917 paths.push_back(mod.path + DIR_DELIM + "sounds");
3918 paths.push_back(mod.path + DIR_DELIM + "media");
3919 paths.push_back(mod.path + DIR_DELIM + "models");
3921 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3923 // Collect media file information from paths into cache
3924 for(std::list<std::string>::iterator i = paths.begin();
3925 i != paths.end(); i++)
3927 std::string mediapath = *i;
3928 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3929 for(u32 j=0; j<dirlist.size(); j++){
3930 if(dirlist[j].dir) // Ignode dirs
3932 std::string filename = dirlist[j].name;
3933 // If name contains illegal characters, ignore the file
3934 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3935 infostream<<"Server: ignoring illegal file name: \""
3936 <<filename<<"\""<<std::endl;
3939 // If name is not in a supported format, ignore it
3940 const char *supported_ext[] = {
3941 ".png", ".jpg", ".bmp", ".tga",
3942 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3944 ".x", ".b3d", ".md2", ".obj",
3947 if(removeStringEnd(filename, supported_ext) == ""){
3948 infostream<<"Server: ignoring unsupported file extension: \""
3949 <<filename<<"\""<<std::endl;
3952 // Ok, attempt to load the file and add to cache
3953 std::string filepath = mediapath + DIR_DELIM + filename;
3955 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3956 if(fis.good() == false){
3957 errorstream<<"Server::fillMediaCache(): Could not open \""
3958 <<filename<<"\" for reading"<<std::endl;
3961 std::ostringstream tmp_os(std::ios_base::binary);
3965 fis.read(buf, 1024);
3966 std::streamsize len = fis.gcount();
3967 tmp_os.write(buf, len);
3976 errorstream<<"Server::fillMediaCache(): Failed to read \""
3977 <<filename<<"\""<<std::endl;
3980 if(tmp_os.str().length() == 0){
3981 errorstream<<"Server::fillMediaCache(): Empty file \""
3982 <<filepath<<"\""<<std::endl;
3987 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3989 unsigned char *digest = sha1.getDigest();
3990 std::string sha1_base64 = base64_encode(digest, 20);
3991 std::string sha1_hex = hex_encode((char*)digest, 20);
3995 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3996 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4001 struct SendableMediaAnnouncement
4004 std::string sha1_digest;
4006 SendableMediaAnnouncement(const std::string &name_="",
4007 const std::string &sha1_digest_=""):
4009 sha1_digest(sha1_digest_)
4013 void Server::sendMediaAnnouncement(u16 peer_id)
4015 DSTACK(__FUNCTION_NAME);
4017 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4020 std::list<SendableMediaAnnouncement> file_announcements;
4022 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4023 i != m_media.end(); i++){
4025 file_announcements.push_back(
4026 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4030 std::ostringstream os(std::ios_base::binary);
4038 u16 length of sha1_digest
4043 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4044 writeU16(os, file_announcements.size());
4046 for(std::list<SendableMediaAnnouncement>::iterator
4047 j = file_announcements.begin();
4048 j != file_announcements.end(); ++j){
4049 os<<serializeString(j->name);
4050 os<<serializeString(j->sha1_digest);
4052 os<<serializeString(g_settings->get("remote_media"));
4055 std::string s = os.str();
4056 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4059 m_clients.send(peer_id, 0, data, true);
4062 struct SendableMedia
4068 SendableMedia(const std::string &name_="", const std::string &path_="",
4069 const std::string &data_=""):
4076 void Server::sendRequestedMedia(u16 peer_id,
4077 const std::list<std::string> &tosend)
4079 DSTACK(__FUNCTION_NAME);
4081 verbosestream<<"Server::sendRequestedMedia(): "
4082 <<"Sending files to client"<<std::endl;
4086 // Put 5kB in one bunch (this is not accurate)
4087 u32 bytes_per_bunch = 5000;
4089 std::vector< std::list<SendableMedia> > file_bunches;
4090 file_bunches.push_back(std::list<SendableMedia>());
4092 u32 file_size_bunch_total = 0;
4094 for(std::list<std::string>::const_iterator i = tosend.begin();
4095 i != tosend.end(); ++i)
4097 const std::string &name = *i;
4099 if(m_media.find(name) == m_media.end()){
4100 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4101 <<"unknown file \""<<(name)<<"\""<<std::endl;
4105 //TODO get path + name
4106 std::string tpath = m_media[name].path;
4109 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4110 if(fis.good() == false){
4111 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4112 <<tpath<<"\" for reading"<<std::endl;
4115 std::ostringstream tmp_os(std::ios_base::binary);
4119 fis.read(buf, 1024);
4120 std::streamsize len = fis.gcount();
4121 tmp_os.write(buf, len);
4122 file_size_bunch_total += len;
4131 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4132 <<name<<"\""<<std::endl;
4135 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4136 <<tname<<"\""<<std::endl;*/
4138 file_bunches[file_bunches.size()-1].push_back(
4139 SendableMedia(name, tpath, tmp_os.str()));
4141 // Start next bunch if got enough data
4142 if(file_size_bunch_total >= bytes_per_bunch){
4143 file_bunches.push_back(std::list<SendableMedia>());
4144 file_size_bunch_total = 0;
4149 /* Create and send packets */
4151 u32 num_bunches = file_bunches.size();
4152 for(u32 i=0; i<num_bunches; i++)
4154 std::ostringstream os(std::ios_base::binary);
4158 u16 total number of texture bunches
4159 u16 index of this bunch
4160 u32 number of files in this bunch
4169 writeU16(os, TOCLIENT_MEDIA);
4170 writeU16(os, num_bunches);
4172 writeU32(os, file_bunches[i].size());
4174 for(std::list<SendableMedia>::iterator
4175 j = file_bunches[i].begin();
4176 j != file_bunches[i].end(); ++j){
4177 os<<serializeString(j->name);
4178 os<<serializeLongString(j->data);
4182 std::string s = os.str();
4183 verbosestream<<"Server::sendRequestedMedia(): bunch "
4184 <<i<<"/"<<num_bunches
4185 <<" files="<<file_bunches[i].size()
4186 <<" size=" <<s.size()<<std::endl;
4187 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4189 m_clients.send(peer_id, 2, data, true);
4193 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4195 if(m_detached_inventories.count(name) == 0){
4196 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4199 Inventory *inv = m_detached_inventories[name];
4201 std::ostringstream os(std::ios_base::binary);
4202 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4203 os<<serializeString(name);
4207 std::string s = os.str();
4208 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4210 if (peer_id != PEER_ID_INEXISTENT)
4213 m_clients.send(peer_id, 0, data, true);
4217 m_clients.sendToAll(0,data,true);
4221 void Server::sendDetachedInventories(u16 peer_id)
4223 DSTACK(__FUNCTION_NAME);
4225 for(std::map<std::string, Inventory*>::iterator
4226 i = m_detached_inventories.begin();
4227 i != m_detached_inventories.end(); i++){
4228 const std::string &name = i->first;
4229 //Inventory *inv = i->second;
4230 sendDetachedInventory(name, peer_id);
4238 void Server::DiePlayer(u16 peer_id)
4240 DSTACK(__FUNCTION_NAME);
4242 PlayerSAO *playersao = getPlayerSAO(peer_id);
4245 infostream<<"Server::DiePlayer(): Player "
4246 <<playersao->getPlayer()->getName()
4247 <<" dies"<<std::endl;
4249 playersao->setHP(0);
4251 // Trigger scripted stuff
4252 m_script->on_dieplayer(playersao);
4254 SendPlayerHP(peer_id);
4255 SendDeathscreen(peer_id, false, v3f(0,0,0));
4258 void Server::RespawnPlayer(u16 peer_id)
4260 DSTACK(__FUNCTION_NAME);
4262 PlayerSAO *playersao = getPlayerSAO(peer_id);
4265 infostream<<"Server::RespawnPlayer(): Player "
4266 <<playersao->getPlayer()->getName()
4267 <<" respawns"<<std::endl;
4269 playersao->setHP(PLAYER_MAX_HP);
4271 bool repositioned = m_script->on_respawnplayer(playersao);
4273 v3f pos = findSpawnPos(m_env->getServerMap());
4274 playersao->setPos(pos);
4278 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4280 DSTACK(__FUNCTION_NAME);
4282 SendAccessDenied(peer_id, reason);
4283 m_clients.event(peer_id,SetDenied);
4284 m_con.DisconnectPeer(peer_id);
4287 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4289 DSTACK(__FUNCTION_NAME);
4290 std::wstring message;
4293 Clear references to playing sounds
4295 for(std::map<s32, ServerPlayingSound>::iterator
4296 i = m_playing_sounds.begin();
4297 i != m_playing_sounds.end();)
4299 ServerPlayingSound &psound = i->second;
4300 psound.clients.erase(peer_id);
4301 if(psound.clients.size() == 0)
4302 m_playing_sounds.erase(i++);
4307 Player *player = m_env->getPlayer(peer_id);
4309 // Collect information about leaving in chat
4311 if(player != NULL && reason != CDR_DENY)
4313 std::wstring name = narrow_to_wide(player->getName());
4316 message += L" left the game.";
4317 if(reason == CDR_TIMEOUT)
4318 message += L" (timed out)";
4322 /* Run scripts and remove from environment */
4326 PlayerSAO *playersao = player->getPlayerSAO();
4329 m_script->on_leaveplayer(playersao);
4331 playersao->disconnected();
4339 if(player != NULL && reason != CDR_DENY)
4341 std::ostringstream os(std::ios_base::binary);
4342 std::list<u16> clients = m_clients.getClientIDs();
4344 for(std::list<u16>::iterator
4345 i = clients.begin();
4346 i != clients.end(); ++i)
4349 Player *player = m_env->getPlayer(*i);
4352 // Get name of player
4353 os<<player->getName()<<" ";
4356 actionstream<<player->getName()<<" "
4357 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4358 <<" List of players: "<<os.str()<<std::endl;
4362 JMutexAutoLock env_lock(m_env_mutex);
4363 m_clients.DeleteClient(peer_id);
4367 // Send leave chat message to all remaining clients
4368 if(message.length() != 0)
4369 SendChatMessage(PEER_ID_INEXISTENT,message);
4372 void Server::UpdateCrafting(u16 peer_id)
4374 DSTACK(__FUNCTION_NAME);
4376 Player* player = m_env->getPlayer(peer_id);
4379 // Get a preview for crafting
4381 InventoryLocation loc;
4382 loc.setPlayer(player->getName());
4383 getCraftingResult(&player->inventory, preview, false, this);
4384 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4386 // Put the new preview in
4387 InventoryList *plist = player->inventory.getList("craftpreview");
4389 assert(plist->getSize() >= 1);
4390 plist->changeItem(0, preview);
4393 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4395 RemoteClient *client = getClientNoEx(peer_id,state_min);
4397 throw ClientNotFoundException("Client not found");
4401 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4403 return m_clients.getClientNoEx(peer_id, state_min);
4406 std::string Server::getPlayerName(u16 peer_id)
4408 Player *player = m_env->getPlayer(peer_id);
4410 return "[id="+itos(peer_id)+"]";
4411 return player->getName();
4414 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4416 Player *player = m_env->getPlayer(peer_id);
4419 return player->getPlayerSAO();
4422 std::wstring Server::getStatusString()
4424 std::wostringstream os(std::ios_base::binary);
4427 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4429 os<<L", uptime="<<m_uptime.get();
4431 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4432 // Information about clients
4435 std::list<u16> clients = m_clients.getClientIDs();
4436 for(std::list<u16>::iterator i = clients.begin();
4437 i != clients.end(); ++i)
4440 Player *player = m_env->getPlayer(*i);
4441 // Get name of player
4442 std::wstring name = L"unknown";
4444 name = narrow_to_wide(player->getName());
4445 // Add name to information string
4453 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4454 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4455 if(g_settings->get("motd") != "")
4456 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4460 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4462 std::set<std::string> privs;
4463 m_script->getAuth(name, NULL, &privs);
4467 bool Server::checkPriv(const std::string &name, const std::string &priv)
4469 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4470 return (privs.count(priv) != 0);
4473 void Server::reportPrivsModified(const std::string &name)
4476 std::list<u16> clients = m_clients.getClientIDs();
4477 for(std::list<u16>::iterator
4478 i = clients.begin();
4479 i != clients.end(); ++i){
4480 Player *player = m_env->getPlayer(*i);
4481 reportPrivsModified(player->getName());
4484 Player *player = m_env->getPlayer(name.c_str());
4487 SendPlayerPrivileges(player->peer_id);
4488 PlayerSAO *sao = player->getPlayerSAO();
4491 sao->updatePrivileges(
4492 getPlayerEffectivePrivs(name),
4497 void Server::reportInventoryFormspecModified(const std::string &name)
4499 Player *player = m_env->getPlayer(name.c_str());
4502 SendPlayerInventoryFormspec(player->peer_id);
4505 void Server::setIpBanned(const std::string &ip, const std::string &name)
4507 m_banmanager->add(ip, name);
4510 void Server::unsetIpBanned(const std::string &ip_or_name)
4512 m_banmanager->remove(ip_or_name);
4515 std::string Server::getBanDescription(const std::string &ip_or_name)
4517 return m_banmanager->getBanDescription(ip_or_name);
4520 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4522 Player *player = m_env->getPlayer(name);
4526 if (player->peer_id == PEER_ID_INEXISTENT)
4529 SendChatMessage(player->peer_id, msg);
4532 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4534 Player *player = m_env->getPlayer(playername);
4538 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4542 SendShowFormspecMessage(player->peer_id, formspec, formname);
4546 u32 Server::hudAdd(Player *player, HudElement *form) {
4550 u32 id = player->getFreeHudID();
4551 if (id < player->hud.size())
4552 player->hud[id] = form;
4554 player->hud.push_back(form);
4556 SendHUDAdd(player->peer_id, id, form);
4560 bool Server::hudRemove(Player *player, u32 id) {
4561 if (!player || id >= player->hud.size() || !player->hud[id])
4564 delete player->hud[id];
4565 player->hud[id] = NULL;
4567 SendHUDRemove(player->peer_id, id);
4571 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4575 SendHUDChange(player->peer_id, id, stat, data);
4579 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4583 SendHUDSetFlags(player->peer_id, flags, mask);
4587 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4590 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4593 std::ostringstream os(std::ios::binary);
4594 writeS32(os, hotbar_itemcount);
4595 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4599 void Server::hudSetHotbarImage(Player *player, std::string name) {
4603 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4606 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4610 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4613 bool Server::setLocalPlayerAnimations(Player *player, v2f animation_frames[4], f32 frame_speed)
4618 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4622 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4627 SendEyeOffset(player->peer_id, first, third);
4631 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4632 const std::string &type, const std::vector<std::string> ¶ms)
4637 SendSetSky(player->peer_id, bgcolor, type, params);
4641 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4647 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4651 void Server::notifyPlayers(const std::wstring &msg)
4653 SendChatMessage(PEER_ID_INEXISTENT,msg);
4656 void Server::spawnParticle(const char *playername, v3f pos,
4657 v3f velocity, v3f acceleration,
4658 float expirationtime, float size, bool
4659 collisiondetection, bool vertical, std::string texture)
4661 Player *player = m_env->getPlayer(playername);
4664 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4665 expirationtime, size, collisiondetection, vertical, texture);
4668 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4669 float expirationtime, float size,
4670 bool collisiondetection, bool vertical, std::string texture)
4672 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4673 expirationtime, size, collisiondetection, vertical, texture);
4676 u32 Server::addParticleSpawner(const char *playername,
4677 u16 amount, float spawntime,
4678 v3f minpos, v3f maxpos,
4679 v3f minvel, v3f maxvel,
4680 v3f minacc, v3f maxacc,
4681 float minexptime, float maxexptime,
4682 float minsize, float maxsize,
4683 bool collisiondetection, bool vertical, std::string texture)
4685 Player *player = m_env->getPlayer(playername);
4690 for(;;) // look for unused particlespawner id
4693 if (std::find(m_particlespawner_ids.begin(),
4694 m_particlespawner_ids.end(), id)
4695 == m_particlespawner_ids.end())
4697 m_particlespawner_ids.push_back(id);
4702 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4703 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4704 minexptime, maxexptime, minsize, maxsize,
4705 collisiondetection, vertical, texture, id);
4710 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4711 v3f minpos, v3f maxpos,
4712 v3f minvel, v3f maxvel,
4713 v3f minacc, v3f maxacc,
4714 float minexptime, float maxexptime,
4715 float minsize, float maxsize,
4716 bool collisiondetection, bool vertical, std::string texture)
4719 for(;;) // look for unused particlespawner id
4722 if (std::find(m_particlespawner_ids.begin(),
4723 m_particlespawner_ids.end(), id)
4724 == m_particlespawner_ids.end())
4726 m_particlespawner_ids.push_back(id);
4731 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4732 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4733 minexptime, maxexptime, minsize, maxsize,
4734 collisiondetection, vertical, texture, id);
4739 void Server::deleteParticleSpawner(const char *playername, u32 id)
4741 Player *player = m_env->getPlayer(playername);
4745 m_particlespawner_ids.erase(
4746 std::remove(m_particlespawner_ids.begin(),
4747 m_particlespawner_ids.end(), id),
4748 m_particlespawner_ids.end());
4749 SendDeleteParticleSpawner(player->peer_id, id);
4752 void Server::deleteParticleSpawnerAll(u32 id)
4754 m_particlespawner_ids.erase(
4755 std::remove(m_particlespawner_ids.begin(),
4756 m_particlespawner_ids.end(), id),
4757 m_particlespawner_ids.end());
4758 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4761 Inventory* Server::createDetachedInventory(const std::string &name)
4763 if(m_detached_inventories.count(name) > 0){
4764 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4765 delete m_detached_inventories[name];
4767 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4769 Inventory *inv = new Inventory(m_itemdef);
4771 m_detached_inventories[name] = inv;
4772 //TODO find a better way to do this
4773 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4780 BoolScopeSet(bool *dst, bool val):
4783 m_orig_state = *m_dst;
4788 *m_dst = m_orig_state;
4795 // actions: time-reversed list
4796 // Return value: success/failure
4797 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4798 std::list<std::string> *log)
4800 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4801 ServerMap *map = (ServerMap*)(&m_env->getMap());
4802 // Disable rollback report sink while reverting
4803 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4805 // Fail if no actions to handle
4806 if(actions.empty()){
4807 log->push_back("Nothing to do.");
4814 for(std::list<RollbackAction>::const_iterator
4815 i = actions.begin();
4816 i != actions.end(); i++)
4818 const RollbackAction &action = *i;
4820 bool success = action.applyRevert(map, this, this);
4823 std::ostringstream os;
4824 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4825 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4827 log->push_back(os.str());
4829 std::ostringstream os;
4830 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4831 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4833 log->push_back(os.str());
4837 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4838 <<" failed"<<std::endl;
4840 // Call it done if less than half failed
4841 return num_failed <= num_tried/2;
4844 // IGameDef interface
4846 IItemDefManager* Server::getItemDefManager()
4850 INodeDefManager* Server::getNodeDefManager()
4854 ICraftDefManager* Server::getCraftDefManager()
4858 ITextureSource* Server::getTextureSource()
4862 IShaderSource* Server::getShaderSource()
4866 u16 Server::allocateUnknownNodeId(const std::string &name)
4868 return m_nodedef->allocateDummy(name);
4870 ISoundManager* Server::getSoundManager()
4872 return &dummySoundManager;
4874 MtEventManager* Server::getEventManager()
4878 IRollbackReportSink* Server::getRollbackReportSink()
4880 if(!m_enable_rollback_recording)
4882 if(!m_rollback_sink_enabled)
4887 IWritableItemDefManager* Server::getWritableItemDefManager()
4891 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4895 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4900 const ModSpec* Server::getModSpec(const std::string &modname)
4902 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4903 i != m_mods.end(); i++){
4904 const ModSpec &mod = *i;
4905 if(mod.name == modname)
4910 void Server::getModNames(std::list<std::string> &modlist)
4912 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4914 modlist.push_back(i->name);
4917 std::string Server::getBuiltinLuaPath()
4919 return porting::path_share + DIR_DELIM + "builtin";
4922 v3f findSpawnPos(ServerMap &map)
4924 //return v3f(50,50,50)*BS;
4929 nodepos = v2s16(0,0);
4934 s16 water_level = map.getWaterLevel();
4936 // Try to find a good place a few times
4937 for(s32 i=0; i<1000; i++)
4940 // We're going to try to throw the player to this position
4941 v2s16 nodepos2d = v2s16(
4942 -range + (myrand() % (range * 2)),
4943 -range + (myrand() % (range * 2)));
4945 // Get ground height at point
4946 s16 groundheight = map.findGroundLevel(nodepos2d);
4947 if (groundheight <= water_level) // Don't go underwater
4949 if (groundheight > water_level + 6) // Don't go to high places
4952 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4953 bool is_good = false;
4955 for (s32 i = 0; i < 10; i++) {
4956 v3s16 blockpos = getNodeBlockPos(nodepos);
4957 map.emergeBlock(blockpos, true);
4958 content_t c = map.getNodeNoEx(nodepos).getContent();
4959 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4961 if (air_count >= 2){
4969 // Found a good place
4970 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4976 return intToFloat(nodepos, BS);
4979 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4981 RemotePlayer *player = NULL;
4982 bool newplayer = false;
4985 Try to get an existing player
4987 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4989 // If player is already connected, cancel
4990 if(player != NULL && player->peer_id != 0)
4992 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4997 If player with the wanted peer_id already exists, cancel.
4999 if(m_env->getPlayer(peer_id) != NULL)
5001 infostream<<"emergePlayer(): Player with wrong name but same"
5002 " peer_id already exists"<<std::endl;
5007 Create a new player if it doesn't exist yet
5012 player = new RemotePlayer(this);
5013 player->updateName(name);
5015 /* Set player position */
5016 infostream<<"Server: Finding spawn place for player \""
5017 <<name<<"\""<<std::endl;
5018 v3f pos = findSpawnPos(m_env->getServerMap());
5019 player->setPosition(pos);
5021 /* Add player to environment */
5022 m_env->addPlayer(player);
5026 Create a new player active object
5028 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5029 getPlayerEffectivePrivs(player->getName()),
5032 /* Clean up old HUD elements from previous sessions */
5033 player->hud.clear();
5035 /* Add object to environment */
5036 m_env->addActiveObject(playersao);
5040 m_script->on_newplayer(playersao);
5045 void dedicated_server_loop(Server &server, bool &kill)
5047 DSTACK(__FUNCTION_NAME);
5049 verbosestream<<"dedicated_server_loop()"<<std::endl;
5051 IntervalLimiter m_profiler_interval;
5055 float steplen = g_settings->getFloat("dedicated_server_step");
5056 // This is kind of a hack but can be done like this
5057 // because server.step() is very light
5059 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5060 sleep_ms((int)(steplen*1000.0));
5062 server.step(steplen);
5064 if(server.getShutdownRequested() || kill)
5066 infostream<<"Dedicated server quitting"<<std::endl;
5068 if(g_settings->getBool("server_announce") == true)
5069 ServerList::sendAnnounce("delete");
5077 float profiler_print_interval =
5078 g_settings->getFloat("profiler_print_interval");
5079 if(profiler_print_interval != 0)
5081 if(m_profiler_interval.step(steplen, profiler_print_interval))
5083 infostream<<"Profiler:"<<std::endl;
5084 g_profiler->print(infostream);
5085 g_profiler->clear();