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 while(!StopRequested())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
107 m_server->AsyncRunStep();
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
165 const std::string &path_world,
166 const SubgameSpec &gamespec,
167 bool simple_singleplayer_mode
169 m_path_world(path_world),
170 m_gamespec(gamespec),
171 m_simple_singleplayer_mode(simple_singleplayer_mode),
172 m_async_fatal_error(""),
177 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
181 m_rollback_sink_enabled(true),
182 m_enable_rollback_recording(false),
185 m_itemdef(createItemDefManager()),
186 m_nodedef(createNodeDefManager()),
187 m_craftdef(createCraftDefManager()),
188 m_event(new EventManager()),
190 m_time_of_day_send_timer(0),
193 m_shutdown_requested(false),
194 m_ignore_map_edit_events(false),
195 m_ignore_map_edit_events_peer_id(0)
198 m_liquid_transform_timer = 0.0;
199 m_liquid_transform_every = 1.0;
200 m_print_info_timer = 0.0;
201 m_masterserver_timer = 0.0;
202 m_objectdata_timer = 0.0;
203 m_emergethread_trigger_timer = 0.0;
204 m_savemap_timer = 0.0;
207 m_lag = g_settings->getFloat("dedicated_server_step");
210 throw ServerError("Supplied empty world path");
212 if(!gamespec.isValid())
213 throw ServerError("Supplied invalid gamespec");
215 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
216 if(m_simple_singleplayer_mode)
217 infostream<<" in simple singleplayer mode"<<std::endl;
219 infostream<<std::endl;
220 infostream<<"- world: "<<m_path_world<<std::endl;
221 infostream<<"- game: "<<m_gamespec.path<<std::endl;
223 // Initialize default settings and override defaults with those provided
225 set_default_settings(g_settings);
226 Settings gamedefaults;
227 getGameMinetestConfig(gamespec.path, gamedefaults);
228 override_default_settings(g_settings, &gamedefaults);
230 // Create server thread
231 m_thread = new ServerThread(this);
233 // Create emerge manager
234 m_emerge = new EmergeManager(this);
236 // Create world if it doesn't exist
237 if(!initializeWorld(m_path_world, m_gamespec.id))
238 throw ServerError("Failed to initialize world");
240 // Create ban manager
241 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
242 m_banmanager = new BanManager(ban_path);
244 // Create rollback manager
245 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
246 m_rollback = createRollbackManager(rollback_path, this);
248 ModConfiguration modconf(m_path_world);
249 m_mods = modconf.getMods();
250 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
251 // complain about mods with unsatisfied dependencies
252 if(!modconf.isConsistent())
254 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
255 it != unsatisfied_mods.end(); ++it)
258 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
259 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
260 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
261 errorstream << " \"" << *dep_it << "\"";
262 errorstream << std::endl;
266 Settings worldmt_settings;
267 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
268 worldmt_settings.readConfigFile(worldmt.c_str());
269 std::vector<std::string> names = worldmt_settings.getNames();
270 std::set<std::string> load_mod_names;
271 for(std::vector<std::string>::iterator it = names.begin();
272 it != names.end(); ++it)
274 std::string name = *it;
275 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
276 load_mod_names.insert(name.substr(9));
278 // complain about mods declared to be loaded, but not found
279 for(std::vector<ModSpec>::iterator it = m_mods.begin();
280 it != m_mods.end(); ++it)
281 load_mod_names.erase((*it).name);
282 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
283 it != unsatisfied_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 if(!load_mod_names.empty())
287 errorstream << "The following mods could not be found:";
288 for(std::set<std::string>::iterator it = load_mod_names.begin();
289 it != load_mod_names.end(); ++it)
290 errorstream << " \"" << (*it) << "\"";
291 errorstream << std::endl;
294 // Path to builtin.lua
295 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
298 JMutexAutoLock envlock(m_env_mutex);
300 // Initialize scripting
301 infostream<<"Server: Initializing Lua"<<std::endl;
303 m_script = new GameScripting(this);
306 // Load and run builtin.lua
307 infostream<<"Server: Loading builtin.lua [\""
308 <<builtinpath<<"\"]"<<std::endl;
309 bool success = m_script->loadMod(builtinpath, "__builtin");
311 errorstream<<"Server: Failed to load and run "
312 <<builtinpath<<std::endl;
313 throw ModError("Failed to load and run "+builtinpath);
316 infostream<<"Server: Loading mods: ";
317 for(std::vector<ModSpec>::iterator i = m_mods.begin();
318 i != m_mods.end(); i++){
319 const ModSpec &mod = *i;
320 infostream<<mod.name<<" ";
322 infostream<<std::endl;
323 // Load and run "mod" scripts
324 for(std::vector<ModSpec>::iterator i = m_mods.begin();
325 i != m_mods.end(); i++){
326 const ModSpec &mod = *i;
327 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
328 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
329 <<scriptpath<<"\"]"<<std::endl;
330 bool success = m_script->loadMod(scriptpath, mod.name);
332 errorstream<<"Server: Failed to load and run "
333 <<scriptpath<<std::endl;
334 throw ModError("Failed to load and run "+scriptpath);
338 // Read Textures and calculate sha1 sums
341 // Apply item aliases in the node definition manager
342 m_nodedef->updateAliases(m_itemdef);
344 // Load the mapgen params from global settings now after any
345 // initial overrides have been set by the mods
346 m_emerge->loadMapgenParams();
348 // Initialize Environment
349 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
350 m_env = new ServerEnvironment(servermap, m_script, this);
352 m_clients.setEnv(m_env);
354 // Run some callbacks after the MG params have been set up but before activation
355 m_script->environment_OnMapgenInit(&m_emerge->params);
357 // Initialize mapgens
358 m_emerge->initMapgens();
360 // Give environment reference to scripting api
361 m_script->initializeEnvironment(m_env);
363 // Register us to receive map edit events
364 servermap->addEventReceiver(this);
366 // If file exists, load environment metadata
367 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
369 infostream<<"Server: Loading environment metadata"<<std::endl;
370 m_env->loadMeta(m_path_world);
374 infostream<<"Server: Loading players"<<std::endl;
375 m_env->deSerializePlayers(m_path_world);
378 Add some test ActiveBlockModifiers to environment
380 add_legacy_abms(m_env, m_nodedef);
382 m_liquid_transform_every = g_settings->getFloat("liquid_update");
387 infostream<<"Server destructing"<<std::endl;
390 Send shutdown message
393 std::wstring line = L"*** Server shutting down";
394 SendChatMessage(PEER_ID_INEXISTENT, line);
398 JMutexAutoLock envlock(m_env_mutex);
401 Execute script shutdown hooks
403 m_script->on_shutdown();
407 JMutexAutoLock envlock(m_env_mutex);
412 infostream<<"Server: Saving players"<<std::endl;
413 m_env->serializePlayers(m_path_world);
416 Save environment metadata
418 infostream<<"Server: Saving environment metadata"<<std::endl;
419 m_env->saveMeta(m_path_world);
428 // stop all emerge threads before deleting players that may have
429 // requested blocks to be emerged
430 m_emerge->stopThreads();
432 // Delete things in the reverse order of creation
435 // N.B. the EmergeManager should be deleted after the Environment since Map
436 // depends on EmergeManager to write its current params to the map meta
445 // Deinitialize scripting
446 infostream<<"Server: Deinitializing scripting"<<std::endl;
449 // Delete detached inventories
451 for(std::map<std::string, Inventory*>::iterator
452 i = m_detached_inventories.begin();
453 i != m_detached_inventories.end(); i++){
459 void Server::start(Address bind_addr)
461 DSTACK(__FUNCTION_NAME);
462 infostream<<"Starting server on "
463 << bind_addr.serializeString() <<"..."<<std::endl;
465 // Stop thread if already running
468 // Initialize connection
469 m_con.SetTimeoutMs(30);
470 m_con.Serve(bind_addr);
475 // ASCII art for the win!
477 <<" .__ __ __ "<<std::endl
478 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
479 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
480 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
481 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
482 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
483 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
484 actionstream<<"Server for gameid=\""<<m_gamespec.id
485 <<"\" listening on "<<bind_addr.serializeString()<<":"
486 <<bind_addr.getPort() << "."<<std::endl;
491 DSTACK(__FUNCTION_NAME);
493 infostream<<"Server: Stopping and waiting threads"<<std::endl;
495 // Stop threads (set run=false first so both start stopping)
497 //m_emergethread.setRun(false);
499 //m_emergethread.stop();
501 infostream<<"Server: Threads stopped"<<std::endl;
504 void Server::step(float dtime)
506 DSTACK(__FUNCTION_NAME);
511 JMutexAutoLock lock(m_step_dtime_mutex);
512 m_step_dtime += dtime;
514 // Throw if fatal error occurred in thread
515 std::string async_err = m_async_fatal_error.get();
517 throw ServerError(async_err);
521 void Server::AsyncRunStep(bool initial_step)
523 DSTACK(__FUNCTION_NAME);
525 g_profiler->add("Server::AsyncRunStep (num)", 1);
529 JMutexAutoLock lock1(m_step_dtime_mutex);
530 dtime = m_step_dtime;
534 // Send blocks to clients
538 if((dtime < 0.001) && (initial_step == false))
541 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
543 //infostream<<"Server steps "<<dtime<<std::endl;
544 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
547 JMutexAutoLock lock1(m_step_dtime_mutex);
548 m_step_dtime -= dtime;
555 m_uptime.set(m_uptime.get() + dtime);
561 Update time of day and overall game time
564 JMutexAutoLock envlock(m_env_mutex);
566 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
569 Send to clients at constant intervals
572 m_time_of_day_send_timer -= dtime;
573 if(m_time_of_day_send_timer < 0.0)
575 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
576 u16 time = m_env->getTimeOfDay();
577 float time_speed = g_settings->getFloat("time_speed");
578 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
583 JMutexAutoLock lock(m_env_mutex);
584 // Figure out and report maximum lag to environment
585 float max_lag = m_env->getMaxLagEstimate();
586 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
588 if(dtime > 0.1 && dtime > max_lag * 2.0)
589 infostream<<"Server: Maximum lag peaked to "<<dtime
593 m_env->reportMaxLagEstimate(max_lag);
595 ScopeProfiler sp(g_profiler, "SEnv step");
596 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
600 const float map_timer_and_unload_dtime = 2.92;
601 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
603 JMutexAutoLock lock(m_env_mutex);
604 // Run Map's timers and unload unused data
605 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
606 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
607 g_settings->getFloat("server_unload_unused_data_timeout"));
618 JMutexAutoLock lock(m_env_mutex);
620 std::list<u16> clientids = m_clients.getClientIDs();
622 ScopeProfiler sp(g_profiler, "Server: handle players");
624 for(std::list<u16>::iterator
625 i = clientids.begin();
626 i != clientids.end(); ++i)
628 PlayerSAO *playersao = getPlayerSAO(*i);
629 if(playersao == NULL)
633 Handle player HPs (die if hp=0)
635 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
637 if(playersao->getHP() == 0)
644 Send player breath if changed
646 if(playersao->m_breath_not_sent){
647 SendPlayerBreath(*i);
651 Send player inventories if necessary
653 if(playersao->m_moved){
655 playersao->m_moved = false;
657 if(playersao->m_inventory_not_sent){
664 /* Transform liquids */
665 m_liquid_transform_timer += dtime;
666 if(m_liquid_transform_timer >= m_liquid_transform_every)
668 m_liquid_transform_timer -= m_liquid_transform_every;
670 JMutexAutoLock lock(m_env_mutex);
672 ScopeProfiler sp(g_profiler, "Server: liquid transform");
674 std::map<v3s16, MapBlock*> modified_blocks;
675 m_env->getMap().transformLiquids(modified_blocks);
680 core::map<v3s16, MapBlock*> lighting_modified_blocks;
681 ServerMap &map = ((ServerMap&)m_env->getMap());
682 map.updateLighting(modified_blocks, lighting_modified_blocks);
684 // Add blocks modified by lighting to modified_blocks
685 for(core::map<v3s16, MapBlock*>::Iterator
686 i = lighting_modified_blocks.getIterator();
687 i.atEnd() == false; i++)
689 MapBlock *block = i.getNode()->getValue();
690 modified_blocks.insert(block->getPos(), block);
694 Set the modified blocks unsent for all the clients
696 if(modified_blocks.size() > 0)
698 SetBlocksNotSent(modified_blocks);
701 m_clients.step(dtime);
703 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
705 // send masterserver announce
707 float &counter = m_masterserver_timer;
708 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
709 g_settings->getBool("server_announce") == true)
711 ServerList::sendAnnounce(!counter ? "start" : "update",
712 m_clients.getPlayerNames(),
714 m_env->getGameTime(),
725 Check added and deleted active objects
728 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
729 JMutexAutoLock envlock(m_env_mutex);
732 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
733 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
735 // Radius inside which objects are active
736 s16 radius = g_settings->getS16("active_object_send_range_blocks");
737 radius *= MAP_BLOCKSIZE;
739 for(std::map<u16, RemoteClient*>::iterator
741 i != clients.end(); ++i)
743 RemoteClient *client = i->second;
745 // If definitions and textures have not been sent, don't
746 // send objects either
747 if (client->getState() < DefinitionsSent)
750 Player *player = m_env->getPlayer(client->peer_id);
753 // This can happen if the client timeouts somehow
754 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
756 <<" has no associated player"<<std::endl;*/
759 v3s16 pos = floatToInt(player->getPosition(), BS);
761 std::set<u16> removed_objects;
762 std::set<u16> added_objects;
763 m_env->getRemovedActiveObjects(pos, radius,
764 client->m_known_objects, removed_objects);
765 m_env->getAddedActiveObjects(pos, radius,
766 client->m_known_objects, added_objects);
768 // Ignore if nothing happened
769 if(removed_objects.size() == 0 && added_objects.size() == 0)
771 //infostream<<"active objects: none changed"<<std::endl;
775 std::string data_buffer;
779 // Handle removed objects
780 writeU16((u8*)buf, removed_objects.size());
781 data_buffer.append(buf, 2);
782 for(std::set<u16>::iterator
783 i = removed_objects.begin();
784 i != removed_objects.end(); ++i)
788 ServerActiveObject* obj = m_env->getActiveObject(id);
790 // Add to data buffer for sending
791 writeU16((u8*)buf, id);
792 data_buffer.append(buf, 2);
794 // Remove from known objects
795 client->m_known_objects.erase(id);
797 if(obj && obj->m_known_by_count > 0)
798 obj->m_known_by_count--;
801 // Handle added objects
802 writeU16((u8*)buf, added_objects.size());
803 data_buffer.append(buf, 2);
804 for(std::set<u16>::iterator
805 i = added_objects.begin();
806 i != added_objects.end(); ++i)
810 ServerActiveObject* obj = m_env->getActiveObject(id);
813 u8 type = ACTIVEOBJECT_TYPE_INVALID;
815 infostream<<"WARNING: "<<__FUNCTION_NAME
816 <<": NULL object"<<std::endl;
818 type = obj->getSendType();
820 // Add to data buffer for sending
821 writeU16((u8*)buf, id);
822 data_buffer.append(buf, 2);
823 writeU8((u8*)buf, type);
824 data_buffer.append(buf, 1);
827 data_buffer.append(serializeLongString(
828 obj->getClientInitializationData(client->net_proto_version)));
830 data_buffer.append(serializeLongString(""));
832 // Add to known objects
833 client->m_known_objects.insert(id);
836 obj->m_known_by_count++;
840 SharedBuffer<u8> reply(2 + data_buffer.size());
841 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
842 memcpy((char*)&reply[2], data_buffer.c_str(),
845 m_clients.send(client->peer_id, 0, reply, true);
847 verbosestream<<"Server: Sent object remove/add: "
848 <<removed_objects.size()<<" removed, "
849 <<added_objects.size()<<" added, "
850 <<"packet size is "<<reply.getSize()<<std::endl;
855 Collect a list of all the objects known by the clients
856 and report it back to the environment.
859 core::map<u16, bool> all_known_objects;
861 for(core::map<u16, RemoteClient*>::Iterator
862 i = m_clients.getIterator();
863 i.atEnd() == false; i++)
865 RemoteClient *client = i.getNode()->getValue();
866 // Go through all known objects of client
867 for(core::map<u16, bool>::Iterator
868 i = client->m_known_objects.getIterator();
869 i.atEnd()==false; i++)
871 u16 id = i.getNode()->getKey();
872 all_known_objects[id] = true;
876 m_env->setKnownActiveObjects(whatever);
885 JMutexAutoLock envlock(m_env_mutex);
886 ScopeProfiler sp(g_profiler, "Server: sending object messages");
889 // Value = data sent by object
890 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
892 // Get active object messages from environment
895 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
899 std::list<ActiveObjectMessage>* message_list = NULL;
900 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
901 n = buffered_messages.find(aom.id);
902 if(n == buffered_messages.end())
904 message_list = new std::list<ActiveObjectMessage>;
905 buffered_messages[aom.id] = message_list;
909 message_list = n->second;
911 message_list->push_back(aom);
915 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
916 // Route data to every client
917 for(std::map<u16, RemoteClient*>::iterator
919 i != clients.end(); ++i)
921 RemoteClient *client = i->second;
922 std::string reliable_data;
923 std::string unreliable_data;
924 // Go through all objects in message buffer
925 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
926 j = buffered_messages.begin();
927 j != buffered_messages.end(); ++j)
929 // If object is not known by client, skip it
931 if(client->m_known_objects.find(id) == client->m_known_objects.end())
933 // Get message list of object
934 std::list<ActiveObjectMessage>* list = j->second;
935 // Go through every message
936 for(std::list<ActiveObjectMessage>::iterator
937 k = list->begin(); k != list->end(); ++k)
939 // Compose the full new data with header
940 ActiveObjectMessage aom = *k;
941 std::string new_data;
944 writeU16((u8*)&buf[0], aom.id);
945 new_data.append(buf, 2);
947 new_data += serializeString(aom.datastring);
948 // Add data to buffer
950 reliable_data += new_data;
952 unreliable_data += new_data;
956 reliable_data and unreliable_data are now ready.
959 if(reliable_data.size() > 0)
961 SharedBuffer<u8> reply(2 + reliable_data.size());
962 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
963 memcpy((char*)&reply[2], reliable_data.c_str(),
964 reliable_data.size());
966 m_clients.send(client->peer_id, 0, reply, true);
968 if(unreliable_data.size() > 0)
970 SharedBuffer<u8> reply(2 + unreliable_data.size());
971 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
972 memcpy((char*)&reply[2], unreliable_data.c_str(),
973 unreliable_data.size());
974 // Send as unreliable
975 m_clients.send(client->peer_id, 1, reply, false);
978 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
980 infostream<<"Server: Size of object message data: "
981 <<"reliable: "<<reliable_data.size()
982 <<", unreliable: "<<unreliable_data.size()
988 // Clear buffered_messages
989 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
990 i = buffered_messages.begin();
991 i != buffered_messages.end(); ++i)
998 Send queued-for-sending map edit events.
1001 // We will be accessing the environment
1002 JMutexAutoLock lock(m_env_mutex);
1004 // Don't send too many at a time
1007 // Single change sending is disabled if queue size is not small
1008 bool disable_single_change_sending = false;
1009 if(m_unsent_map_edit_queue.size() >= 4)
1010 disable_single_change_sending = true;
1012 int event_count = m_unsent_map_edit_queue.size();
1014 // We'll log the amount of each
1017 while(m_unsent_map_edit_queue.size() != 0)
1019 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1021 // Players far away from the change are stored here.
1022 // Instead of sending the changes, MapBlocks are set not sent
1024 std::list<u16> far_players;
1026 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1028 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1029 prof.add("MEET_ADDNODE", 1);
1030 if(disable_single_change_sending)
1031 sendAddNode(event->p, event->n, event->already_known_by_peer,
1032 &far_players, 5, event->type == MEET_ADDNODE);
1034 sendAddNode(event->p, event->n, event->already_known_by_peer,
1035 &far_players, 30, event->type == MEET_ADDNODE);
1037 else if(event->type == MEET_REMOVENODE)
1039 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1040 prof.add("MEET_REMOVENODE", 1);
1041 if(disable_single_change_sending)
1042 sendRemoveNode(event->p, event->already_known_by_peer,
1045 sendRemoveNode(event->p, event->already_known_by_peer,
1048 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1050 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1051 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1052 setBlockNotSent(event->p);
1054 else if(event->type == MEET_OTHER)
1056 infostream<<"Server: MEET_OTHER"<<std::endl;
1057 prof.add("MEET_OTHER", 1);
1058 for(std::set<v3s16>::iterator
1059 i = event->modified_blocks.begin();
1060 i != event->modified_blocks.end(); ++i)
1062 setBlockNotSent(*i);
1067 prof.add("unknown", 1);
1068 infostream<<"WARNING: Server: Unknown MapEditEvent "
1069 <<((u32)event->type)<<std::endl;
1073 Set blocks not sent to far players
1075 if(far_players.size() > 0)
1077 // Convert list format to that wanted by SetBlocksNotSent
1078 std::map<v3s16, MapBlock*> modified_blocks2;
1079 for(std::set<v3s16>::iterator
1080 i = event->modified_blocks.begin();
1081 i != event->modified_blocks.end(); ++i)
1083 modified_blocks2[*i] =
1084 m_env->getMap().getBlockNoCreateNoEx(*i);
1086 // Set blocks not sent
1087 for(std::list<u16>::iterator
1088 i = far_players.begin();
1089 i != far_players.end(); ++i)
1092 RemoteClient *client = getClient(peer_id);
1095 client->SetBlocksNotSent(modified_blocks2);
1101 /*// Don't send too many at a time
1103 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1107 if(event_count >= 5){
1108 infostream<<"Server: MapEditEvents:"<<std::endl;
1109 prof.print(infostream);
1110 } else if(event_count != 0){
1111 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1112 prof.print(verbosestream);
1118 Trigger emergethread (it somehow gets to a non-triggered but
1119 bysy state sometimes)
1122 float &counter = m_emergethread_trigger_timer;
1128 m_emerge->startThreads();
1130 // Update m_enable_rollback_recording here too
1131 m_enable_rollback_recording =
1132 g_settings->getBool("enable_rollback_recording");
1136 // Save map, players and auth stuff
1138 float &counter = m_savemap_timer;
1140 if(counter >= g_settings->getFloat("server_map_save_interval"))
1143 JMutexAutoLock lock(m_env_mutex);
1145 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1148 if(m_banmanager->isModified())
1149 m_banmanager->save();
1151 // Save changed parts of map
1152 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1155 m_env->serializePlayers(m_path_world);
1157 // Save environment metadata
1158 m_env->saveMeta(m_path_world);
1163 void Server::Receive()
1165 DSTACK(__FUNCTION_NAME);
1166 SharedBuffer<u8> data;
1170 datasize = m_con.Receive(peer_id,data);
1171 ProcessData(*data, datasize, peer_id);
1173 catch(con::InvalidIncomingDataException &e)
1175 infostream<<"Server::Receive(): "
1176 "InvalidIncomingDataException: what()="
1177 <<e.what()<<std::endl;
1179 catch(con::PeerNotFoundException &e)
1181 //NOTE: This is not needed anymore
1183 // The peer has been disconnected.
1184 // Find the associated player and remove it.
1186 /*JMutexAutoLock envlock(m_env_mutex);
1188 infostream<<"ServerThread: peer_id="<<peer_id
1189 <<" has apparently closed connection. "
1190 <<"Removing player."<<std::endl;
1192 m_env->removePlayer(peer_id);*/
1194 catch(ClientStateError &e)
1196 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1197 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1198 L"Try reconnecting or updating your client");
1202 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1204 std::string playername = "";
1205 PlayerSAO *playersao = NULL;
1207 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
1208 if (client != NULL) {
1209 playername = client->getName();
1210 playersao = emergePlayer(playername.c_str(), peer_id);
1214 RemotePlayer *player =
1215 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1217 // If failed, cancel
1218 if((playersao == NULL) || (player == NULL))
1220 if(player && player->peer_id != 0){
1221 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1222 <<" (player allocated to an another client)"<<std::endl;
1223 DenyAccess(peer_id, L"Another client is connected with this "
1224 L"name. If your client closed unexpectedly, try again in "
1227 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1229 DenyAccess(peer_id, L"Could not allocate player.");
1235 Send complete position information
1237 SendMovePlayer(peer_id);
1240 SendPlayerPrivileges(peer_id);
1242 // Send inventory formspec
1243 SendPlayerInventoryFormspec(peer_id);
1246 UpdateCrafting(peer_id);
1247 SendInventory(peer_id);
1250 if(g_settings->getBool("enable_damage"))
1251 SendPlayerHP(peer_id);
1254 SendPlayerBreath(peer_id);
1256 // Show death screen if necessary
1258 SendDeathscreen(peer_id, false, v3f(0,0,0));
1260 // Note things in chat if not in simple singleplayer mode
1261 if(!m_simple_singleplayer_mode)
1263 // Send information about server to player in chat
1264 SendChatMessage(peer_id, getStatusString());
1266 // Send information about joining in chat
1268 std::wstring name = L"unknown";
1269 Player *player = m_env->getPlayer(peer_id);
1271 name = narrow_to_wide(player->getName());
1273 std::wstring message;
1276 message += L" joined the game.";
1277 SendChatMessage(PEER_ID_INEXISTENT,message);
1281 actionstream<<player->getName() <<" joins game. " << std::endl;
1286 std::vector<std::string> names = m_clients.getPlayerNames();
1288 actionstream<<player->getName() <<" joins game. List of players: ";
1290 for (std::vector<std::string>::iterator i = names.begin();
1291 i != names.end(); i++)
1293 actionstream << *i << " ";
1296 actionstream<<std::endl;
1301 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1303 DSTACK(__FUNCTION_NAME);
1304 // Environment is locked first.
1305 JMutexAutoLock envlock(m_env_mutex);
1307 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1311 Address address = getPeerAddress(peer_id);
1312 addr_s = address.serializeString();
1314 // drop player if is ip is banned
1315 if(m_banmanager->isIpBanned(addr_s)){
1316 std::string ban_name = m_banmanager->getBanName(addr_s);
1317 infostream<<"Server: A banned client tried to connect from "
1318 <<addr_s<<"; banned name was "
1319 <<ban_name<<std::endl;
1320 // This actually doesn't seem to transfer to the client
1321 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1322 +narrow_to_wide(ban_name));
1326 catch(con::PeerNotFoundException &e)
1328 errorstream<<"Server::ProcessData(): Cancelling: peer "
1329 <<peer_id<<" not found"<<std::endl;
1339 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1341 if(command == TOSERVER_INIT)
1343 // [0] u16 TOSERVER_INIT
1344 // [2] u8 SER_FMT_VER_HIGHEST_READ
1345 // [3] u8[20] player_name
1346 // [23] u8[28] password <--- can be sent without this, from old versions
1348 if(datasize < 2+1+PLAYERNAME_SIZE)
1351 RemoteClient* client = getClient(peer_id,Created);
1353 // If net_proto_version is set, this client has already been handled
1354 if(client->getState() > Created)
1356 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1357 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1361 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1362 <<peer_id<<")"<<std::endl;
1364 // Do not allow multiple players in simple singleplayer mode.
1365 // This isn't a perfect way to do it, but will suffice for now
1366 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1367 infostream<<"Server: Not allowing another client ("<<addr_s
1368 <<") to connect in simple singleplayer mode"<<std::endl;
1369 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1373 // First byte after command is maximum supported
1374 // serialization version
1375 u8 client_max = data[2];
1376 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1377 // Use the highest version supported by both
1378 u8 deployed = std::min(client_max, our_max);
1379 // If it's lower than the lowest supported, give up.
1380 if(deployed < SER_FMT_VER_LOWEST)
1381 deployed = SER_FMT_VER_INVALID;
1383 if(deployed == SER_FMT_VER_INVALID)
1385 actionstream<<"Server: A mismatched client tried to connect from "
1386 <<addr_s<<std::endl;
1387 infostream<<"Server: Cannot negotiate serialization version with "
1388 <<addr_s<<std::endl;
1389 DenyAccess(peer_id, std::wstring(
1390 L"Your client's version is not supported.\n"
1391 L"Server version is ")
1392 + narrow_to_wide(minetest_version_simple) + L"."
1397 client->setPendingSerializationVersion(deployed);
1400 Read and check network protocol version
1403 u16 min_net_proto_version = 0;
1404 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1405 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1407 // Use same version as minimum and maximum if maximum version field
1408 // doesn't exist (backwards compatibility)
1409 u16 max_net_proto_version = min_net_proto_version;
1410 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1411 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1413 // Start with client's maximum version
1414 u16 net_proto_version = max_net_proto_version;
1416 // Figure out a working version if it is possible at all
1417 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1418 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1420 // If maximum is larger than our maximum, go with our maximum
1421 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1422 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1423 // Else go with client's maximum
1425 net_proto_version = max_net_proto_version;
1428 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1429 <<min_net_proto_version<<", max: "<<max_net_proto_version
1430 <<", chosen: "<<net_proto_version<<std::endl;
1432 client->net_proto_version = net_proto_version;
1434 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1435 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1437 actionstream<<"Server: A mismatched client tried to connect from "
1438 <<addr_s<<std::endl;
1439 DenyAccess(peer_id, std::wstring(
1440 L"Your client's version is not supported.\n"
1441 L"Server version is ")
1442 + narrow_to_wide(minetest_version_simple) + L",\n"
1443 + L"server's PROTOCOL_VERSION is "
1444 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1446 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1447 + L", client's PROTOCOL_VERSION is "
1448 + narrow_to_wide(itos(min_net_proto_version))
1450 + narrow_to_wide(itos(max_net_proto_version))
1455 if(g_settings->getBool("strict_protocol_version_checking"))
1457 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1459 actionstream<<"Server: A mismatched (strict) client tried to "
1460 <<"connect from "<<addr_s<<std::endl;
1461 DenyAccess(peer_id, std::wstring(
1462 L"Your client's version is not supported.\n"
1463 L"Server version is ")
1464 + narrow_to_wide(minetest_version_simple) + L",\n"
1465 + L"server's PROTOCOL_VERSION (strict) is "
1466 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1467 + L", client's PROTOCOL_VERSION is "
1468 + narrow_to_wide(itos(min_net_proto_version))
1470 + narrow_to_wide(itos(max_net_proto_version))
1481 char playername[PLAYERNAME_SIZE];
1482 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1484 playername[i] = data[3+i];
1486 playername[PLAYERNAME_SIZE-1] = 0;
1488 if(playername[0]=='\0')
1490 actionstream<<"Server: Player with an empty name "
1491 <<"tried to connect from "<<addr_s<<std::endl;
1492 DenyAccess(peer_id, L"Empty name");
1496 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1498 actionstream<<"Server: Player with an invalid name "
1499 <<"tried to connect from "<<addr_s<<std::endl;
1500 DenyAccess(peer_id, L"Name contains unallowed characters");
1504 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1506 actionstream<<"Server: Player with the name \"singleplayer\" "
1507 <<"tried to connect from "<<addr_s<<std::endl;
1508 DenyAccess(peer_id, L"Name is not allowed");
1514 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1516 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1517 <<"tried to connect from "<<addr_s<<" "
1518 <<"but it was disallowed for the following reason: "
1519 <<reason<<std::endl;
1520 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1525 infostream<<"Server: New connection: \""<<playername<<"\" from "
1526 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1529 char given_password[PASSWORD_SIZE];
1530 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1532 // old version - assume blank password
1533 given_password[0] = 0;
1537 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1539 given_password[i] = data[23+i];
1541 given_password[PASSWORD_SIZE-1] = 0;
1544 if(!base64_is_valid(given_password)){
1545 actionstream<<"Server: "<<playername
1546 <<" supplied invalid password hash"<<std::endl;
1547 DenyAccess(peer_id, L"Invalid password hash");
1551 // Enforce user limit.
1552 // Don't enforce for users that have some admin right
1553 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1554 !checkPriv(playername, "server") &&
1555 !checkPriv(playername, "ban") &&
1556 !checkPriv(playername, "privs") &&
1557 !checkPriv(playername, "password") &&
1558 playername != g_settings->get("name"))
1560 actionstream<<"Server: "<<playername<<" tried to join, but there"
1561 <<" are already max_users="
1562 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1563 DenyAccess(peer_id, L"Too many users.");
1567 std::string checkpwd; // Password hash to check against
1568 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1570 // If no authentication info exists for user, create it
1572 if(!isSingleplayer() &&
1573 g_settings->getBool("disallow_empty_password") &&
1574 std::string(given_password) == ""){
1575 actionstream<<"Server: "<<playername
1576 <<" supplied empty password"<<std::endl;
1577 DenyAccess(peer_id, L"Empty passwords are "
1578 L"disallowed. Set a password and try again.");
1581 std::wstring raw_default_password =
1582 narrow_to_wide(g_settings->get("default_password"));
1583 std::string initial_password =
1584 translatePassword(playername, raw_default_password);
1586 // If default_password is empty, allow any initial password
1587 if (raw_default_password.length() == 0)
1588 initial_password = given_password;
1590 m_script->createAuth(playername, initial_password);
1593 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1596 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1597 <<" (auth handler does not work?)"<<std::endl;
1598 DenyAccess(peer_id, L"Not allowed to login");
1602 if(given_password != checkpwd){
1603 actionstream<<"Server: "<<playername<<" supplied wrong password"
1605 DenyAccess(peer_id, L"Wrong password");
1609 RemotePlayer *player =
1610 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1612 if(player && player->peer_id != 0){
1613 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1614 <<" (player allocated to an another client)"<<std::endl;
1615 DenyAccess(peer_id, L"Another client is connected with this "
1616 L"name. If your client closed unexpectedly, try again in "
1620 m_clients.setPlayerName(peer_id,playername);
1623 Answer with a TOCLIENT_INIT
1626 SharedBuffer<u8> reply(2+1+6+8+4);
1627 writeU16(&reply[0], TOCLIENT_INIT);
1628 writeU8(&reply[2], deployed);
1629 //send dummy pos for legacy reasons only
1630 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1631 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1632 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1635 m_clients.send(peer_id, 0, reply, true);
1636 m_clients.event(peer_id, Init);
1642 if(command == TOSERVER_INIT2)
1645 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1646 <<peer_id<<std::endl;
1648 m_clients.event(peer_id, GotInit2);
1649 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1652 ///// begin compatibility code
1653 PlayerSAO* playersao = NULL;
1654 if (protocol_version <= 22) {
1655 playersao = StageTwoClientInit(peer_id);
1657 if (playersao == NULL) {
1659 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1660 << peer_id << std::endl;
1664 ///// end compatibility code
1667 Send some initialization data
1670 infostream<<"Server: Sending content to "
1671 <<getPlayerName(peer_id)<<std::endl;
1673 // Send player movement settings
1674 SendMovement(peer_id);
1676 // Send item definitions
1677 SendItemDef(peer_id, m_itemdef, protocol_version);
1679 // Send node definitions
1680 SendNodeDef(peer_id, m_nodedef, protocol_version);
1682 m_clients.event(peer_id, SetDefinitionsSent);
1684 // Send media announcement
1685 sendMediaAnnouncement(peer_id);
1687 // Send detached inventories
1688 sendDetachedInventories(peer_id);
1691 u16 time = m_env->getTimeOfDay();
1692 float time_speed = g_settings->getFloat("time_speed");
1693 SendTimeOfDay(peer_id, time, time_speed);
1695 ///// begin compatibility code
1696 if (protocol_version <= 22) {
1697 m_clients.event(peer_id, SetClientReady);
1698 m_script->on_joinplayer(playersao);
1700 ///// end compatibility code
1702 // Warnings about protocol version can be issued here
1703 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1705 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1706 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1712 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1713 u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1715 if(peer_ser_ver == SER_FMT_VER_INVALID)
1717 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1718 " serialization format invalid or not initialized."
1719 " Skipping incoming command="<<command<<std::endl;
1723 /* Handle commands relate to client startup */
1724 if(command == TOSERVER_REQUEST_MEDIA) {
1725 std::string datastring((char*)&data[2], datasize-2);
1726 std::istringstream is(datastring, std::ios_base::binary);
1728 std::list<std::string> tosend;
1729 u16 numfiles = readU16(is);
1731 infostream<<"Sending "<<numfiles<<" files to "
1732 <<getPlayerName(peer_id)<<std::endl;
1733 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1735 for(int i = 0; i < numfiles; i++) {
1736 std::string name = deSerializeString(is);
1737 tosend.push_back(name);
1738 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1742 sendRequestedMedia(peer_id, tosend);
1745 else if(command == TOSERVER_RECEIVED_MEDIA) {
1748 else if(command == TOSERVER_CLIENT_READY) {
1749 // clients <= protocol version 22 did not send ready message,
1750 // they're already initialized
1751 assert(peer_proto_ver > 22);
1753 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1755 if (playersao == NULL) {
1757 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1758 << peer_id << std::endl;
1766 m_clients.setClientVersion(
1768 data[2], data[3], data[4],
1769 std::string((char*) &data[8],(u16) data[6]));
1771 m_clients.event(peer_id, SetClientReady);
1772 m_script->on_joinplayer(playersao);
1775 else if(command == TOSERVER_GOTBLOCKS)
1788 u16 count = data[2];
1789 for(u16 i=0; i<count; i++)
1791 if((s16)datasize < 2+1+(i+1)*6)
1792 throw con::InvalidIncomingDataException
1793 ("GOTBLOCKS length is too short");
1794 v3s16 p = readV3S16(&data[2+1+i*6]);
1795 /*infostream<<"Server: GOTBLOCKS ("
1796 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1797 RemoteClient *client = getClient(peer_id);
1798 client->GotBlock(p);
1803 if (m_clients.getClientState(peer_id) < Active)
1805 if (command == TOSERVER_PLAYERPOS) return;
1807 errorstream<<"Got packet command: " << command << " for peer id "
1808 << peer_id << " but client isn't active yet. Dropping packet "
1813 Player *player = m_env->getPlayer(peer_id);
1815 errorstream<<"Server::ProcessData(): Cancelling: "
1816 "No player for peer_id="<<peer_id
1821 PlayerSAO *playersao = player->getPlayerSAO();
1822 if(playersao == NULL){
1823 errorstream<<"Server::ProcessData(): Cancelling: "
1824 "No player object for peer_id="<<peer_id
1829 if(command == TOSERVER_PLAYERPOS)
1831 if(datasize < 2+12+12+4+4)
1835 v3s32 ps = readV3S32(&data[start+2]);
1836 v3s32 ss = readV3S32(&data[start+2+12]);
1837 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1838 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1840 if(datasize >= 2+12+12+4+4+4)
1841 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1842 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1843 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1844 pitch = wrapDegrees(pitch);
1845 yaw = wrapDegrees(yaw);
1847 player->setPosition(position);
1848 player->setSpeed(speed);
1849 player->setPitch(pitch);
1850 player->setYaw(yaw);
1851 player->keyPressed=keyPressed;
1852 player->control.up = (bool)(keyPressed&1);
1853 player->control.down = (bool)(keyPressed&2);
1854 player->control.left = (bool)(keyPressed&4);
1855 player->control.right = (bool)(keyPressed&8);
1856 player->control.jump = (bool)(keyPressed&16);
1857 player->control.aux1 = (bool)(keyPressed&32);
1858 player->control.sneak = (bool)(keyPressed&64);
1859 player->control.LMB = (bool)(keyPressed&128);
1860 player->control.RMB = (bool)(keyPressed&256);
1862 bool cheated = playersao->checkMovementCheat();
1865 m_script->on_cheat(playersao, "moved_too_fast");
1868 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1869 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1870 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1872 else if(command == TOSERVER_DELETEDBLOCKS)
1885 u16 count = data[2];
1886 for(u16 i=0; i<count; i++)
1888 if((s16)datasize < 2+1+(i+1)*6)
1889 throw con::InvalidIncomingDataException
1890 ("DELETEDBLOCKS length is too short");
1891 v3s16 p = readV3S16(&data[2+1+i*6]);
1892 /*infostream<<"Server: DELETEDBLOCKS ("
1893 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1894 RemoteClient *client = getClient(peer_id);
1895 client->SetBlockNotSent(p);
1898 else if(command == TOSERVER_CLICK_OBJECT)
1900 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1903 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1905 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1908 else if(command == TOSERVER_GROUND_ACTION)
1910 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1914 else if(command == TOSERVER_RELEASE)
1916 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1919 else if(command == TOSERVER_SIGNTEXT)
1921 infostream<<"Server: SIGNTEXT not supported anymore"
1925 else if(command == TOSERVER_SIGNNODETEXT)
1927 infostream<<"Server: SIGNNODETEXT not supported anymore"
1931 else if(command == TOSERVER_INVENTORY_ACTION)
1933 // Strip command and create a stream
1934 std::string datastring((char*)&data[2], datasize-2);
1935 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1936 std::istringstream is(datastring, std::ios_base::binary);
1938 InventoryAction *a = InventoryAction::deSerialize(is);
1941 infostream<<"TOSERVER_INVENTORY_ACTION: "
1942 <<"InventoryAction::deSerialize() returned NULL"
1947 // If something goes wrong, this player is to blame
1948 RollbackScopeActor rollback_scope(m_rollback,
1949 std::string("player:")+player->getName());
1952 Note: Always set inventory not sent, to repair cases
1953 where the client made a bad prediction.
1957 Handle restrictions and special cases of the move action
1959 if(a->getType() == IACTION_MOVE)
1961 IMoveAction *ma = (IMoveAction*)a;
1963 ma->from_inv.applyCurrentPlayer(player->getName());
1964 ma->to_inv.applyCurrentPlayer(player->getName());
1966 setInventoryModified(ma->from_inv);
1967 setInventoryModified(ma->to_inv);
1969 bool from_inv_is_current_player =
1970 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1971 (ma->from_inv.name == player->getName());
1973 bool to_inv_is_current_player =
1974 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1975 (ma->to_inv.name == player->getName());
1978 Disable moving items out of craftpreview
1980 if(ma->from_list == "craftpreview")
1982 infostream<<"Ignoring IMoveAction from "
1983 <<(ma->from_inv.dump())<<":"<<ma->from_list
1984 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1985 <<" because src is "<<ma->from_list<<std::endl;
1991 Disable moving items into craftresult and craftpreview
1993 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1995 infostream<<"Ignoring IMoveAction from "
1996 <<(ma->from_inv.dump())<<":"<<ma->from_list
1997 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1998 <<" because dst is "<<ma->to_list<<std::endl;
2003 // Disallow moving items in elsewhere than player's inventory
2004 // if not allowed to interact
2005 if(!checkPriv(player->getName(), "interact") &&
2006 (!from_inv_is_current_player ||
2007 !to_inv_is_current_player))
2009 infostream<<"Cannot move outside of player's inventory: "
2010 <<"No interact privilege"<<std::endl;
2016 Handle restrictions and special cases of the drop action
2018 else if(a->getType() == IACTION_DROP)
2020 IDropAction *da = (IDropAction*)a;
2022 da->from_inv.applyCurrentPlayer(player->getName());
2024 setInventoryModified(da->from_inv);
2027 Disable dropping items out of craftpreview
2029 if(da->from_list == "craftpreview")
2031 infostream<<"Ignoring IDropAction from "
2032 <<(da->from_inv.dump())<<":"<<da->from_list
2033 <<" because src is "<<da->from_list<<std::endl;
2038 // Disallow dropping items if not allowed to interact
2039 if(!checkPriv(player->getName(), "interact"))
2046 Handle restrictions and special cases of the craft action
2048 else if(a->getType() == IACTION_CRAFT)
2050 ICraftAction *ca = (ICraftAction*)a;
2052 ca->craft_inv.applyCurrentPlayer(player->getName());
2054 setInventoryModified(ca->craft_inv);
2056 //bool craft_inv_is_current_player =
2057 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2058 // (ca->craft_inv.name == player->getName());
2060 // Disallow crafting if not allowed to interact
2061 if(!checkPriv(player->getName(), "interact"))
2063 infostream<<"Cannot craft: "
2064 <<"No interact privilege"<<std::endl;
2071 a->apply(this, playersao, this);
2075 else if(command == TOSERVER_CHAT_MESSAGE)
2083 std::string datastring((char*)&data[2], datasize-2);
2084 std::istringstream is(datastring, std::ios_base::binary);
2087 is.read((char*)buf, 2);
2088 u16 len = readU16(buf);
2090 std::wstring message;
2091 for(u16 i=0; i<len; i++)
2093 is.read((char*)buf, 2);
2094 message += (wchar_t)readU16(buf);
2097 // If something goes wrong, this player is to blame
2098 RollbackScopeActor rollback_scope(m_rollback,
2099 std::string("player:")+player->getName());
2101 // Get player name of this client
2102 std::wstring name = narrow_to_wide(player->getName());
2105 bool ate = m_script->on_chat_message(player->getName(),
2106 wide_to_narrow(message));
2107 // If script ate the message, don't proceed
2111 // Line to send to players
2113 // Whether to send to the player that sent the line
2114 bool send_to_sender_only = false;
2116 // Commands are implemented in Lua, so only catch invalid
2117 // commands that were not "eaten" and send an error back
2118 if(message[0] == L'/')
2120 message = message.substr(1);
2121 send_to_sender_only = true;
2122 if(message.length() == 0)
2123 line += L"-!- Empty command";
2125 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2129 if(checkPriv(player->getName(), "shout")){
2135 line += L"-!- You don't have permission to shout.";
2136 send_to_sender_only = true;
2143 Send the message to sender
2145 if (send_to_sender_only)
2147 SendChatMessage(peer_id, line);
2150 Send the message to others
2154 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2156 std::list<u16> clients = m_clients.getClientIDs();
2158 for(std::list<u16>::iterator
2159 i = clients.begin();
2160 i != clients.end(); ++i)
2163 SendChatMessage(*i, line);
2168 else if(command == TOSERVER_DAMAGE)
2170 std::string datastring((char*)&data[2], datasize-2);
2171 std::istringstream is(datastring, std::ios_base::binary);
2172 u8 damage = readU8(is);
2174 if(g_settings->getBool("enable_damage"))
2176 actionstream<<player->getName()<<" damaged by "
2177 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2180 playersao->setHP(playersao->getHP() - damage);
2182 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2185 if(playersao->m_hp_not_sent)
2186 SendPlayerHP(peer_id);
2189 else if(command == TOSERVER_BREATH)
2191 std::string datastring((char*)&data[2], datasize-2);
2192 std::istringstream is(datastring, std::ios_base::binary);
2193 u16 breath = readU16(is);
2194 playersao->setBreath(breath);
2196 else if(command == TOSERVER_PASSWORD)
2199 [0] u16 TOSERVER_PASSWORD
2200 [2] u8[28] old password
2201 [30] u8[28] new password
2204 if(datasize != 2+PASSWORD_SIZE*2)
2206 /*char password[PASSWORD_SIZE];
2207 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2208 password[i] = data[2+i];
2209 password[PASSWORD_SIZE-1] = 0;*/
2211 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2219 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2221 char c = data[2+PASSWORD_SIZE+i];
2227 if(!base64_is_valid(newpwd)){
2228 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2229 // Wrong old password supplied!!
2230 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2234 infostream<<"Server: Client requests a password change from "
2235 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2237 std::string playername = player->getName();
2239 std::string checkpwd;
2240 m_script->getAuth(playername, &checkpwd, NULL);
2242 if(oldpwd != checkpwd)
2244 infostream<<"Server: invalid old password"<<std::endl;
2245 // Wrong old password supplied!!
2246 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2250 bool success = m_script->setPassword(playername, newpwd);
2252 actionstream<<player->getName()<<" changes password"<<std::endl;
2253 SendChatMessage(peer_id, L"Password change successful.");
2255 actionstream<<player->getName()<<" tries to change password but "
2256 <<"it fails"<<std::endl;
2257 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2260 else if(command == TOSERVER_PLAYERITEM)
2265 u16 item = readU16(&data[2]);
2266 playersao->setWieldIndex(item);
2268 else if(command == TOSERVER_RESPAWN)
2270 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2273 RespawnPlayer(peer_id);
2275 actionstream<<player->getName()<<" respawns at "
2276 <<PP(player->getPosition()/BS)<<std::endl;
2278 // ActiveObject is added to environment in AsyncRunStep after
2279 // the previous addition has been succesfully removed
2281 else if(command == TOSERVER_INTERACT)
2283 std::string datastring((char*)&data[2], datasize-2);
2284 std::istringstream is(datastring, std::ios_base::binary);
2290 [5] u32 length of the next item
2291 [9] serialized PointedThing
2293 0: start digging (from undersurface) or use
2294 1: stop digging (all parameters ignored)
2295 2: digging completed
2296 3: place block or item (to abovesurface)
2299 u8 action = readU8(is);
2300 u16 item_i = readU16(is);
2301 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2302 PointedThing pointed;
2303 pointed.deSerialize(tmp_is);
2305 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2306 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2310 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2311 <<" tried to interact, but is dead!"<<std::endl;
2315 v3f player_pos = playersao->getLastGoodPosition();
2317 // Update wielded item
2318 playersao->setWieldIndex(item_i);
2320 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2321 v3s16 p_under = pointed.node_undersurface;
2322 v3s16 p_above = pointed.node_abovesurface;
2324 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2325 ServerActiveObject *pointed_object = NULL;
2326 if(pointed.type == POINTEDTHING_OBJECT)
2328 pointed_object = m_env->getActiveObject(pointed.object_id);
2329 if(pointed_object == NULL)
2331 verbosestream<<"TOSERVER_INTERACT: "
2332 "pointed object is NULL"<<std::endl;
2338 v3f pointed_pos_under = player_pos;
2339 v3f pointed_pos_above = player_pos;
2340 if(pointed.type == POINTEDTHING_NODE)
2342 pointed_pos_under = intToFloat(p_under, BS);
2343 pointed_pos_above = intToFloat(p_above, BS);
2345 else if(pointed.type == POINTEDTHING_OBJECT)
2347 pointed_pos_under = pointed_object->getBasePosition();
2348 pointed_pos_above = pointed_pos_under;
2352 Check that target is reasonably close
2353 (only when digging or placing things)
2355 if(action == 0 || action == 2 || action == 3)
2357 float d = player_pos.getDistanceFrom(pointed_pos_under);
2358 float max_d = BS * 14; // Just some large enough value
2360 actionstream<<"Player "<<player->getName()
2361 <<" tried to access "<<pointed.dump()
2363 <<"d="<<d<<", max_d="<<max_d
2364 <<". ignoring."<<std::endl;
2365 // Re-send block to revert change on client-side
2366 RemoteClient *client = getClient(peer_id);
2367 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2368 client->SetBlockNotSent(blockpos);
2370 m_script->on_cheat(playersao, "interacted_too_far");
2377 Make sure the player is allowed to do it
2379 if(!checkPriv(player->getName(), "interact"))
2381 actionstream<<player->getName()<<" attempted to interact with "
2382 <<pointed.dump()<<" without 'interact' privilege"
2384 // Re-send block to revert change on client-side
2385 RemoteClient *client = getClient(peer_id);
2386 // Digging completed -> under
2388 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2389 client->SetBlockNotSent(blockpos);
2391 // Placement -> above
2393 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2394 client->SetBlockNotSent(blockpos);
2400 If something goes wrong, this player is to blame
2402 RollbackScopeActor rollback_scope(m_rollback,
2403 std::string("player:")+player->getName());
2406 0: start digging or punch object
2410 if(pointed.type == POINTEDTHING_NODE)
2413 NOTE: This can be used in the future to check if
2414 somebody is cheating, by checking the timing.
2416 MapNode n(CONTENT_IGNORE);
2419 n = m_env->getMap().getNode(p_under);
2421 catch(InvalidPositionException &e)
2423 infostream<<"Server: Not punching: Node not found."
2424 <<" Adding block to emerge queue."
2426 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2428 if(n.getContent() != CONTENT_IGNORE)
2429 m_script->node_on_punch(p_under, n, playersao, pointed);
2431 playersao->noCheatDigStart(p_under);
2433 else if(pointed.type == POINTEDTHING_OBJECT)
2435 // Skip if object has been removed
2436 if(pointed_object->m_removed)
2439 actionstream<<player->getName()<<" punches object "
2440 <<pointed.object_id<<": "
2441 <<pointed_object->getDescription()<<std::endl;
2443 ItemStack punchitem = playersao->getWieldedItem();
2444 ToolCapabilities toolcap =
2445 punchitem.getToolCapabilities(m_itemdef);
2446 v3f dir = (pointed_object->getBasePosition() -
2447 (player->getPosition() + player->getEyeOffset())
2449 float time_from_last_punch =
2450 playersao->resetTimeFromLastPunch();
2451 pointed_object->punch(dir, &toolcap, playersao,
2452 time_from_last_punch);
2460 else if(action == 1)
2465 2: Digging completed
2467 else if(action == 2)
2469 // Only digging of nodes
2470 if(pointed.type == POINTEDTHING_NODE)
2472 MapNode n(CONTENT_IGNORE);
2475 n = m_env->getMap().getNode(p_under);
2477 catch(InvalidPositionException &e)
2479 infostream<<"Server: Not finishing digging: Node not found."
2480 <<" Adding block to emerge queue."
2482 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2485 /* Cheat prevention */
2486 bool is_valid_dig = true;
2487 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2489 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2490 float nocheat_t = playersao->getNoCheatDigTime();
2491 playersao->noCheatDigEnd();
2492 // If player didn't start digging this, ignore dig
2493 if(nocheat_p != p_under){
2494 infostream<<"Server: NoCheat: "<<player->getName()
2495 <<" started digging "
2496 <<PP(nocheat_p)<<" and completed digging "
2497 <<PP(p_under)<<"; not digging."<<std::endl;
2498 is_valid_dig = false;
2500 m_script->on_cheat(playersao, "finished_unknown_dig");
2502 // Get player's wielded item
2503 ItemStack playeritem;
2504 InventoryList *mlist = playersao->getInventory()->getList("main");
2506 playeritem = mlist->getItem(playersao->getWieldIndex());
2507 ToolCapabilities playeritem_toolcap =
2508 playeritem.getToolCapabilities(m_itemdef);
2509 // Get diggability and expected digging time
2510 DigParams params = getDigParams(m_nodedef->get(n).groups,
2511 &playeritem_toolcap);
2512 // If can't dig, try hand
2513 if(!params.diggable){
2514 const ItemDefinition &hand = m_itemdef->get("");
2515 const ToolCapabilities *tp = hand.tool_capabilities;
2517 params = getDigParams(m_nodedef->get(n).groups, tp);
2519 // If can't dig, ignore dig
2520 if(!params.diggable){
2521 infostream<<"Server: NoCheat: "<<player->getName()
2522 <<" completed digging "<<PP(p_under)
2523 <<", which is not diggable with tool. not digging."
2525 is_valid_dig = false;
2527 m_script->on_cheat(playersao, "dug_unbreakable");
2529 // Check digging time
2530 // If already invalidated, we don't have to
2532 // Well not our problem then
2534 // Clean and long dig
2535 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2536 // All is good, but grab time from pool; don't care if
2537 // it's actually available
2538 playersao->getDigPool().grab(params.time);
2540 // Short or laggy dig
2541 // Try getting the time from pool
2542 else if(playersao->getDigPool().grab(params.time)){
2547 infostream<<"Server: NoCheat: "<<player->getName()
2548 <<" completed digging "<<PP(p_under)
2549 <<"too fast; not digging."<<std::endl;
2550 is_valid_dig = false;
2552 m_script->on_cheat(playersao, "dug_too_fast");
2556 /* Actually dig node */
2558 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2559 m_script->node_on_dig(p_under, n, playersao);
2561 // Send unusual result (that is, node not being removed)
2562 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2564 // Re-send block to revert change on client-side
2565 RemoteClient *client = getClient(peer_id);
2566 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2567 client->SetBlockNotSent(blockpos);
2573 3: place block or right-click object
2575 else if(action == 3)
2577 ItemStack item = playersao->getWieldedItem();
2579 // Reset build time counter
2580 if(pointed.type == POINTEDTHING_NODE &&
2581 item.getDefinition(m_itemdef).type == ITEM_NODE)
2582 getClient(peer_id)->m_time_from_building = 0.0;
2584 if(pointed.type == POINTEDTHING_OBJECT)
2586 // Right click object
2588 // Skip if object has been removed
2589 if(pointed_object->m_removed)
2592 actionstream<<player->getName()<<" right-clicks object "
2593 <<pointed.object_id<<": "
2594 <<pointed_object->getDescription()<<std::endl;
2597 pointed_object->rightClick(playersao);
2599 else if(m_script->item_OnPlace(
2600 item, playersao, pointed))
2602 // Placement was handled in lua
2604 // Apply returned ItemStack
2605 playersao->setWieldedItem(item);
2608 // If item has node placement prediction, always send the
2609 // blocks to make sure the client knows what exactly happened
2610 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2611 RemoteClient *client = getClient(peer_id);
2612 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2613 client->SetBlockNotSent(blockpos);
2614 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2615 if(blockpos2 != blockpos){
2616 client->SetBlockNotSent(blockpos2);
2624 else if(action == 4)
2626 ItemStack item = playersao->getWieldedItem();
2628 actionstream<<player->getName()<<" uses "<<item.name
2629 <<", pointing at "<<pointed.dump()<<std::endl;
2631 if(m_script->item_OnUse(
2632 item, playersao, pointed))
2634 // Apply returned ItemStack
2635 playersao->setWieldedItem(item);
2642 Catch invalid actions
2646 infostream<<"WARNING: Server: Invalid action "
2647 <<action<<std::endl;
2650 else if(command == TOSERVER_REMOVED_SOUNDS)
2652 std::string datastring((char*)&data[2], datasize-2);
2653 std::istringstream is(datastring, std::ios_base::binary);
2655 int num = readU16(is);
2656 for(int k=0; k<num; k++){
2657 s32 id = readS32(is);
2658 std::map<s32, ServerPlayingSound>::iterator i =
2659 m_playing_sounds.find(id);
2660 if(i == m_playing_sounds.end())
2662 ServerPlayingSound &psound = i->second;
2663 psound.clients.erase(peer_id);
2664 if(psound.clients.size() == 0)
2665 m_playing_sounds.erase(i++);
2668 else if(command == TOSERVER_NODEMETA_FIELDS)
2670 std::string datastring((char*)&data[2], datasize-2);
2671 std::istringstream is(datastring, std::ios_base::binary);
2673 v3s16 p = readV3S16(is);
2674 std::string formname = deSerializeString(is);
2675 int num = readU16(is);
2676 std::map<std::string, std::string> fields;
2677 for(int k=0; k<num; k++){
2678 std::string fieldname = deSerializeString(is);
2679 std::string fieldvalue = deSerializeLongString(is);
2680 fields[fieldname] = fieldvalue;
2683 // If something goes wrong, this player is to blame
2684 RollbackScopeActor rollback_scope(m_rollback,
2685 std::string("player:")+player->getName());
2687 // Check the target node for rollback data; leave others unnoticed
2688 RollbackNode rn_old(&m_env->getMap(), p, this);
2690 m_script->node_on_receive_fields(p, formname, fields,playersao);
2692 // Report rollback data
2693 RollbackNode rn_new(&m_env->getMap(), p, this);
2694 if(rollback() && rn_new != rn_old){
2695 RollbackAction action;
2696 action.setSetNode(p, rn_old, rn_new);
2697 rollback()->reportAction(action);
2700 else if(command == TOSERVER_INVENTORY_FIELDS)
2702 std::string datastring((char*)&data[2], datasize-2);
2703 std::istringstream is(datastring, std::ios_base::binary);
2705 std::string formname = deSerializeString(is);
2706 int num = readU16(is);
2707 std::map<std::string, std::string> fields;
2708 for(int k=0; k<num; k++){
2709 std::string fieldname = deSerializeString(is);
2710 std::string fieldvalue = deSerializeLongString(is);
2711 fields[fieldname] = fieldvalue;
2714 m_script->on_playerReceiveFields(playersao, formname, fields);
2718 infostream<<"Server::ProcessData(): Ignoring "
2719 "unknown command "<<command<<std::endl;
2723 catch(SendFailedException &e)
2725 errorstream<<"Server::ProcessData(): SendFailedException: "
2731 void Server::setTimeOfDay(u32 time)
2733 m_env->setTimeOfDay(time);
2734 m_time_of_day_send_timer = 0;
2737 void Server::onMapEditEvent(MapEditEvent *event)
2739 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2740 if(m_ignore_map_edit_events)
2742 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2744 MapEditEvent *e = event->clone();
2745 m_unsent_map_edit_queue.push_back(e);
2748 Inventory* Server::getInventory(const InventoryLocation &loc)
2751 case InventoryLocation::UNDEFINED:
2754 case InventoryLocation::CURRENT_PLAYER:
2757 case InventoryLocation::PLAYER:
2759 Player *player = m_env->getPlayer(loc.name.c_str());
2762 PlayerSAO *playersao = player->getPlayerSAO();
2765 return playersao->getInventory();
2768 case InventoryLocation::NODEMETA:
2770 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2773 return meta->getInventory();
2776 case InventoryLocation::DETACHED:
2778 if(m_detached_inventories.count(loc.name) == 0)
2780 return m_detached_inventories[loc.name];
2788 void Server::setInventoryModified(const InventoryLocation &loc)
2791 case InventoryLocation::UNDEFINED:
2794 case InventoryLocation::PLAYER:
2796 Player *player = m_env->getPlayer(loc.name.c_str());
2799 PlayerSAO *playersao = player->getPlayerSAO();
2802 playersao->m_inventory_not_sent = true;
2803 playersao->m_wielded_item_not_sent = true;
2806 case InventoryLocation::NODEMETA:
2808 v3s16 blockpos = getNodeBlockPos(loc.p);
2810 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2812 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2814 setBlockNotSent(blockpos);
2817 case InventoryLocation::DETACHED:
2819 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2827 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2829 std::list<u16> clients = m_clients.getClientIDs();
2831 // Set the modified blocks unsent for all the clients
2832 for (std::list<u16>::iterator
2833 i = clients.begin();
2834 i != clients.end(); ++i) {
2835 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2837 client->SetBlocksNotSent(block);
2842 void Server::peerAdded(con::Peer *peer)
2844 DSTACK(__FUNCTION_NAME);
2845 verbosestream<<"Server::peerAdded(): peer->id="
2846 <<peer->id<<std::endl;
2849 c.type = con::PEER_ADDED;
2850 c.peer_id = peer->id;
2852 m_peer_change_queue.push_back(c);
2855 void Server::deletingPeer(con::Peer *peer, bool timeout)
2857 DSTACK(__FUNCTION_NAME);
2858 verbosestream<<"Server::deletingPeer(): peer->id="
2859 <<peer->id<<", timeout="<<timeout<<std::endl;
2861 m_clients.event(peer->id,Disconnect);
2863 c.type = con::PEER_REMOVED;
2864 c.peer_id = peer->id;
2865 c.timeout = timeout;
2866 m_peer_change_queue.push_back(c);
2869 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2871 *retval = m_con.getPeerStat(peer_id,type);
2872 if (*retval == -1) return false;
2876 bool Server::getClientInfo(
2885 std::string* vers_string
2888 *state = m_clients.getClientState(peer_id);
2890 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2895 *uptime = client->uptime();
2896 *ser_vers = client->serialization_version;
2897 *prot_vers = client->net_proto_version;
2899 *major = client->getMajor();
2900 *minor = client->getMinor();
2901 *patch = client->getPatch();
2902 *vers_string = client->getPatch();
2909 void Server::handlePeerChanges()
2911 while(m_peer_change_queue.size() > 0)
2913 con::PeerChange c = m_peer_change_queue.pop_front();
2915 verbosestream<<"Server: Handling peer change: "
2916 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2921 case con::PEER_ADDED:
2922 m_clients.CreateClient(c.peer_id);
2925 case con::PEER_REMOVED:
2926 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2930 assert("Invalid peer change event received!" == 0);
2936 void Server::SendMovement(u16 peer_id)
2938 DSTACK(__FUNCTION_NAME);
2939 std::ostringstream os(std::ios_base::binary);
2941 writeU16(os, TOCLIENT_MOVEMENT);
2942 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2943 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2944 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2945 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2946 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2947 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2948 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2949 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2950 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2951 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2952 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2953 writeF1000(os, g_settings->getFloat("movement_gravity"));
2956 std::string s = os.str();
2957 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2959 m_clients.send(peer_id, 0, data, true);
2962 void Server::SendHP(u16 peer_id, u8 hp)
2964 DSTACK(__FUNCTION_NAME);
2965 std::ostringstream os(std::ios_base::binary);
2967 writeU16(os, TOCLIENT_HP);
2971 std::string s = os.str();
2972 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2974 m_clients.send(peer_id, 0, data, true);
2977 void Server::SendBreath(u16 peer_id, u16 breath)
2979 DSTACK(__FUNCTION_NAME);
2980 std::ostringstream os(std::ios_base::binary);
2982 writeU16(os, TOCLIENT_BREATH);
2983 writeU16(os, breath);
2986 std::string s = os.str();
2987 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2989 m_clients.send(peer_id, 0, data, true);
2992 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2994 DSTACK(__FUNCTION_NAME);
2995 std::ostringstream os(std::ios_base::binary);
2997 writeU16(os, TOCLIENT_ACCESS_DENIED);
2998 os<<serializeWideString(reason);
3001 std::string s = os.str();
3002 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3004 m_clients.send(peer_id, 0, data, true);
3007 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3008 v3f camera_point_target)
3010 DSTACK(__FUNCTION_NAME);
3011 std::ostringstream os(std::ios_base::binary);
3013 writeU16(os, TOCLIENT_DEATHSCREEN);
3014 writeU8(os, set_camera_point_target);
3015 writeV3F1000(os, camera_point_target);
3018 std::string s = os.str();
3019 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3021 m_clients.send(peer_id, 0, data, true);
3024 void Server::SendItemDef(u16 peer_id,
3025 IItemDefManager *itemdef, u16 protocol_version)
3027 DSTACK(__FUNCTION_NAME);
3028 std::ostringstream os(std::ios_base::binary);
3032 u32 length of the next item
3033 zlib-compressed serialized ItemDefManager
3035 writeU16(os, TOCLIENT_ITEMDEF);
3036 std::ostringstream tmp_os(std::ios::binary);
3037 itemdef->serialize(tmp_os, protocol_version);
3038 std::ostringstream tmp_os2(std::ios::binary);
3039 compressZlib(tmp_os.str(), tmp_os2);
3040 os<<serializeLongString(tmp_os2.str());
3043 std::string s = os.str();
3044 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3045 <<"): size="<<s.size()<<std::endl;
3046 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3048 m_clients.send(peer_id, 0, data, true);
3051 void Server::SendNodeDef(u16 peer_id,
3052 INodeDefManager *nodedef, u16 protocol_version)
3054 DSTACK(__FUNCTION_NAME);
3055 std::ostringstream os(std::ios_base::binary);
3059 u32 length of the next item
3060 zlib-compressed serialized NodeDefManager
3062 writeU16(os, TOCLIENT_NODEDEF);
3063 std::ostringstream tmp_os(std::ios::binary);
3064 nodedef->serialize(tmp_os, protocol_version);
3065 std::ostringstream tmp_os2(std::ios::binary);
3066 compressZlib(tmp_os.str(), tmp_os2);
3067 os<<serializeLongString(tmp_os2.str());
3070 std::string s = os.str();
3071 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3072 <<"): size="<<s.size()<<std::endl;
3073 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3075 m_clients.send(peer_id, 0, data, true);
3079 Non-static send methods
3082 void Server::SendInventory(u16 peer_id)
3084 DSTACK(__FUNCTION_NAME);
3086 PlayerSAO *playersao = getPlayerSAO(peer_id);
3089 playersao->m_inventory_not_sent = false;
3095 std::ostringstream os;
3096 playersao->getInventory()->serialize(os);
3098 std::string s = os.str();
3100 SharedBuffer<u8> data(s.size()+2);
3101 writeU16(&data[0], TOCLIENT_INVENTORY);
3102 memcpy(&data[2], s.c_str(), s.size());
3105 m_clients.send(peer_id, 0, data, true);
3108 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3110 DSTACK(__FUNCTION_NAME);
3112 std::ostringstream os(std::ios_base::binary);
3116 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3117 os.write((char*)buf, 2);
3120 writeU16(buf, message.size());
3121 os.write((char*)buf, 2);
3124 for(u32 i=0; i<message.size(); i++)
3128 os.write((char*)buf, 2);
3132 std::string s = os.str();
3133 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3135 if (peer_id != PEER_ID_INEXISTENT)
3138 m_clients.send(peer_id, 0, data, true);
3142 m_clients.sendToAll(0,data,true);
3146 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3147 const std::string &formname)
3149 DSTACK(__FUNCTION_NAME);
3151 std::ostringstream os(std::ios_base::binary);
3155 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3156 os.write((char*)buf, 2);
3157 os<<serializeLongString(formspec);
3158 os<<serializeString(formname);
3161 std::string s = os.str();
3162 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3164 m_clients.send(peer_id, 0, data, true);
3167 // Spawns a particle on peer with peer_id
3168 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3169 float expirationtime, float size, bool collisiondetection,
3170 bool vertical, std::string texture)
3172 DSTACK(__FUNCTION_NAME);
3174 std::ostringstream os(std::ios_base::binary);
3175 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3176 writeV3F1000(os, pos);
3177 writeV3F1000(os, velocity);
3178 writeV3F1000(os, acceleration);
3179 writeF1000(os, expirationtime);
3180 writeF1000(os, size);
3181 writeU8(os, collisiondetection);
3182 os<<serializeLongString(texture);
3183 writeU8(os, vertical);
3186 std::string s = os.str();
3187 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3189 if (peer_id != PEER_ID_INEXISTENT)
3192 m_clients.send(peer_id, 0, data, true);
3196 m_clients.sendToAll(0,data,true);
3200 // Adds a ParticleSpawner on peer with peer_id
3201 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3202 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3203 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3205 DSTACK(__FUNCTION_NAME);
3207 std::ostringstream os(std::ios_base::binary);
3208 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3210 writeU16(os, amount);
3211 writeF1000(os, spawntime);
3212 writeV3F1000(os, minpos);
3213 writeV3F1000(os, maxpos);
3214 writeV3F1000(os, minvel);
3215 writeV3F1000(os, maxvel);
3216 writeV3F1000(os, minacc);
3217 writeV3F1000(os, maxacc);
3218 writeF1000(os, minexptime);
3219 writeF1000(os, maxexptime);
3220 writeF1000(os, minsize);
3221 writeF1000(os, maxsize);
3222 writeU8(os, collisiondetection);
3223 os<<serializeLongString(texture);
3225 writeU8(os, vertical);
3228 std::string s = os.str();
3229 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3231 if (peer_id != PEER_ID_INEXISTENT)
3234 m_clients.send(peer_id, 0, data, true);
3237 m_clients.sendToAll(0,data,true);
3241 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3243 DSTACK(__FUNCTION_NAME);
3245 std::ostringstream os(std::ios_base::binary);
3246 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3251 std::string s = os.str();
3252 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3254 if (peer_id != PEER_ID_INEXISTENT) {
3256 m_clients.send(peer_id, 0, data, true);
3259 m_clients.sendToAll(0,data,true);
3264 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3266 std::ostringstream os(std::ios_base::binary);
3269 writeU16(os, TOCLIENT_HUDADD);
3271 writeU8(os, (u8)form->type);
3272 writeV2F1000(os, form->pos);
3273 os << serializeString(form->name);
3274 writeV2F1000(os, form->scale);
3275 os << serializeString(form->text);
3276 writeU32(os, form->number);
3277 writeU32(os, form->item);
3278 writeU32(os, form->dir);
3279 writeV2F1000(os, form->align);
3280 writeV2F1000(os, form->offset);
3281 writeV3F1000(os, form->world_pos);
3284 std::string s = os.str();
3285 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3287 m_clients.send(peer_id, 1, data, true);
3290 void Server::SendHUDRemove(u16 peer_id, u32 id)
3292 std::ostringstream os(std::ios_base::binary);
3295 writeU16(os, TOCLIENT_HUDRM);
3299 std::string s = os.str();
3300 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3303 m_clients.send(peer_id, 1, data, true);
3306 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3308 std::ostringstream os(std::ios_base::binary);
3311 writeU16(os, TOCLIENT_HUDCHANGE);
3313 writeU8(os, (u8)stat);
3316 case HUD_STAT_SCALE:
3317 case HUD_STAT_ALIGN:
3318 case HUD_STAT_OFFSET:
3319 writeV2F1000(os, *(v2f *)value);
3323 os << serializeString(*(std::string *)value);
3325 case HUD_STAT_WORLD_POS:
3326 writeV3F1000(os, *(v3f *)value);
3328 case HUD_STAT_NUMBER:
3332 writeU32(os, *(u32 *)value);
3337 std::string s = os.str();
3338 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3340 m_clients.send(peer_id, 0, data, true);
3343 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3345 std::ostringstream os(std::ios_base::binary);
3348 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3349 writeU32(os, flags);
3353 std::string s = os.str();
3354 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3356 m_clients.send(peer_id, 0, data, true);
3359 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3361 std::ostringstream os(std::ios_base::binary);
3364 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3365 writeU16(os, param);
3366 os<<serializeString(value);
3369 std::string s = os.str();
3370 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3372 m_clients.send(peer_id, 0, data, true);
3375 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3376 const std::string &type, const std::vector<std::string> ¶ms)
3378 std::ostringstream os(std::ios_base::binary);
3381 writeU16(os, TOCLIENT_SET_SKY);
3382 writeARGB8(os, bgcolor);
3383 os<<serializeString(type);
3384 writeU16(os, params.size());
3385 for(size_t i=0; i<params.size(); i++)
3386 os<<serializeString(params[i]);
3389 std::string s = os.str();
3390 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3392 m_clients.send(peer_id, 0, data, true);
3395 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3398 std::ostringstream os(std::ios_base::binary);
3401 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3402 writeU8(os, do_override);
3403 writeU16(os, ratio*65535);
3406 std::string s = os.str();
3407 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3409 m_clients.send(peer_id, 0, data, true);
3412 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3414 DSTACK(__FUNCTION_NAME);
3417 SharedBuffer<u8> data(2+2+4);
3418 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3419 writeU16(&data[2], time);
3420 writeF1000(&data[4], time_speed);
3422 if (peer_id == PEER_ID_INEXISTENT) {
3423 m_clients.sendToAll(0,data,true);
3427 m_clients.send(peer_id, 0, data, true);
3431 void Server::SendPlayerHP(u16 peer_id)
3433 DSTACK(__FUNCTION_NAME);
3434 PlayerSAO *playersao = getPlayerSAO(peer_id);
3436 playersao->m_hp_not_sent = false;
3437 SendHP(peer_id, playersao->getHP());
3439 // Send to other clients
3440 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3441 ActiveObjectMessage aom(playersao->getId(), true, str);
3442 playersao->m_messages_out.push_back(aom);
3445 void Server::SendPlayerBreath(u16 peer_id)
3447 DSTACK(__FUNCTION_NAME);
3448 PlayerSAO *playersao = getPlayerSAO(peer_id);
3450 playersao->m_breath_not_sent = false;
3451 SendBreath(peer_id, playersao->getBreath());
3454 void Server::SendMovePlayer(u16 peer_id)
3456 DSTACK(__FUNCTION_NAME);
3457 Player *player = m_env->getPlayer(peer_id);
3460 std::ostringstream os(std::ios_base::binary);
3461 writeU16(os, TOCLIENT_MOVE_PLAYER);
3462 writeV3F1000(os, player->getPosition());
3463 writeF1000(os, player->getPitch());
3464 writeF1000(os, player->getYaw());
3467 v3f pos = player->getPosition();
3468 f32 pitch = player->getPitch();
3469 f32 yaw = player->getYaw();
3470 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3471 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3478 std::string s = os.str();
3479 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3481 m_clients.send(peer_id, 0, data, true);
3484 void Server::SendPlayerPrivileges(u16 peer_id)
3486 Player *player = m_env->getPlayer(peer_id);
3488 if(player->peer_id == PEER_ID_INEXISTENT)
3491 std::set<std::string> privs;
3492 m_script->getAuth(player->getName(), NULL, &privs);
3494 std::ostringstream os(std::ios_base::binary);
3495 writeU16(os, TOCLIENT_PRIVILEGES);
3496 writeU16(os, privs.size());
3497 for(std::set<std::string>::const_iterator i = privs.begin();
3498 i != privs.end(); i++){
3499 os<<serializeString(*i);
3503 std::string s = os.str();
3504 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3506 m_clients.send(peer_id, 0, data, true);
3509 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3511 Player *player = m_env->getPlayer(peer_id);
3513 if(player->peer_id == PEER_ID_INEXISTENT)
3516 std::ostringstream os(std::ios_base::binary);
3517 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3518 os<<serializeLongString(player->inventory_formspec);
3521 std::string s = os.str();
3522 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3524 m_clients.send(peer_id, 0, data, true);
3527 s32 Server::playSound(const SimpleSoundSpec &spec,
3528 const ServerSoundParams ¶ms)
3530 // Find out initial position of sound
3531 bool pos_exists = false;
3532 v3f pos = params.getPos(m_env, &pos_exists);
3533 // If position is not found while it should be, cancel sound
3534 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3537 // Filter destination clients
3538 std::list<u16> dst_clients;
3539 if(params.to_player != "")
3541 Player *player = m_env->getPlayer(params.to_player.c_str());
3543 infostream<<"Server::playSound: Player \""<<params.to_player
3544 <<"\" not found"<<std::endl;
3547 if(player->peer_id == PEER_ID_INEXISTENT){
3548 infostream<<"Server::playSound: Player \""<<params.to_player
3549 <<"\" not connected"<<std::endl;
3552 dst_clients.push_back(player->peer_id);
3556 std::list<u16> clients = m_clients.getClientIDs();
3558 for(std::list<u16>::iterator
3559 i = clients.begin(); i != clients.end(); ++i)
3561 Player *player = m_env->getPlayer(*i);
3565 if(player->getPosition().getDistanceFrom(pos) >
3566 params.max_hear_distance)
3569 dst_clients.push_back(*i);
3572 if(dst_clients.size() == 0)
3576 s32 id = m_next_sound_id++;
3577 // The sound will exist as a reference in m_playing_sounds
3578 m_playing_sounds[id] = ServerPlayingSound();
3579 ServerPlayingSound &psound = m_playing_sounds[id];
3580 psound.params = params;
3581 for(std::list<u16>::iterator i = dst_clients.begin();
3582 i != dst_clients.end(); i++)
3583 psound.clients.insert(*i);
3585 std::ostringstream os(std::ios_base::binary);
3586 writeU16(os, TOCLIENT_PLAY_SOUND);
3588 os<<serializeString(spec.name);
3589 writeF1000(os, spec.gain * params.gain);
3590 writeU8(os, params.type);
3591 writeV3F1000(os, pos);
3592 writeU16(os, params.object);
3593 writeU8(os, params.loop);
3595 std::string s = os.str();
3596 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3598 for(std::list<u16>::iterator i = dst_clients.begin();
3599 i != dst_clients.end(); i++){
3601 m_clients.send(*i, 0, data, true);
3605 void Server::stopSound(s32 handle)
3607 // Get sound reference
3608 std::map<s32, ServerPlayingSound>::iterator i =
3609 m_playing_sounds.find(handle);
3610 if(i == m_playing_sounds.end())
3612 ServerPlayingSound &psound = i->second;
3614 std::ostringstream os(std::ios_base::binary);
3615 writeU16(os, TOCLIENT_STOP_SOUND);
3616 writeS32(os, handle);
3618 std::string s = os.str();
3619 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3621 for(std::set<u16>::iterator i = psound.clients.begin();
3622 i != psound.clients.end(); i++){
3624 m_clients.send(*i, 0, data, true);
3626 // Remove sound reference
3627 m_playing_sounds.erase(i);
3630 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3631 std::list<u16> *far_players, float far_d_nodes)
3633 float maxd = far_d_nodes*BS;
3634 v3f p_f = intToFloat(p, BS);
3638 SharedBuffer<u8> reply(replysize);
3639 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3640 writeS16(&reply[2], p.X);
3641 writeS16(&reply[4], p.Y);
3642 writeS16(&reply[6], p.Z);
3644 std::list<u16> clients = m_clients.getClientIDs();
3645 for(std::list<u16>::iterator
3646 i = clients.begin();
3647 i != clients.end(); ++i)
3652 Player *player = m_env->getPlayer(*i);
3655 // If player is far away, only set modified blocks not sent
3656 v3f player_pos = player->getPosition();
3657 if(player_pos.getDistanceFrom(p_f) > maxd)
3659 far_players->push_back(*i);
3666 m_clients.send(*i, 0, reply, true);
3670 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3671 std::list<u16> *far_players, float far_d_nodes,
3672 bool remove_metadata)
3674 float maxd = far_d_nodes*BS;
3675 v3f p_f = intToFloat(p, BS);
3677 std::list<u16> clients = m_clients.getClientIDs();
3678 for(std::list<u16>::iterator
3679 i = clients.begin();
3680 i != clients.end(); ++i)
3686 Player *player = m_env->getPlayer(*i);
3689 // If player is far away, only set modified blocks not sent
3690 v3f player_pos = player->getPosition();
3691 if(player_pos.getDistanceFrom(p_f) > maxd)
3693 far_players->push_back(*i);
3698 SharedBuffer<u8> reply(0);
3700 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3704 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3705 reply = SharedBuffer<u8>(replysize);
3706 writeU16(&reply[0], TOCLIENT_ADDNODE);
3707 writeS16(&reply[2], p.X);
3708 writeS16(&reply[4], p.Y);
3709 writeS16(&reply[6], p.Z);
3710 n.serialize(&reply[8], client->serialization_version);
3711 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3712 writeU8(&reply[index], remove_metadata ? 0 : 1);
3714 if (!remove_metadata) {
3715 if (client->net_proto_version <= 21) {
3716 // Old clients always clear metadata; fix it
3717 // by sending the full block again.
3718 client->SetBlockNotSent(p);
3725 if (reply.getSize() > 0)
3726 m_clients.send(*i, 0, reply, true);
3730 void Server::setBlockNotSent(v3s16 p)
3732 std::list<u16> clients = m_clients.getClientIDs();
3734 for(std::list<u16>::iterator
3735 i = clients.begin();
3736 i != clients.end(); ++i)
3738 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3739 client->SetBlockNotSent(p);
3744 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3746 DSTACK(__FUNCTION_NAME);
3748 v3s16 p = block->getPos();
3752 bool completely_air = true;
3753 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3754 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3755 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3757 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3759 completely_air = false;
3760 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3765 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3767 infostream<<"[completely air] ";
3768 infostream<<std::endl;
3772 Create a packet with the block in the right format
3775 std::ostringstream os(std::ios_base::binary);
3776 block->serialize(os, ver, false);
3777 block->serializeNetworkSpecific(os, net_proto_version);
3778 std::string s = os.str();
3779 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3781 u32 replysize = 8 + blockdata.getSize();
3782 SharedBuffer<u8> reply(replysize);
3783 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3784 writeS16(&reply[2], p.X);
3785 writeS16(&reply[4], p.Y);
3786 writeS16(&reply[6], p.Z);
3787 memcpy(&reply[8], *blockdata, blockdata.getSize());
3789 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3790 <<": \tpacket size: "<<replysize<<std::endl;*/
3795 m_clients.send(peer_id, 2, reply, true);
3798 void Server::SendBlocks(float dtime)
3800 DSTACK(__FUNCTION_NAME);
3802 JMutexAutoLock envlock(m_env_mutex);
3803 //TODO check if one big lock could be faster then multiple small ones
3805 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3807 std::vector<PrioritySortedBlockTransfer> queue;
3809 s32 total_sending = 0;
3812 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3814 std::list<u16> clients = m_clients.getClientIDs();
3817 for(std::list<u16>::iterator
3818 i = clients.begin();
3819 i != clients.end(); ++i)
3821 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3826 total_sending += client->SendingCount();
3827 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3833 // Lowest priority number comes first.
3834 // Lowest is most important.
3835 std::sort(queue.begin(), queue.end());
3838 for(u32 i=0; i<queue.size(); i++)
3840 //TODO: Calculate limit dynamically
3841 if(total_sending >= g_settings->getS32
3842 ("max_simultaneous_block_sends_server_total"))
3845 PrioritySortedBlockTransfer q = queue[i];
3847 MapBlock *block = NULL;
3850 block = m_env->getMap().getBlockNoCreate(q.pos);
3852 catch(InvalidPositionException &e)
3857 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3862 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3864 client->SentBlock(q.pos);
3870 void Server::fillMediaCache()
3872 DSTACK(__FUNCTION_NAME);
3874 infostream<<"Server: Calculating media file checksums"<<std::endl;
3876 // Collect all media file paths
3877 std::list<std::string> paths;
3878 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3879 i != m_mods.end(); i++){
3880 const ModSpec &mod = *i;
3881 paths.push_back(mod.path + DIR_DELIM + "textures");
3882 paths.push_back(mod.path + DIR_DELIM + "sounds");
3883 paths.push_back(mod.path + DIR_DELIM + "media");
3884 paths.push_back(mod.path + DIR_DELIM + "models");
3886 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3888 // Collect media file information from paths into cache
3889 for(std::list<std::string>::iterator i = paths.begin();
3890 i != paths.end(); i++)
3892 std::string mediapath = *i;
3893 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3894 for(u32 j=0; j<dirlist.size(); j++){
3895 if(dirlist[j].dir) // Ignode dirs
3897 std::string filename = dirlist[j].name;
3898 // If name contains illegal characters, ignore the file
3899 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3900 infostream<<"Server: ignoring illegal file name: \""
3901 <<filename<<"\""<<std::endl;
3904 // If name is not in a supported format, ignore it
3905 const char *supported_ext[] = {
3906 ".png", ".jpg", ".bmp", ".tga",
3907 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3909 ".x", ".b3d", ".md2", ".obj",
3912 if(removeStringEnd(filename, supported_ext) == ""){
3913 infostream<<"Server: ignoring unsupported file extension: \""
3914 <<filename<<"\""<<std::endl;
3917 // Ok, attempt to load the file and add to cache
3918 std::string filepath = mediapath + DIR_DELIM + filename;
3920 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3921 if(fis.good() == false){
3922 errorstream<<"Server::fillMediaCache(): Could not open \""
3923 <<filename<<"\" for reading"<<std::endl;
3926 std::ostringstream tmp_os(std::ios_base::binary);
3930 fis.read(buf, 1024);
3931 std::streamsize len = fis.gcount();
3932 tmp_os.write(buf, len);
3941 errorstream<<"Server::fillMediaCache(): Failed to read \""
3942 <<filename<<"\""<<std::endl;
3945 if(tmp_os.str().length() == 0){
3946 errorstream<<"Server::fillMediaCache(): Empty file \""
3947 <<filepath<<"\""<<std::endl;
3952 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3954 unsigned char *digest = sha1.getDigest();
3955 std::string sha1_base64 = base64_encode(digest, 20);
3956 std::string sha1_hex = hex_encode((char*)digest, 20);
3960 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3961 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3966 struct SendableMediaAnnouncement
3969 std::string sha1_digest;
3971 SendableMediaAnnouncement(const std::string &name_="",
3972 const std::string &sha1_digest_=""):
3974 sha1_digest(sha1_digest_)
3978 void Server::sendMediaAnnouncement(u16 peer_id)
3980 DSTACK(__FUNCTION_NAME);
3982 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
3985 std::list<SendableMediaAnnouncement> file_announcements;
3987 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
3988 i != m_media.end(); i++){
3990 file_announcements.push_back(
3991 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
3995 std::ostringstream os(std::ios_base::binary);
4003 u16 length of sha1_digest
4008 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4009 writeU16(os, file_announcements.size());
4011 for(std::list<SendableMediaAnnouncement>::iterator
4012 j = file_announcements.begin();
4013 j != file_announcements.end(); ++j){
4014 os<<serializeString(j->name);
4015 os<<serializeString(j->sha1_digest);
4017 os<<serializeString(g_settings->get("remote_media"));
4020 std::string s = os.str();
4021 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4024 m_clients.send(peer_id, 0, data, true);
4027 struct SendableMedia
4033 SendableMedia(const std::string &name_="", const std::string &path_="",
4034 const std::string &data_=""):
4041 void Server::sendRequestedMedia(u16 peer_id,
4042 const std::list<std::string> &tosend)
4044 DSTACK(__FUNCTION_NAME);
4046 verbosestream<<"Server::sendRequestedMedia(): "
4047 <<"Sending files to client"<<std::endl;
4051 // Put 5kB in one bunch (this is not accurate)
4052 u32 bytes_per_bunch = 5000;
4054 std::vector< std::list<SendableMedia> > file_bunches;
4055 file_bunches.push_back(std::list<SendableMedia>());
4057 u32 file_size_bunch_total = 0;
4059 for(std::list<std::string>::const_iterator i = tosend.begin();
4060 i != tosend.end(); ++i)
4062 const std::string &name = *i;
4064 if(m_media.find(name) == m_media.end()){
4065 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4066 <<"unknown file \""<<(name)<<"\""<<std::endl;
4070 //TODO get path + name
4071 std::string tpath = m_media[name].path;
4074 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4075 if(fis.good() == false){
4076 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4077 <<tpath<<"\" for reading"<<std::endl;
4080 std::ostringstream tmp_os(std::ios_base::binary);
4084 fis.read(buf, 1024);
4085 std::streamsize len = fis.gcount();
4086 tmp_os.write(buf, len);
4087 file_size_bunch_total += len;
4096 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4097 <<name<<"\""<<std::endl;
4100 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4101 <<tname<<"\""<<std::endl;*/
4103 file_bunches[file_bunches.size()-1].push_back(
4104 SendableMedia(name, tpath, tmp_os.str()));
4106 // Start next bunch if got enough data
4107 if(file_size_bunch_total >= bytes_per_bunch){
4108 file_bunches.push_back(std::list<SendableMedia>());
4109 file_size_bunch_total = 0;
4114 /* Create and send packets */
4116 u32 num_bunches = file_bunches.size();
4117 for(u32 i=0; i<num_bunches; i++)
4119 std::ostringstream os(std::ios_base::binary);
4123 u16 total number of texture bunches
4124 u16 index of this bunch
4125 u32 number of files in this bunch
4134 writeU16(os, TOCLIENT_MEDIA);
4135 writeU16(os, num_bunches);
4137 writeU32(os, file_bunches[i].size());
4139 for(std::list<SendableMedia>::iterator
4140 j = file_bunches[i].begin();
4141 j != file_bunches[i].end(); ++j){
4142 os<<serializeString(j->name);
4143 os<<serializeLongString(j->data);
4147 std::string s = os.str();
4148 verbosestream<<"Server::sendRequestedMedia(): bunch "
4149 <<i<<"/"<<num_bunches
4150 <<" files="<<file_bunches[i].size()
4151 <<" size=" <<s.size()<<std::endl;
4152 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4154 m_clients.send(peer_id, 2, data, true);
4158 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4160 if(m_detached_inventories.count(name) == 0){
4161 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4164 Inventory *inv = m_detached_inventories[name];
4166 std::ostringstream os(std::ios_base::binary);
4167 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4168 os<<serializeString(name);
4172 std::string s = os.str();
4173 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4175 if (peer_id != PEER_ID_INEXISTENT)
4178 m_clients.send(peer_id, 0, data, true);
4182 m_clients.sendToAll(0,data,true);
4186 void Server::sendDetachedInventories(u16 peer_id)
4188 DSTACK(__FUNCTION_NAME);
4190 for(std::map<std::string, Inventory*>::iterator
4191 i = m_detached_inventories.begin();
4192 i != m_detached_inventories.end(); i++){
4193 const std::string &name = i->first;
4194 //Inventory *inv = i->second;
4195 sendDetachedInventory(name, peer_id);
4203 void Server::DiePlayer(u16 peer_id)
4205 DSTACK(__FUNCTION_NAME);
4207 PlayerSAO *playersao = getPlayerSAO(peer_id);
4210 infostream<<"Server::DiePlayer(): Player "
4211 <<playersao->getPlayer()->getName()
4212 <<" dies"<<std::endl;
4214 playersao->setHP(0);
4216 // Trigger scripted stuff
4217 m_script->on_dieplayer(playersao);
4219 SendPlayerHP(peer_id);
4220 SendDeathscreen(peer_id, false, v3f(0,0,0));
4223 void Server::RespawnPlayer(u16 peer_id)
4225 DSTACK(__FUNCTION_NAME);
4227 PlayerSAO *playersao = getPlayerSAO(peer_id);
4230 infostream<<"Server::RespawnPlayer(): Player "
4231 <<playersao->getPlayer()->getName()
4232 <<" respawns"<<std::endl;
4234 playersao->setHP(PLAYER_MAX_HP);
4236 bool repositioned = m_script->on_respawnplayer(playersao);
4238 v3f pos = findSpawnPos(m_env->getServerMap());
4239 playersao->setPos(pos);
4243 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4245 DSTACK(__FUNCTION_NAME);
4247 SendAccessDenied(peer_id, reason);
4248 m_clients.event(peer_id,SetDenied);
4249 m_con.DisconnectPeer(peer_id);
4252 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4254 DSTACK(__FUNCTION_NAME);
4255 std::wstring message;
4258 Clear references to playing sounds
4260 for(std::map<s32, ServerPlayingSound>::iterator
4261 i = m_playing_sounds.begin();
4262 i != m_playing_sounds.end();)
4264 ServerPlayingSound &psound = i->second;
4265 psound.clients.erase(peer_id);
4266 if(psound.clients.size() == 0)
4267 m_playing_sounds.erase(i++);
4272 Player *player = m_env->getPlayer(peer_id);
4274 // Collect information about leaving in chat
4276 if(player != NULL && reason != CDR_DENY)
4278 std::wstring name = narrow_to_wide(player->getName());
4281 message += L" left the game.";
4282 if(reason == CDR_TIMEOUT)
4283 message += L" (timed out)";
4287 /* Run scripts and remove from environment */
4291 PlayerSAO *playersao = player->getPlayerSAO();
4294 m_script->on_leaveplayer(playersao);
4296 playersao->disconnected();
4304 if(player != NULL && reason != CDR_DENY)
4306 std::ostringstream os(std::ios_base::binary);
4307 std::list<u16> clients = m_clients.getClientIDs();
4309 for(std::list<u16>::iterator
4310 i = clients.begin();
4311 i != clients.end(); ++i)
4314 Player *player = m_env->getPlayer(*i);
4317 // Get name of player
4318 os<<player->getName()<<" ";
4321 actionstream<<player->getName()<<" "
4322 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4323 <<" List of players: "<<os.str()<<std::endl;
4327 JMutexAutoLock env_lock(m_env_mutex);
4328 m_clients.DeleteClient(peer_id);
4332 // Send leave chat message to all remaining clients
4333 if(message.length() != 0)
4334 SendChatMessage(PEER_ID_INEXISTENT,message);
4337 void Server::UpdateCrafting(u16 peer_id)
4339 DSTACK(__FUNCTION_NAME);
4341 Player* player = m_env->getPlayer(peer_id);
4344 // Get a preview for crafting
4346 InventoryLocation loc;
4347 loc.setPlayer(player->getName());
4348 getCraftingResult(&player->inventory, preview, false, this);
4349 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4351 // Put the new preview in
4352 InventoryList *plist = player->inventory.getList("craftpreview");
4354 assert(plist->getSize() >= 1);
4355 plist->changeItem(0, preview);
4358 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4360 RemoteClient *client = getClientNoEx(peer_id,state_min);
4362 throw ClientNotFoundException("Client not found");
4366 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4368 return m_clients.getClientNoEx(peer_id, state_min);
4371 std::string Server::getPlayerName(u16 peer_id)
4373 Player *player = m_env->getPlayer(peer_id);
4375 return "[id="+itos(peer_id)+"]";
4376 return player->getName();
4379 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4381 Player *player = m_env->getPlayer(peer_id);
4384 return player->getPlayerSAO();
4387 std::wstring Server::getStatusString()
4389 std::wostringstream os(std::ios_base::binary);
4392 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4394 os<<L", uptime="<<m_uptime.get();
4396 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4397 // Information about clients
4400 std::list<u16> clients = m_clients.getClientIDs();
4401 for(std::list<u16>::iterator i = clients.begin();
4402 i != clients.end(); ++i)
4405 Player *player = m_env->getPlayer(*i);
4406 // Get name of player
4407 std::wstring name = L"unknown";
4409 name = narrow_to_wide(player->getName());
4410 // Add name to information string
4418 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4419 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4420 if(g_settings->get("motd") != "")
4421 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4425 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4427 std::set<std::string> privs;
4428 m_script->getAuth(name, NULL, &privs);
4432 bool Server::checkPriv(const std::string &name, const std::string &priv)
4434 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4435 return (privs.count(priv) != 0);
4438 void Server::reportPrivsModified(const std::string &name)
4441 std::list<u16> clients = m_clients.getClientIDs();
4442 for(std::list<u16>::iterator
4443 i = clients.begin();
4444 i != clients.end(); ++i){
4445 Player *player = m_env->getPlayer(*i);
4446 reportPrivsModified(player->getName());
4449 Player *player = m_env->getPlayer(name.c_str());
4452 SendPlayerPrivileges(player->peer_id);
4453 PlayerSAO *sao = player->getPlayerSAO();
4456 sao->updatePrivileges(
4457 getPlayerEffectivePrivs(name),
4462 void Server::reportInventoryFormspecModified(const std::string &name)
4464 Player *player = m_env->getPlayer(name.c_str());
4467 SendPlayerInventoryFormspec(player->peer_id);
4470 void Server::setIpBanned(const std::string &ip, const std::string &name)
4472 m_banmanager->add(ip, name);
4475 void Server::unsetIpBanned(const std::string &ip_or_name)
4477 m_banmanager->remove(ip_or_name);
4480 std::string Server::getBanDescription(const std::string &ip_or_name)
4482 return m_banmanager->getBanDescription(ip_or_name);
4485 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4487 Player *player = m_env->getPlayer(name);
4491 if (player->peer_id == PEER_ID_INEXISTENT)
4494 SendChatMessage(player->peer_id, msg);
4497 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4499 Player *player = m_env->getPlayer(playername);
4503 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4507 SendShowFormspecMessage(player->peer_id, formspec, formname);
4511 u32 Server::hudAdd(Player *player, HudElement *form) {
4515 u32 id = player->getFreeHudID();
4516 if (id < player->hud.size())
4517 player->hud[id] = form;
4519 player->hud.push_back(form);
4521 SendHUDAdd(player->peer_id, id, form);
4525 bool Server::hudRemove(Player *player, u32 id) {
4526 if (!player || id >= player->hud.size() || !player->hud[id])
4529 delete player->hud[id];
4530 player->hud[id] = NULL;
4532 SendHUDRemove(player->peer_id, id);
4536 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4540 SendHUDChange(player->peer_id, id, stat, data);
4544 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4548 SendHUDSetFlags(player->peer_id, flags, mask);
4552 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4555 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4558 std::ostringstream os(std::ios::binary);
4559 writeS32(os, hotbar_itemcount);
4560 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4564 void Server::hudSetHotbarImage(Player *player, std::string name) {
4568 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4571 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4575 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4578 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4579 const std::string &type, const std::vector<std::string> ¶ms)
4584 SendSetSky(player->peer_id, bgcolor, type, params);
4588 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4594 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4598 void Server::notifyPlayers(const std::wstring &msg)
4600 SendChatMessage(PEER_ID_INEXISTENT,msg);
4603 void Server::spawnParticle(const char *playername, v3f pos,
4604 v3f velocity, v3f acceleration,
4605 float expirationtime, float size, bool
4606 collisiondetection, bool vertical, std::string texture)
4608 Player *player = m_env->getPlayer(playername);
4611 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4612 expirationtime, size, collisiondetection, vertical, texture);
4615 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4616 float expirationtime, float size,
4617 bool collisiondetection, bool vertical, std::string texture)
4619 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4620 expirationtime, size, collisiondetection, vertical, texture);
4623 u32 Server::addParticleSpawner(const char *playername,
4624 u16 amount, float spawntime,
4625 v3f minpos, v3f maxpos,
4626 v3f minvel, v3f maxvel,
4627 v3f minacc, v3f maxacc,
4628 float minexptime, float maxexptime,
4629 float minsize, float maxsize,
4630 bool collisiondetection, bool vertical, std::string texture)
4632 Player *player = m_env->getPlayer(playername);
4637 for(;;) // look for unused particlespawner id
4640 if (std::find(m_particlespawner_ids.begin(),
4641 m_particlespawner_ids.end(), id)
4642 == m_particlespawner_ids.end())
4644 m_particlespawner_ids.push_back(id);
4649 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4650 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4651 minexptime, maxexptime, minsize, maxsize,
4652 collisiondetection, vertical, texture, id);
4657 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4658 v3f minpos, v3f maxpos,
4659 v3f minvel, v3f maxvel,
4660 v3f minacc, v3f maxacc,
4661 float minexptime, float maxexptime,
4662 float minsize, float maxsize,
4663 bool collisiondetection, bool vertical, std::string texture)
4666 for(;;) // look for unused particlespawner id
4669 if (std::find(m_particlespawner_ids.begin(),
4670 m_particlespawner_ids.end(), id)
4671 == m_particlespawner_ids.end())
4673 m_particlespawner_ids.push_back(id);
4678 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4679 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4680 minexptime, maxexptime, minsize, maxsize,
4681 collisiondetection, vertical, texture, id);
4686 void Server::deleteParticleSpawner(const char *playername, u32 id)
4688 Player *player = m_env->getPlayer(playername);
4692 m_particlespawner_ids.erase(
4693 std::remove(m_particlespawner_ids.begin(),
4694 m_particlespawner_ids.end(), id),
4695 m_particlespawner_ids.end());
4696 SendDeleteParticleSpawner(player->peer_id, id);
4699 void Server::deleteParticleSpawnerAll(u32 id)
4701 m_particlespawner_ids.erase(
4702 std::remove(m_particlespawner_ids.begin(),
4703 m_particlespawner_ids.end(), id),
4704 m_particlespawner_ids.end());
4705 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4708 Inventory* Server::createDetachedInventory(const std::string &name)
4710 if(m_detached_inventories.count(name) > 0){
4711 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4712 delete m_detached_inventories[name];
4714 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4716 Inventory *inv = new Inventory(m_itemdef);
4718 m_detached_inventories[name] = inv;
4719 //TODO find a better way to do this
4720 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4727 BoolScopeSet(bool *dst, bool val):
4730 m_orig_state = *m_dst;
4735 *m_dst = m_orig_state;
4742 // actions: time-reversed list
4743 // Return value: success/failure
4744 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4745 std::list<std::string> *log)
4747 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4748 ServerMap *map = (ServerMap*)(&m_env->getMap());
4749 // Disable rollback report sink while reverting
4750 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4752 // Fail if no actions to handle
4753 if(actions.empty()){
4754 log->push_back("Nothing to do.");
4761 for(std::list<RollbackAction>::const_iterator
4762 i = actions.begin();
4763 i != actions.end(); i++)
4765 const RollbackAction &action = *i;
4767 bool success = action.applyRevert(map, this, this);
4770 std::ostringstream os;
4771 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4772 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4774 log->push_back(os.str());
4776 std::ostringstream os;
4777 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4778 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4780 log->push_back(os.str());
4784 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4785 <<" failed"<<std::endl;
4787 // Call it done if less than half failed
4788 return num_failed <= num_tried/2;
4791 // IGameDef interface
4793 IItemDefManager* Server::getItemDefManager()
4797 INodeDefManager* Server::getNodeDefManager()
4801 ICraftDefManager* Server::getCraftDefManager()
4805 ITextureSource* Server::getTextureSource()
4809 IShaderSource* Server::getShaderSource()
4813 u16 Server::allocateUnknownNodeId(const std::string &name)
4815 return m_nodedef->allocateDummy(name);
4817 ISoundManager* Server::getSoundManager()
4819 return &dummySoundManager;
4821 MtEventManager* Server::getEventManager()
4825 IRollbackReportSink* Server::getRollbackReportSink()
4827 if(!m_enable_rollback_recording)
4829 if(!m_rollback_sink_enabled)
4834 IWritableItemDefManager* Server::getWritableItemDefManager()
4838 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4842 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4847 const ModSpec* Server::getModSpec(const std::string &modname)
4849 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4850 i != m_mods.end(); i++){
4851 const ModSpec &mod = *i;
4852 if(mod.name == modname)
4857 void Server::getModNames(std::list<std::string> &modlist)
4859 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4861 modlist.push_back(i->name);
4864 std::string Server::getBuiltinLuaPath()
4866 return porting::path_share + DIR_DELIM + "builtin";
4869 v3f findSpawnPos(ServerMap &map)
4871 //return v3f(50,50,50)*BS;
4876 nodepos = v2s16(0,0);
4881 s16 water_level = map.getWaterLevel();
4883 // Try to find a good place a few times
4884 for(s32 i=0; i<1000; i++)
4887 // We're going to try to throw the player to this position
4888 v2s16 nodepos2d = v2s16(
4889 -range + (myrand() % (range * 2)),
4890 -range + (myrand() % (range * 2)));
4892 // Get ground height at point
4893 s16 groundheight = map.findGroundLevel(nodepos2d);
4894 if (groundheight <= water_level) // Don't go underwater
4896 if (groundheight > water_level + 6) // Don't go to high places
4899 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4900 bool is_good = false;
4902 for (s32 i = 0; i < 10; i++) {
4903 v3s16 blockpos = getNodeBlockPos(nodepos);
4904 map.emergeBlock(blockpos, true);
4905 content_t c = map.getNodeNoEx(nodepos).getContent();
4906 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4908 if (air_count >= 2){
4916 // Found a good place
4917 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4923 return intToFloat(nodepos, BS);
4926 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4928 RemotePlayer *player = NULL;
4929 bool newplayer = false;
4932 Try to get an existing player
4934 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4936 // If player is already connected, cancel
4937 if(player != NULL && player->peer_id != 0)
4939 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4944 If player with the wanted peer_id already exists, cancel.
4946 if(m_env->getPlayer(peer_id) != NULL)
4948 infostream<<"emergePlayer(): Player with wrong name but same"
4949 " peer_id already exists"<<std::endl;
4954 Create a new player if it doesn't exist yet
4959 player = new RemotePlayer(this);
4960 player->updateName(name);
4962 /* Set player position */
4963 infostream<<"Server: Finding spawn place for player \""
4964 <<name<<"\""<<std::endl;
4965 v3f pos = findSpawnPos(m_env->getServerMap());
4966 player->setPosition(pos);
4968 /* Add player to environment */
4969 m_env->addPlayer(player);
4973 Create a new player active object
4975 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4976 getPlayerEffectivePrivs(player->getName()),
4979 /* Clean up old HUD elements from previous sessions */
4980 player->hud.clear();
4982 /* Add object to environment */
4983 m_env->addActiveObject(playersao);
4987 m_script->on_newplayer(playersao);
4992 void dedicated_server_loop(Server &server, bool &kill)
4994 DSTACK(__FUNCTION_NAME);
4996 verbosestream<<"dedicated_server_loop()"<<std::endl;
4998 IntervalLimiter m_profiler_interval;
5002 float steplen = g_settings->getFloat("dedicated_server_step");
5003 // This is kind of a hack but can be done like this
5004 // because server.step() is very light
5006 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5007 sleep_ms((int)(steplen*1000.0));
5009 server.step(steplen);
5011 if(server.getShutdownRequested() || kill)
5013 infostream<<"Dedicated server quitting"<<std::endl;
5015 if(g_settings->getBool("server_announce") == true)
5016 ServerList::sendAnnounce("delete");
5024 float profiler_print_interval =
5025 g_settings->getFloat("profiler_print_interval");
5026 if(profiler_print_interval != 0)
5028 if(m_profiler_interval.step(steplen, profiler_print_interval))
5030 infostream<<"Profiler:"<<std::endl;
5031 g_profiler->print(infostream);
5032 g_profiler->clear();