3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_rollback_sink_enabled(true),
185 m_enable_rollback_recording(false),
188 m_itemdef(createItemDefManager()),
189 m_nodedef(createNodeDefManager()),
190 m_craftdef(createCraftDefManager()),
191 m_event(new EventManager()),
193 m_time_of_day_send_timer(0),
196 m_shutdown_requested(false),
197 m_ignore_map_edit_events(false),
198 m_ignore_map_edit_events_peer_id(0)
201 m_liquid_transform_timer = 0.0;
202 m_liquid_transform_every = 1.0;
203 m_print_info_timer = 0.0;
204 m_masterserver_timer = 0.0;
205 m_objectdata_timer = 0.0;
206 m_emergethread_trigger_timer = 0.0;
207 m_savemap_timer = 0.0;
210 m_lag = g_settings->getFloat("dedicated_server_step");
213 throw ServerError("Supplied empty world path");
215 if(!gamespec.isValid())
216 throw ServerError("Supplied invalid gamespec");
218 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
219 if(m_simple_singleplayer_mode)
220 infostream<<" in simple singleplayer mode"<<std::endl;
222 infostream<<std::endl;
223 infostream<<"- world: "<<m_path_world<<std::endl;
224 infostream<<"- game: "<<m_gamespec.path<<std::endl;
226 // Initialize default settings and override defaults with those provided
228 set_default_settings(g_settings);
229 Settings gamedefaults;
230 getGameMinetestConfig(gamespec.path, gamedefaults);
231 override_default_settings(g_settings, &gamedefaults);
233 // Create server thread
234 m_thread = new ServerThread(this);
236 // Create emerge manager
237 m_emerge = new EmergeManager(this);
239 // Create world if it doesn't exist
240 if(!initializeWorld(m_path_world, m_gamespec.id))
241 throw ServerError("Failed to initialize world");
243 // Create ban manager
244 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
245 m_banmanager = new BanManager(ban_path);
247 // Create rollback manager
248 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
249 m_rollback = createRollbackManager(rollback_path, this);
251 ModConfiguration modconf(m_path_world);
252 m_mods = modconf.getMods();
253 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
254 // complain about mods with unsatisfied dependencies
255 if(!modconf.isConsistent())
257 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
258 it != unsatisfied_mods.end(); ++it)
261 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
262 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
263 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
264 errorstream << " \"" << *dep_it << "\"";
265 errorstream << std::endl;
269 Settings worldmt_settings;
270 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
271 worldmt_settings.readConfigFile(worldmt.c_str());
272 std::vector<std::string> names = worldmt_settings.getNames();
273 std::set<std::string> load_mod_names;
274 for(std::vector<std::string>::iterator it = names.begin();
275 it != names.end(); ++it)
277 std::string name = *it;
278 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
279 load_mod_names.insert(name.substr(9));
281 // complain about mods declared to be loaded, but not found
282 for(std::vector<ModSpec>::iterator it = m_mods.begin();
283 it != m_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
286 it != unsatisfied_mods.end(); ++it)
287 load_mod_names.erase((*it).name);
288 if(!load_mod_names.empty())
290 errorstream << "The following mods could not be found:";
291 for(std::set<std::string>::iterator it = load_mod_names.begin();
292 it != load_mod_names.end(); ++it)
293 errorstream << " \"" << (*it) << "\"";
294 errorstream << std::endl;
297 // Path to builtin.lua
298 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
301 JMutexAutoLock envlock(m_env_mutex);
303 // Initialize scripting
304 infostream<<"Server: Initializing Lua"<<std::endl;
306 m_script = new GameScripting(this);
309 // Load and run builtin.lua
310 infostream<<"Server: Loading builtin.lua [\""
311 <<builtinpath<<"\"]"<<std::endl;
312 bool success = m_script->loadMod(builtinpath, "__builtin");
314 errorstream<<"Server: Failed to load and run "
315 <<builtinpath<<std::endl;
316 throw ModError("Failed to load and run "+builtinpath);
319 infostream<<"Server: Loading mods: ";
320 for(std::vector<ModSpec>::iterator i = m_mods.begin();
321 i != m_mods.end(); i++){
322 const ModSpec &mod = *i;
323 infostream<<mod.name<<" ";
325 infostream<<std::endl;
326 // Load and run "mod" scripts
327 for(std::vector<ModSpec>::iterator i = m_mods.begin();
328 i != m_mods.end(); i++){
329 const ModSpec &mod = *i;
330 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
331 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
332 <<scriptpath<<"\"]"<<std::endl;
333 bool success = m_script->loadMod(scriptpath, mod.name);
335 errorstream<<"Server: Failed to load and run "
336 <<scriptpath<<std::endl;
337 throw ModError("Failed to load and run "+scriptpath);
341 // Read Textures and calculate sha1 sums
344 // Apply item aliases in the node definition manager
345 m_nodedef->updateAliases(m_itemdef);
347 // Load the mapgen params from global settings now after any
348 // initial overrides have been set by the mods
349 m_emerge->loadMapgenParams();
351 // Initialize Environment
352 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
353 m_env = new ServerEnvironment(servermap, m_script, this);
355 m_clients.setEnv(m_env);
357 // Run some callbacks after the MG params have been set up but before activation
358 m_script->environment_OnMapgenInit(&m_emerge->params);
360 // Initialize mapgens
361 m_emerge->initMapgens();
363 // Give environment reference to scripting api
364 m_script->initializeEnvironment(m_env);
366 // Register us to receive map edit events
367 servermap->addEventReceiver(this);
369 // If file exists, load environment metadata
370 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
372 infostream<<"Server: Loading environment metadata"<<std::endl;
373 m_env->loadMeta(m_path_world);
377 infostream<<"Server: Loading players"<<std::endl;
378 m_env->deSerializePlayers(m_path_world);
381 Add some test ActiveBlockModifiers to environment
383 add_legacy_abms(m_env, m_nodedef);
385 m_liquid_transform_every = g_settings->getFloat("liquid_update");
390 infostream<<"Server destructing"<<std::endl;
393 Send shutdown message
396 std::wstring line = L"*** Server shutting down";
397 SendChatMessage(PEER_ID_INEXISTENT, line);
401 JMutexAutoLock envlock(m_env_mutex);
404 Execute script shutdown hooks
406 m_script->on_shutdown();
410 JMutexAutoLock envlock(m_env_mutex);
415 infostream<<"Server: Saving players"<<std::endl;
416 m_env->serializePlayers(m_path_world);
419 Save environment metadata
421 infostream<<"Server: Saving environment metadata"<<std::endl;
422 m_env->saveMeta(m_path_world);
431 // stop all emerge threads before deleting players that may have
432 // requested blocks to be emerged
433 m_emerge->stopThreads();
435 // Delete things in the reverse order of creation
438 // N.B. the EmergeManager should be deleted after the Environment since Map
439 // depends on EmergeManager to write its current params to the map meta
448 // Deinitialize scripting
449 infostream<<"Server: Deinitializing scripting"<<std::endl;
452 // Delete detached inventories
454 for(std::map<std::string, Inventory*>::iterator
455 i = m_detached_inventories.begin();
456 i != m_detached_inventories.end(); i++){
462 void Server::start(Address bind_addr)
464 DSTACK(__FUNCTION_NAME);
465 infostream<<"Starting server on "
466 << bind_addr.serializeString() <<"..."<<std::endl;
468 // Stop thread if already running
471 // Initialize connection
472 m_con.SetTimeoutMs(30);
473 m_con.Serve(bind_addr);
478 // ASCII art for the win!
480 <<" .__ __ __ "<<std::endl
481 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
482 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
483 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
484 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
485 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
486 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
487 actionstream<<"Server for gameid=\""<<m_gamespec.id
488 <<"\" listening on "<<bind_addr.serializeString()<<":"
489 <<bind_addr.getPort() << "."<<std::endl;
494 DSTACK(__FUNCTION_NAME);
496 infostream<<"Server: Stopping and waiting threads"<<std::endl;
498 // Stop threads (set run=false first so both start stopping)
500 //m_emergethread.setRun(false);
502 //m_emergethread.stop();
504 infostream<<"Server: Threads stopped"<<std::endl;
507 void Server::step(float dtime)
509 DSTACK(__FUNCTION_NAME);
514 JMutexAutoLock lock(m_step_dtime_mutex);
515 m_step_dtime += dtime;
517 // Throw if fatal error occurred in thread
518 std::string async_err = m_async_fatal_error.get();
520 throw ServerError(async_err);
524 void Server::AsyncRunStep(bool initial_step)
526 DSTACK(__FUNCTION_NAME);
528 g_profiler->add("Server::AsyncRunStep (num)", 1);
532 JMutexAutoLock lock1(m_step_dtime_mutex);
533 dtime = m_step_dtime;
537 // Send blocks to clients
541 if((dtime < 0.001) && (initial_step == false))
544 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
546 //infostream<<"Server steps "<<dtime<<std::endl;
547 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
550 JMutexAutoLock lock1(m_step_dtime_mutex);
551 m_step_dtime -= dtime;
558 m_uptime.set(m_uptime.get() + dtime);
564 Update time of day and overall game time
567 JMutexAutoLock envlock(m_env_mutex);
569 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
572 Send to clients at constant intervals
575 m_time_of_day_send_timer -= dtime;
576 if(m_time_of_day_send_timer < 0.0)
578 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
579 u16 time = m_env->getTimeOfDay();
580 float time_speed = g_settings->getFloat("time_speed");
581 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
586 JMutexAutoLock lock(m_env_mutex);
587 // Figure out and report maximum lag to environment
588 float max_lag = m_env->getMaxLagEstimate();
589 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
591 if(dtime > 0.1 && dtime > max_lag * 2.0)
592 infostream<<"Server: Maximum lag peaked to "<<dtime
596 m_env->reportMaxLagEstimate(max_lag);
598 ScopeProfiler sp(g_profiler, "SEnv step");
599 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
603 const float map_timer_and_unload_dtime = 2.92;
604 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
606 JMutexAutoLock lock(m_env_mutex);
607 // Run Map's timers and unload unused data
608 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
609 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
610 g_settings->getFloat("server_unload_unused_data_timeout"));
621 JMutexAutoLock lock(m_env_mutex);
623 std::list<u16> clientids = m_clients.getClientIDs();
625 ScopeProfiler sp(g_profiler, "Server: handle players");
627 for(std::list<u16>::iterator
628 i = clientids.begin();
629 i != clientids.end(); ++i)
631 PlayerSAO *playersao = getPlayerSAO(*i);
632 if(playersao == NULL)
636 Handle player HPs (die if hp=0)
638 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
640 if(playersao->getHP() == 0)
647 Send player breath if changed
649 if(playersao->m_breath_not_sent) {
650 SendPlayerBreath(*i);
654 Send player inventories if necessary
656 if(playersao->m_moved){
658 playersao->m_moved = false;
660 if(playersao->m_inventory_not_sent){
667 /* Transform liquids */
668 m_liquid_transform_timer += dtime;
669 if(m_liquid_transform_timer >= m_liquid_transform_every)
671 m_liquid_transform_timer -= m_liquid_transform_every;
673 JMutexAutoLock lock(m_env_mutex);
675 ScopeProfiler sp(g_profiler, "Server: liquid transform");
677 std::map<v3s16, MapBlock*> modified_blocks;
678 m_env->getMap().transformLiquids(modified_blocks);
683 core::map<v3s16, MapBlock*> lighting_modified_blocks;
684 ServerMap &map = ((ServerMap&)m_env->getMap());
685 map.updateLighting(modified_blocks, lighting_modified_blocks);
687 // Add blocks modified by lighting to modified_blocks
688 for(core::map<v3s16, MapBlock*>::Iterator
689 i = lighting_modified_blocks.getIterator();
690 i.atEnd() == false; i++)
692 MapBlock *block = i.getNode()->getValue();
693 modified_blocks.insert(block->getPos(), block);
697 Set the modified blocks unsent for all the clients
699 if(modified_blocks.size() > 0)
701 SetBlocksNotSent(modified_blocks);
704 m_clients.step(dtime);
706 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
708 // send masterserver announce
710 float &counter = m_masterserver_timer;
711 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
712 g_settings->getBool("server_announce") == true)
714 ServerList::sendAnnounce(!counter ? "start" : "update",
715 m_clients.getPlayerNames(),
717 m_env->getGameTime(),
728 Check added and deleted active objects
731 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
732 JMutexAutoLock envlock(m_env_mutex);
735 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
736 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
738 // Radius inside which objects are active
739 s16 radius = g_settings->getS16("active_object_send_range_blocks");
740 radius *= MAP_BLOCKSIZE;
742 for(std::map<u16, RemoteClient*>::iterator
744 i != clients.end(); ++i)
746 RemoteClient *client = i->second;
748 // If definitions and textures have not been sent, don't
749 // send objects either
750 if (client->getState() < DefinitionsSent)
753 Player *player = m_env->getPlayer(client->peer_id);
756 // This can happen if the client timeouts somehow
757 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
759 <<" has no associated player"<<std::endl;*/
762 v3s16 pos = floatToInt(player->getPosition(), BS);
764 std::set<u16> removed_objects;
765 std::set<u16> added_objects;
766 m_env->getRemovedActiveObjects(pos, radius,
767 client->m_known_objects, removed_objects);
768 m_env->getAddedActiveObjects(pos, radius,
769 client->m_known_objects, added_objects);
771 // Ignore if nothing happened
772 if(removed_objects.size() == 0 && added_objects.size() == 0)
774 //infostream<<"active objects: none changed"<<std::endl;
778 std::string data_buffer;
782 // Handle removed objects
783 writeU16((u8*)buf, removed_objects.size());
784 data_buffer.append(buf, 2);
785 for(std::set<u16>::iterator
786 i = removed_objects.begin();
787 i != removed_objects.end(); ++i)
791 ServerActiveObject* obj = m_env->getActiveObject(id);
793 // Add to data buffer for sending
794 writeU16((u8*)buf, id);
795 data_buffer.append(buf, 2);
797 // Remove from known objects
798 client->m_known_objects.erase(id);
800 if(obj && obj->m_known_by_count > 0)
801 obj->m_known_by_count--;
804 // Handle added objects
805 writeU16((u8*)buf, added_objects.size());
806 data_buffer.append(buf, 2);
807 for(std::set<u16>::iterator
808 i = added_objects.begin();
809 i != added_objects.end(); ++i)
813 ServerActiveObject* obj = m_env->getActiveObject(id);
816 u8 type = ACTIVEOBJECT_TYPE_INVALID;
818 infostream<<"WARNING: "<<__FUNCTION_NAME
819 <<": NULL object"<<std::endl;
821 type = obj->getSendType();
823 // Add to data buffer for sending
824 writeU16((u8*)buf, id);
825 data_buffer.append(buf, 2);
826 writeU8((u8*)buf, type);
827 data_buffer.append(buf, 1);
830 data_buffer.append(serializeLongString(
831 obj->getClientInitializationData(client->net_proto_version)));
833 data_buffer.append(serializeLongString(""));
835 // Add to known objects
836 client->m_known_objects.insert(id);
839 obj->m_known_by_count++;
843 SharedBuffer<u8> reply(2 + data_buffer.size());
844 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
845 memcpy((char*)&reply[2], data_buffer.c_str(),
848 m_clients.send(client->peer_id, 0, reply, true);
850 verbosestream<<"Server: Sent object remove/add: "
851 <<removed_objects.size()<<" removed, "
852 <<added_objects.size()<<" added, "
853 <<"packet size is "<<reply.getSize()<<std::endl;
858 Collect a list of all the objects known by the clients
859 and report it back to the environment.
862 core::map<u16, bool> all_known_objects;
864 for(core::map<u16, RemoteClient*>::Iterator
865 i = m_clients.getIterator();
866 i.atEnd() == false; i++)
868 RemoteClient *client = i.getNode()->getValue();
869 // Go through all known objects of client
870 for(core::map<u16, bool>::Iterator
871 i = client->m_known_objects.getIterator();
872 i.atEnd()==false; i++)
874 u16 id = i.getNode()->getKey();
875 all_known_objects[id] = true;
879 m_env->setKnownActiveObjects(whatever);
888 JMutexAutoLock envlock(m_env_mutex);
889 ScopeProfiler sp(g_profiler, "Server: sending object messages");
892 // Value = data sent by object
893 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
895 // Get active object messages from environment
898 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
902 std::list<ActiveObjectMessage>* message_list = NULL;
903 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
904 n = buffered_messages.find(aom.id);
905 if(n == buffered_messages.end())
907 message_list = new std::list<ActiveObjectMessage>;
908 buffered_messages[aom.id] = message_list;
912 message_list = n->second;
914 message_list->push_back(aom);
918 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
919 // Route data to every client
920 for(std::map<u16, RemoteClient*>::iterator
922 i != clients.end(); ++i)
924 RemoteClient *client = i->second;
925 std::string reliable_data;
926 std::string unreliable_data;
927 // Go through all objects in message buffer
928 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
929 j = buffered_messages.begin();
930 j != buffered_messages.end(); ++j)
932 // If object is not known by client, skip it
934 if(client->m_known_objects.find(id) == client->m_known_objects.end())
936 // Get message list of object
937 std::list<ActiveObjectMessage>* list = j->second;
938 // Go through every message
939 for(std::list<ActiveObjectMessage>::iterator
940 k = list->begin(); k != list->end(); ++k)
942 // Compose the full new data with header
943 ActiveObjectMessage aom = *k;
944 std::string new_data;
947 writeU16((u8*)&buf[0], aom.id);
948 new_data.append(buf, 2);
950 new_data += serializeString(aom.datastring);
951 // Add data to buffer
953 reliable_data += new_data;
955 unreliable_data += new_data;
959 reliable_data and unreliable_data are now ready.
962 if(reliable_data.size() > 0)
964 SharedBuffer<u8> reply(2 + reliable_data.size());
965 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
966 memcpy((char*)&reply[2], reliable_data.c_str(),
967 reliable_data.size());
969 m_clients.send(client->peer_id, 0, reply, true);
971 if(unreliable_data.size() > 0)
973 SharedBuffer<u8> reply(2 + unreliable_data.size());
974 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
975 memcpy((char*)&reply[2], unreliable_data.c_str(),
976 unreliable_data.size());
977 // Send as unreliable
978 m_clients.send(client->peer_id, 1, reply, false);
981 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
983 infostream<<"Server: Size of object message data: "
984 <<"reliable: "<<reliable_data.size()
985 <<", unreliable: "<<unreliable_data.size()
991 // Clear buffered_messages
992 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
993 i = buffered_messages.begin();
994 i != buffered_messages.end(); ++i)
1001 Send queued-for-sending map edit events.
1004 // We will be accessing the environment
1005 JMutexAutoLock lock(m_env_mutex);
1007 // Don't send too many at a time
1010 // Single change sending is disabled if queue size is not small
1011 bool disable_single_change_sending = false;
1012 if(m_unsent_map_edit_queue.size() >= 4)
1013 disable_single_change_sending = true;
1015 int event_count = m_unsent_map_edit_queue.size();
1017 // We'll log the amount of each
1020 while(m_unsent_map_edit_queue.size() != 0)
1022 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1024 // Players far away from the change are stored here.
1025 // Instead of sending the changes, MapBlocks are set not sent
1027 std::list<u16> far_players;
1029 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1031 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1032 prof.add("MEET_ADDNODE", 1);
1033 if(disable_single_change_sending)
1034 sendAddNode(event->p, event->n, event->already_known_by_peer,
1035 &far_players, 5, event->type == MEET_ADDNODE);
1037 sendAddNode(event->p, event->n, event->already_known_by_peer,
1038 &far_players, 30, event->type == MEET_ADDNODE);
1040 else if(event->type == MEET_REMOVENODE)
1042 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1043 prof.add("MEET_REMOVENODE", 1);
1044 if(disable_single_change_sending)
1045 sendRemoveNode(event->p, event->already_known_by_peer,
1048 sendRemoveNode(event->p, event->already_known_by_peer,
1051 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1053 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1054 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1055 setBlockNotSent(event->p);
1057 else if(event->type == MEET_OTHER)
1059 infostream<<"Server: MEET_OTHER"<<std::endl;
1060 prof.add("MEET_OTHER", 1);
1061 for(std::set<v3s16>::iterator
1062 i = event->modified_blocks.begin();
1063 i != event->modified_blocks.end(); ++i)
1065 setBlockNotSent(*i);
1070 prof.add("unknown", 1);
1071 infostream<<"WARNING: Server: Unknown MapEditEvent "
1072 <<((u32)event->type)<<std::endl;
1076 Set blocks not sent to far players
1078 if(far_players.size() > 0)
1080 // Convert list format to that wanted by SetBlocksNotSent
1081 std::map<v3s16, MapBlock*> modified_blocks2;
1082 for(std::set<v3s16>::iterator
1083 i = event->modified_blocks.begin();
1084 i != event->modified_blocks.end(); ++i)
1086 modified_blocks2[*i] =
1087 m_env->getMap().getBlockNoCreateNoEx(*i);
1089 // Set blocks not sent
1090 for(std::list<u16>::iterator
1091 i = far_players.begin();
1092 i != far_players.end(); ++i)
1095 RemoteClient *client = getClient(peer_id);
1098 client->SetBlocksNotSent(modified_blocks2);
1104 /*// Don't send too many at a time
1106 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1110 if(event_count >= 5){
1111 infostream<<"Server: MapEditEvents:"<<std::endl;
1112 prof.print(infostream);
1113 } else if(event_count != 0){
1114 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1115 prof.print(verbosestream);
1121 Trigger emergethread (it somehow gets to a non-triggered but
1122 bysy state sometimes)
1125 float &counter = m_emergethread_trigger_timer;
1131 m_emerge->startThreads();
1133 // Update m_enable_rollback_recording here too
1134 m_enable_rollback_recording =
1135 g_settings->getBool("enable_rollback_recording");
1139 // Save map, players and auth stuff
1141 float &counter = m_savemap_timer;
1143 if(counter >= g_settings->getFloat("server_map_save_interval"))
1146 JMutexAutoLock lock(m_env_mutex);
1148 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1151 if(m_banmanager->isModified())
1152 m_banmanager->save();
1154 // Save changed parts of map
1155 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1158 m_env->serializePlayers(m_path_world);
1160 // Save environment metadata
1161 m_env->saveMeta(m_path_world);
1166 void Server::Receive()
1168 DSTACK(__FUNCTION_NAME);
1169 SharedBuffer<u8> data;
1173 datasize = m_con.Receive(peer_id,data);
1174 ProcessData(*data, datasize, peer_id);
1176 catch(con::InvalidIncomingDataException &e)
1178 infostream<<"Server::Receive(): "
1179 "InvalidIncomingDataException: what()="
1180 <<e.what()<<std::endl;
1182 catch(con::PeerNotFoundException &e)
1184 //NOTE: This is not needed anymore
1186 // The peer has been disconnected.
1187 // Find the associated player and remove it.
1189 /*JMutexAutoLock envlock(m_env_mutex);
1191 infostream<<"ServerThread: peer_id="<<peer_id
1192 <<" has apparently closed connection. "
1193 <<"Removing player."<<std::endl;
1195 m_env->removePlayer(peer_id);*/
1197 catch(ClientStateError &e)
1199 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1200 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1201 L"Try reconnecting or updating your client");
1205 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1207 std::string playername = "";
1208 PlayerSAO *playersao = NULL;
1210 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
1211 if (client != NULL) {
1212 playername = client->getName();
1213 playersao = emergePlayer(playername.c_str(), peer_id);
1217 RemotePlayer *player =
1218 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1220 // If failed, cancel
1221 if((playersao == NULL) || (player == NULL))
1223 if(player && player->peer_id != 0){
1224 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1225 <<" (player allocated to an another client)"<<std::endl;
1226 DenyAccess(peer_id, L"Another client is connected with this "
1227 L"name. If your client closed unexpectedly, try again in "
1230 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1232 DenyAccess(peer_id, L"Could not allocate player.");
1238 Send complete position information
1240 SendMovePlayer(peer_id);
1243 SendPlayerPrivileges(peer_id);
1245 // Send inventory formspec
1246 SendPlayerInventoryFormspec(peer_id);
1249 UpdateCrafting(peer_id);
1250 SendInventory(peer_id);
1253 if(g_settings->getBool("enable_damage"))
1254 SendPlayerHP(peer_id);
1257 SendPlayerBreath(peer_id);
1259 // Show death screen if necessary
1261 SendDeathscreen(peer_id, false, v3f(0,0,0));
1263 // Note things in chat if not in simple singleplayer mode
1264 if(!m_simple_singleplayer_mode)
1266 // Send information about server to player in chat
1267 SendChatMessage(peer_id, getStatusString());
1269 // Send information about joining in chat
1271 std::wstring name = L"unknown";
1272 Player *player = m_env->getPlayer(peer_id);
1274 name = narrow_to_wide(player->getName());
1276 std::wstring message;
1279 message += L" joined the game.";
1280 SendChatMessage(PEER_ID_INEXISTENT,message);
1283 Address addr = getPeerAddress(player->peer_id);
1284 std::string ip_str = addr.serializeString();
1285 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1290 std::vector<std::string> names = m_clients.getPlayerNames();
1292 actionstream<<player->getName() <<" joins game. List of players: ";
1294 for (std::vector<std::string>::iterator i = names.begin();
1295 i != names.end(); i++)
1297 actionstream << *i << " ";
1300 actionstream<<std::endl;
1305 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1307 DSTACK(__FUNCTION_NAME);
1308 // Environment is locked first.
1309 JMutexAutoLock envlock(m_env_mutex);
1311 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1315 Address address = getPeerAddress(peer_id);
1316 addr_s = address.serializeString();
1318 // drop player if is ip is banned
1319 if(m_banmanager->isIpBanned(addr_s)){
1320 std::string ban_name = m_banmanager->getBanName(addr_s);
1321 infostream<<"Server: A banned client tried to connect from "
1322 <<addr_s<<"; banned name was "
1323 <<ban_name<<std::endl;
1324 // This actually doesn't seem to transfer to the client
1325 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1326 +narrow_to_wide(ban_name));
1330 catch(con::PeerNotFoundException &e)
1333 * no peer for this packet found
1334 * most common reason is peer timeout, e.g. peer didn't
1335 * respond for some time, your server was overloaded or
1338 infostream<<"Server::ProcessData(): Cancelling: peer "
1339 <<peer_id<<" not found"<<std::endl;
1349 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1351 if(command == TOSERVER_INIT)
1353 // [0] u16 TOSERVER_INIT
1354 // [2] u8 SER_FMT_VER_HIGHEST_READ
1355 // [3] u8[20] player_name
1356 // [23] u8[28] password <--- can be sent without this, from old versions
1358 if(datasize < 2+1+PLAYERNAME_SIZE)
1361 RemoteClient* client = getClient(peer_id,Created);
1363 // If net_proto_version is set, this client has already been handled
1364 if(client->getState() > Created)
1366 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1367 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1371 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1372 <<peer_id<<")"<<std::endl;
1374 // Do not allow multiple players in simple singleplayer mode.
1375 // This isn't a perfect way to do it, but will suffice for now
1376 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1377 infostream<<"Server: Not allowing another client ("<<addr_s
1378 <<") to connect in simple singleplayer mode"<<std::endl;
1379 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1383 // First byte after command is maximum supported
1384 // serialization version
1385 u8 client_max = data[2];
1386 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1387 // Use the highest version supported by both
1388 u8 deployed = std::min(client_max, our_max);
1389 // If it's lower than the lowest supported, give up.
1390 if(deployed < SER_FMT_VER_LOWEST)
1391 deployed = SER_FMT_VER_INVALID;
1393 if(deployed == SER_FMT_VER_INVALID)
1395 actionstream<<"Server: A mismatched client tried to connect from "
1396 <<addr_s<<std::endl;
1397 infostream<<"Server: Cannot negotiate serialization version with "
1398 <<addr_s<<std::endl;
1399 DenyAccess(peer_id, std::wstring(
1400 L"Your client's version is not supported.\n"
1401 L"Server version is ")
1402 + narrow_to_wide(minetest_version_simple) + L"."
1407 client->setPendingSerializationVersion(deployed);
1410 Read and check network protocol version
1413 u16 min_net_proto_version = 0;
1414 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1415 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1417 // Use same version as minimum and maximum if maximum version field
1418 // doesn't exist (backwards compatibility)
1419 u16 max_net_proto_version = min_net_proto_version;
1420 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1421 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1423 // Start with client's maximum version
1424 u16 net_proto_version = max_net_proto_version;
1426 // Figure out a working version if it is possible at all
1427 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1428 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1430 // If maximum is larger than our maximum, go with our maximum
1431 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1432 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1433 // Else go with client's maximum
1435 net_proto_version = max_net_proto_version;
1438 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1439 <<min_net_proto_version<<", max: "<<max_net_proto_version
1440 <<", chosen: "<<net_proto_version<<std::endl;
1442 client->net_proto_version = net_proto_version;
1444 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1445 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1447 actionstream<<"Server: A mismatched client tried to connect from "
1448 <<addr_s<<std::endl;
1449 DenyAccess(peer_id, std::wstring(
1450 L"Your client's version is not supported.\n"
1451 L"Server version is ")
1452 + narrow_to_wide(minetest_version_simple) + L",\n"
1453 + L"server's PROTOCOL_VERSION is "
1454 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1456 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1457 + L", client's PROTOCOL_VERSION is "
1458 + narrow_to_wide(itos(min_net_proto_version))
1460 + narrow_to_wide(itos(max_net_proto_version))
1465 if(g_settings->getBool("strict_protocol_version_checking"))
1467 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1469 actionstream<<"Server: A mismatched (strict) client tried to "
1470 <<"connect from "<<addr_s<<std::endl;
1471 DenyAccess(peer_id, std::wstring(
1472 L"Your client's version is not supported.\n"
1473 L"Server version is ")
1474 + narrow_to_wide(minetest_version_simple) + L",\n"
1475 + L"server's PROTOCOL_VERSION (strict) is "
1476 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1477 + L", client's PROTOCOL_VERSION is "
1478 + narrow_to_wide(itos(min_net_proto_version))
1480 + narrow_to_wide(itos(max_net_proto_version))
1491 char playername[PLAYERNAME_SIZE];
1492 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1494 playername[i] = data[3+i];
1496 playername[PLAYERNAME_SIZE-1] = 0;
1498 if(playername[0]=='\0')
1500 actionstream<<"Server: Player with an empty name "
1501 <<"tried to connect from "<<addr_s<<std::endl;
1502 DenyAccess(peer_id, L"Empty name");
1506 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1508 actionstream<<"Server: Player with an invalid name "
1509 <<"tried to connect from "<<addr_s<<std::endl;
1510 DenyAccess(peer_id, L"Name contains unallowed characters");
1514 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1516 actionstream<<"Server: Player with the name \"singleplayer\" "
1517 <<"tried to connect from "<<addr_s<<std::endl;
1518 DenyAccess(peer_id, L"Name is not allowed");
1524 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1526 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1527 <<"tried to connect from "<<addr_s<<" "
1528 <<"but it was disallowed for the following reason: "
1529 <<reason<<std::endl;
1530 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1535 infostream<<"Server: New connection: \""<<playername<<"\" from "
1536 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1539 char given_password[PASSWORD_SIZE];
1540 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1542 // old version - assume blank password
1543 given_password[0] = 0;
1547 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1549 given_password[i] = data[23+i];
1551 given_password[PASSWORD_SIZE-1] = 0;
1554 if(!base64_is_valid(given_password)){
1555 actionstream<<"Server: "<<playername
1556 <<" supplied invalid password hash"<<std::endl;
1557 DenyAccess(peer_id, L"Invalid password hash");
1561 // Enforce user limit.
1562 // Don't enforce for users that have some admin right
1563 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1564 !checkPriv(playername, "server") &&
1565 !checkPriv(playername, "ban") &&
1566 !checkPriv(playername, "privs") &&
1567 !checkPriv(playername, "password") &&
1568 playername != g_settings->get("name"))
1570 actionstream<<"Server: "<<playername<<" tried to join, but there"
1571 <<" are already max_users="
1572 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1573 DenyAccess(peer_id, L"Too many users.");
1577 std::string checkpwd; // Password hash to check against
1578 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1580 // If no authentication info exists for user, create it
1582 if(!isSingleplayer() &&
1583 g_settings->getBool("disallow_empty_password") &&
1584 std::string(given_password) == ""){
1585 actionstream<<"Server: "<<playername
1586 <<" supplied empty password"<<std::endl;
1587 DenyAccess(peer_id, L"Empty passwords are "
1588 L"disallowed. Set a password and try again.");
1591 std::wstring raw_default_password =
1592 narrow_to_wide(g_settings->get("default_password"));
1593 std::string initial_password =
1594 translatePassword(playername, raw_default_password);
1596 // If default_password is empty, allow any initial password
1597 if (raw_default_password.length() == 0)
1598 initial_password = given_password;
1600 m_script->createAuth(playername, initial_password);
1603 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1606 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1607 <<" (auth handler does not work?)"<<std::endl;
1608 DenyAccess(peer_id, L"Not allowed to login");
1612 if(given_password != checkpwd){
1613 actionstream<<"Server: "<<playername<<" supplied wrong password"
1615 DenyAccess(peer_id, L"Wrong password");
1619 RemotePlayer *player =
1620 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1622 if(player && player->peer_id != 0){
1623 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1624 <<" (player allocated to an another client)"<<std::endl;
1625 DenyAccess(peer_id, L"Another client is connected with this "
1626 L"name. If your client closed unexpectedly, try again in "
1630 m_clients.setPlayerName(peer_id,playername);
1633 Answer with a TOCLIENT_INIT
1636 SharedBuffer<u8> reply(2+1+6+8+4);
1637 writeU16(&reply[0], TOCLIENT_INIT);
1638 writeU8(&reply[2], deployed);
1639 //send dummy pos for legacy reasons only
1640 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1641 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1642 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1645 m_clients.send(peer_id, 0, reply, true);
1646 m_clients.event(peer_id, Init);
1652 if(command == TOSERVER_INIT2)
1655 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1656 <<peer_id<<std::endl;
1658 m_clients.event(peer_id, GotInit2);
1659 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1662 ///// begin compatibility code
1663 PlayerSAO* playersao = NULL;
1664 if (protocol_version <= 22) {
1665 playersao = StageTwoClientInit(peer_id);
1667 if (playersao == NULL) {
1669 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1670 << peer_id << std::endl;
1674 ///// end compatibility code
1677 Send some initialization data
1680 infostream<<"Server: Sending content to "
1681 <<getPlayerName(peer_id)<<std::endl;
1683 // Send player movement settings
1684 SendMovement(peer_id);
1686 // Send item definitions
1687 SendItemDef(peer_id, m_itemdef, protocol_version);
1689 // Send node definitions
1690 SendNodeDef(peer_id, m_nodedef, protocol_version);
1692 m_clients.event(peer_id, SetDefinitionsSent);
1694 // Send media announcement
1695 sendMediaAnnouncement(peer_id);
1697 // Send detached inventories
1698 sendDetachedInventories(peer_id);
1701 u16 time = m_env->getTimeOfDay();
1702 float time_speed = g_settings->getFloat("time_speed");
1703 SendTimeOfDay(peer_id, time, time_speed);
1705 ///// begin compatibility code
1706 if (protocol_version <= 22) {
1707 m_clients.event(peer_id, SetClientReady);
1708 m_script->on_joinplayer(playersao);
1710 ///// end compatibility code
1712 // Warnings about protocol version can be issued here
1713 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1715 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1716 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1722 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1723 u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1725 if(peer_ser_ver == SER_FMT_VER_INVALID)
1727 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1728 " serialization format invalid or not initialized."
1729 " Skipping incoming command="<<command<<std::endl;
1733 /* Handle commands relate to client startup */
1734 if(command == TOSERVER_REQUEST_MEDIA) {
1735 std::string datastring((char*)&data[2], datasize-2);
1736 std::istringstream is(datastring, std::ios_base::binary);
1738 std::list<std::string> tosend;
1739 u16 numfiles = readU16(is);
1741 infostream<<"Sending "<<numfiles<<" files to "
1742 <<getPlayerName(peer_id)<<std::endl;
1743 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1745 for(int i = 0; i < numfiles; i++) {
1746 std::string name = deSerializeString(is);
1747 tosend.push_back(name);
1748 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1752 sendRequestedMedia(peer_id, tosend);
1755 else if(command == TOSERVER_RECEIVED_MEDIA) {
1758 else if(command == TOSERVER_CLIENT_READY) {
1759 // clients <= protocol version 22 did not send ready message,
1760 // they're already initialized
1761 assert(peer_proto_ver > 22);
1763 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1765 if (playersao == NULL) {
1767 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1768 << peer_id << std::endl;
1776 m_clients.setClientVersion(
1778 data[2], data[3], data[4],
1779 std::string((char*) &data[8],(u16) data[6]));
1781 m_clients.event(peer_id, SetClientReady);
1782 m_script->on_joinplayer(playersao);
1785 else if(command == TOSERVER_GOTBLOCKS)
1798 u16 count = data[2];
1799 for(u16 i=0; i<count; i++)
1801 if((s16)datasize < 2+1+(i+1)*6)
1802 throw con::InvalidIncomingDataException
1803 ("GOTBLOCKS length is too short");
1804 v3s16 p = readV3S16(&data[2+1+i*6]);
1805 /*infostream<<"Server: GOTBLOCKS ("
1806 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1807 RemoteClient *client = getClient(peer_id);
1808 client->GotBlock(p);
1813 if (m_clients.getClientState(peer_id) < Active)
1815 if (command == TOSERVER_PLAYERPOS) return;
1817 errorstream<<"Got packet command: " << command << " for peer id "
1818 << peer_id << " but client isn't active yet. Dropping packet "
1823 Player *player = m_env->getPlayer(peer_id);
1825 errorstream<<"Server::ProcessData(): Cancelling: "
1826 "No player for peer_id="<<peer_id
1831 PlayerSAO *playersao = player->getPlayerSAO();
1832 if(playersao == NULL){
1833 errorstream<<"Server::ProcessData(): Cancelling: "
1834 "No player object for peer_id="<<peer_id
1839 if(command == TOSERVER_PLAYERPOS)
1841 if(datasize < 2+12+12+4+4)
1845 v3s32 ps = readV3S32(&data[start+2]);
1846 v3s32 ss = readV3S32(&data[start+2+12]);
1847 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1848 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1850 if(datasize >= 2+12+12+4+4+4)
1851 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1852 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1853 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1854 pitch = wrapDegrees(pitch);
1855 yaw = wrapDegrees(yaw);
1857 player->setPosition(position);
1858 player->setSpeed(speed);
1859 player->setPitch(pitch);
1860 player->setYaw(yaw);
1861 player->keyPressed=keyPressed;
1862 player->control.up = (bool)(keyPressed&1);
1863 player->control.down = (bool)(keyPressed&2);
1864 player->control.left = (bool)(keyPressed&4);
1865 player->control.right = (bool)(keyPressed&8);
1866 player->control.jump = (bool)(keyPressed&16);
1867 player->control.aux1 = (bool)(keyPressed&32);
1868 player->control.sneak = (bool)(keyPressed&64);
1869 player->control.LMB = (bool)(keyPressed&128);
1870 player->control.RMB = (bool)(keyPressed&256);
1872 bool cheated = playersao->checkMovementCheat();
1875 m_script->on_cheat(playersao, "moved_too_fast");
1878 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1879 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1880 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1882 else if(command == TOSERVER_DELETEDBLOCKS)
1895 u16 count = data[2];
1896 for(u16 i=0; i<count; i++)
1898 if((s16)datasize < 2+1+(i+1)*6)
1899 throw con::InvalidIncomingDataException
1900 ("DELETEDBLOCKS length is too short");
1901 v3s16 p = readV3S16(&data[2+1+i*6]);
1902 /*infostream<<"Server: DELETEDBLOCKS ("
1903 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1904 RemoteClient *client = getClient(peer_id);
1905 client->SetBlockNotSent(p);
1908 else if(command == TOSERVER_CLICK_OBJECT)
1910 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1913 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1915 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1918 else if(command == TOSERVER_GROUND_ACTION)
1920 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1924 else if(command == TOSERVER_RELEASE)
1926 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1929 else if(command == TOSERVER_SIGNTEXT)
1931 infostream<<"Server: SIGNTEXT not supported anymore"
1935 else if(command == TOSERVER_SIGNNODETEXT)
1937 infostream<<"Server: SIGNNODETEXT not supported anymore"
1941 else if(command == TOSERVER_INVENTORY_ACTION)
1943 // Strip command and create a stream
1944 std::string datastring((char*)&data[2], datasize-2);
1945 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1946 std::istringstream is(datastring, std::ios_base::binary);
1948 InventoryAction *a = InventoryAction::deSerialize(is);
1951 infostream<<"TOSERVER_INVENTORY_ACTION: "
1952 <<"InventoryAction::deSerialize() returned NULL"
1957 // If something goes wrong, this player is to blame
1958 RollbackScopeActor rollback_scope(m_rollback,
1959 std::string("player:")+player->getName());
1962 Note: Always set inventory not sent, to repair cases
1963 where the client made a bad prediction.
1967 Handle restrictions and special cases of the move action
1969 if(a->getType() == IACTION_MOVE)
1971 IMoveAction *ma = (IMoveAction*)a;
1973 ma->from_inv.applyCurrentPlayer(player->getName());
1974 ma->to_inv.applyCurrentPlayer(player->getName());
1976 setInventoryModified(ma->from_inv);
1977 setInventoryModified(ma->to_inv);
1979 bool from_inv_is_current_player =
1980 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1981 (ma->from_inv.name == player->getName());
1983 bool to_inv_is_current_player =
1984 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1985 (ma->to_inv.name == player->getName());
1988 Disable moving items out of craftpreview
1990 if(ma->from_list == "craftpreview")
1992 infostream<<"Ignoring IMoveAction from "
1993 <<(ma->from_inv.dump())<<":"<<ma->from_list
1994 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1995 <<" because src is "<<ma->from_list<<std::endl;
2001 Disable moving items into craftresult and craftpreview
2003 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2005 infostream<<"Ignoring IMoveAction from "
2006 <<(ma->from_inv.dump())<<":"<<ma->from_list
2007 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2008 <<" because dst is "<<ma->to_list<<std::endl;
2013 // Disallow moving items in elsewhere than player's inventory
2014 // if not allowed to interact
2015 if(!checkPriv(player->getName(), "interact") &&
2016 (!from_inv_is_current_player ||
2017 !to_inv_is_current_player))
2019 infostream<<"Cannot move outside of player's inventory: "
2020 <<"No interact privilege"<<std::endl;
2026 Handle restrictions and special cases of the drop action
2028 else if(a->getType() == IACTION_DROP)
2030 IDropAction *da = (IDropAction*)a;
2032 da->from_inv.applyCurrentPlayer(player->getName());
2034 setInventoryModified(da->from_inv);
2037 Disable dropping items out of craftpreview
2039 if(da->from_list == "craftpreview")
2041 infostream<<"Ignoring IDropAction from "
2042 <<(da->from_inv.dump())<<":"<<da->from_list
2043 <<" because src is "<<da->from_list<<std::endl;
2048 // Disallow dropping items if not allowed to interact
2049 if(!checkPriv(player->getName(), "interact"))
2056 Handle restrictions and special cases of the craft action
2058 else if(a->getType() == IACTION_CRAFT)
2060 ICraftAction *ca = (ICraftAction*)a;
2062 ca->craft_inv.applyCurrentPlayer(player->getName());
2064 setInventoryModified(ca->craft_inv);
2066 //bool craft_inv_is_current_player =
2067 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2068 // (ca->craft_inv.name == player->getName());
2070 // Disallow crafting if not allowed to interact
2071 if(!checkPriv(player->getName(), "interact"))
2073 infostream<<"Cannot craft: "
2074 <<"No interact privilege"<<std::endl;
2081 a->apply(this, playersao, this);
2085 else if(command == TOSERVER_CHAT_MESSAGE)
2093 std::string datastring((char*)&data[2], datasize-2);
2094 std::istringstream is(datastring, std::ios_base::binary);
2097 is.read((char*)buf, 2);
2098 u16 len = readU16(buf);
2100 std::wstring message;
2101 for(u16 i=0; i<len; i++)
2103 is.read((char*)buf, 2);
2104 message += (wchar_t)readU16(buf);
2107 // If something goes wrong, this player is to blame
2108 RollbackScopeActor rollback_scope(m_rollback,
2109 std::string("player:")+player->getName());
2111 // Get player name of this client
2112 std::wstring name = narrow_to_wide(player->getName());
2115 bool ate = m_script->on_chat_message(player->getName(),
2116 wide_to_narrow(message));
2117 // If script ate the message, don't proceed
2121 // Line to send to players
2123 // Whether to send to the player that sent the line
2124 bool send_to_sender_only = false;
2126 // Commands are implemented in Lua, so only catch invalid
2127 // commands that were not "eaten" and send an error back
2128 if(message[0] == L'/')
2130 message = message.substr(1);
2131 send_to_sender_only = true;
2132 if(message.length() == 0)
2133 line += L"-!- Empty command";
2135 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2139 if(checkPriv(player->getName(), "shout")){
2145 line += L"-!- You don't have permission to shout.";
2146 send_to_sender_only = true;
2153 Send the message to sender
2155 if (send_to_sender_only)
2157 SendChatMessage(peer_id, line);
2160 Send the message to others
2164 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2166 std::list<u16> clients = m_clients.getClientIDs();
2168 for(std::list<u16>::iterator
2169 i = clients.begin();
2170 i != clients.end(); ++i)
2173 SendChatMessage(*i, line);
2178 else if(command == TOSERVER_DAMAGE)
2180 std::string datastring((char*)&data[2], datasize-2);
2181 std::istringstream is(datastring, std::ios_base::binary);
2182 u8 damage = readU8(is);
2184 if(g_settings->getBool("enable_damage"))
2186 actionstream<<player->getName()<<" damaged by "
2187 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2190 playersao->setHP(playersao->getHP() - damage);
2192 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2195 if(playersao->m_hp_not_sent)
2196 SendPlayerHP(peer_id);
2199 else if(command == TOSERVER_BREATH)
2201 std::string datastring((char*)&data[2], datasize-2);
2202 std::istringstream is(datastring, std::ios_base::binary);
2203 u16 breath = readU16(is);
2204 playersao->setBreath(breath);
2205 m_script->player_event(playersao,"breath_changed");
2207 else if(command == TOSERVER_PASSWORD)
2210 [0] u16 TOSERVER_PASSWORD
2211 [2] u8[28] old password
2212 [30] u8[28] new password
2215 if(datasize != 2+PASSWORD_SIZE*2)
2217 /*char password[PASSWORD_SIZE];
2218 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2219 password[i] = data[2+i];
2220 password[PASSWORD_SIZE-1] = 0;*/
2222 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2230 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2232 char c = data[2+PASSWORD_SIZE+i];
2238 if(!base64_is_valid(newpwd)){
2239 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2240 // Wrong old password supplied!!
2241 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2245 infostream<<"Server: Client requests a password change from "
2246 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2248 std::string playername = player->getName();
2250 std::string checkpwd;
2251 m_script->getAuth(playername, &checkpwd, NULL);
2253 if(oldpwd != checkpwd)
2255 infostream<<"Server: invalid old password"<<std::endl;
2256 // Wrong old password supplied!!
2257 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2261 bool success = m_script->setPassword(playername, newpwd);
2263 actionstream<<player->getName()<<" changes password"<<std::endl;
2264 SendChatMessage(peer_id, L"Password change successful.");
2266 actionstream<<player->getName()<<" tries to change password but "
2267 <<"it fails"<<std::endl;
2268 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2271 else if(command == TOSERVER_PLAYERITEM)
2276 u16 item = readU16(&data[2]);
2277 playersao->setWieldIndex(item);
2279 else if(command == TOSERVER_RESPAWN)
2281 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2284 RespawnPlayer(peer_id);
2286 actionstream<<player->getName()<<" respawns at "
2287 <<PP(player->getPosition()/BS)<<std::endl;
2289 // ActiveObject is added to environment in AsyncRunStep after
2290 // the previous addition has been succesfully removed
2292 else if(command == TOSERVER_INTERACT)
2294 std::string datastring((char*)&data[2], datasize-2);
2295 std::istringstream is(datastring, std::ios_base::binary);
2301 [5] u32 length of the next item
2302 [9] serialized PointedThing
2304 0: start digging (from undersurface) or use
2305 1: stop digging (all parameters ignored)
2306 2: digging completed
2307 3: place block or item (to abovesurface)
2310 u8 action = readU8(is);
2311 u16 item_i = readU16(is);
2312 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2313 PointedThing pointed;
2314 pointed.deSerialize(tmp_is);
2316 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2317 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2321 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2322 <<" tried to interact, but is dead!"<<std::endl;
2326 v3f player_pos = playersao->getLastGoodPosition();
2328 // Update wielded item
2329 playersao->setWieldIndex(item_i);
2331 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2332 v3s16 p_under = pointed.node_undersurface;
2333 v3s16 p_above = pointed.node_abovesurface;
2335 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2336 ServerActiveObject *pointed_object = NULL;
2337 if(pointed.type == POINTEDTHING_OBJECT)
2339 pointed_object = m_env->getActiveObject(pointed.object_id);
2340 if(pointed_object == NULL)
2342 verbosestream<<"TOSERVER_INTERACT: "
2343 "pointed object is NULL"<<std::endl;
2349 v3f pointed_pos_under = player_pos;
2350 v3f pointed_pos_above = player_pos;
2351 if(pointed.type == POINTEDTHING_NODE)
2353 pointed_pos_under = intToFloat(p_under, BS);
2354 pointed_pos_above = intToFloat(p_above, BS);
2356 else if(pointed.type == POINTEDTHING_OBJECT)
2358 pointed_pos_under = pointed_object->getBasePosition();
2359 pointed_pos_above = pointed_pos_under;
2363 Check that target is reasonably close
2364 (only when digging or placing things)
2366 if(action == 0 || action == 2 || action == 3)
2368 float d = player_pos.getDistanceFrom(pointed_pos_under);
2369 float max_d = BS * 14; // Just some large enough value
2371 actionstream<<"Player "<<player->getName()
2372 <<" tried to access "<<pointed.dump()
2374 <<"d="<<d<<", max_d="<<max_d
2375 <<". ignoring."<<std::endl;
2376 // Re-send block to revert change on client-side
2377 RemoteClient *client = getClient(peer_id);
2378 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2379 client->SetBlockNotSent(blockpos);
2381 m_script->on_cheat(playersao, "interacted_too_far");
2388 Make sure the player is allowed to do it
2390 if(!checkPriv(player->getName(), "interact"))
2392 actionstream<<player->getName()<<" attempted to interact with "
2393 <<pointed.dump()<<" without 'interact' privilege"
2395 // Re-send block to revert change on client-side
2396 RemoteClient *client = getClient(peer_id);
2397 // Digging completed -> under
2399 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2400 client->SetBlockNotSent(blockpos);
2402 // Placement -> above
2404 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2405 client->SetBlockNotSent(blockpos);
2411 If something goes wrong, this player is to blame
2413 RollbackScopeActor rollback_scope(m_rollback,
2414 std::string("player:")+player->getName());
2417 0: start digging or punch object
2421 if(pointed.type == POINTEDTHING_NODE)
2424 NOTE: This can be used in the future to check if
2425 somebody is cheating, by checking the timing.
2427 MapNode n(CONTENT_IGNORE);
2430 n = m_env->getMap().getNode(p_under);
2432 catch(InvalidPositionException &e)
2434 infostream<<"Server: Not punching: Node not found."
2435 <<" Adding block to emerge queue."
2437 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2439 if(n.getContent() != CONTENT_IGNORE)
2440 m_script->node_on_punch(p_under, n, playersao, pointed);
2442 playersao->noCheatDigStart(p_under);
2444 else if(pointed.type == POINTEDTHING_OBJECT)
2446 // Skip if object has been removed
2447 if(pointed_object->m_removed)
2450 actionstream<<player->getName()<<" punches object "
2451 <<pointed.object_id<<": "
2452 <<pointed_object->getDescription()<<std::endl;
2454 ItemStack punchitem = playersao->getWieldedItem();
2455 ToolCapabilities toolcap =
2456 punchitem.getToolCapabilities(m_itemdef);
2457 v3f dir = (pointed_object->getBasePosition() -
2458 (player->getPosition() + player->getEyeOffset())
2460 float time_from_last_punch =
2461 playersao->resetTimeFromLastPunch();
2462 pointed_object->punch(dir, &toolcap, playersao,
2463 time_from_last_punch);
2471 else if(action == 1)
2476 2: Digging completed
2478 else if(action == 2)
2480 // Only digging of nodes
2481 if(pointed.type == POINTEDTHING_NODE)
2483 MapNode n(CONTENT_IGNORE);
2486 n = m_env->getMap().getNode(p_under);
2488 catch(InvalidPositionException &e)
2490 infostream<<"Server: Not finishing digging: Node not found."
2491 <<" Adding block to emerge queue."
2493 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2496 /* Cheat prevention */
2497 bool is_valid_dig = true;
2498 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2500 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2501 float nocheat_t = playersao->getNoCheatDigTime();
2502 playersao->noCheatDigEnd();
2503 // If player didn't start digging this, ignore dig
2504 if(nocheat_p != p_under){
2505 infostream<<"Server: NoCheat: "<<player->getName()
2506 <<" started digging "
2507 <<PP(nocheat_p)<<" and completed digging "
2508 <<PP(p_under)<<"; not digging."<<std::endl;
2509 is_valid_dig = false;
2511 m_script->on_cheat(playersao, "finished_unknown_dig");
2513 // Get player's wielded item
2514 ItemStack playeritem;
2515 InventoryList *mlist = playersao->getInventory()->getList("main");
2517 playeritem = mlist->getItem(playersao->getWieldIndex());
2518 ToolCapabilities playeritem_toolcap =
2519 playeritem.getToolCapabilities(m_itemdef);
2520 // Get diggability and expected digging time
2521 DigParams params = getDigParams(m_nodedef->get(n).groups,
2522 &playeritem_toolcap);
2523 // If can't dig, try hand
2524 if(!params.diggable){
2525 const ItemDefinition &hand = m_itemdef->get("");
2526 const ToolCapabilities *tp = hand.tool_capabilities;
2528 params = getDigParams(m_nodedef->get(n).groups, tp);
2530 // If can't dig, ignore dig
2531 if(!params.diggable){
2532 infostream<<"Server: NoCheat: "<<player->getName()
2533 <<" completed digging "<<PP(p_under)
2534 <<", which is not diggable with tool. not digging."
2536 is_valid_dig = false;
2538 m_script->on_cheat(playersao, "dug_unbreakable");
2540 // Check digging time
2541 // If already invalidated, we don't have to
2543 // Well not our problem then
2545 // Clean and long dig
2546 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2547 // All is good, but grab time from pool; don't care if
2548 // it's actually available
2549 playersao->getDigPool().grab(params.time);
2551 // Short or laggy dig
2552 // Try getting the time from pool
2553 else if(playersao->getDigPool().grab(params.time)){
2558 infostream<<"Server: NoCheat: "<<player->getName()
2559 <<" completed digging "<<PP(p_under)
2560 <<"too fast; not digging."<<std::endl;
2561 is_valid_dig = false;
2563 m_script->on_cheat(playersao, "dug_too_fast");
2567 /* Actually dig node */
2569 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2570 m_script->node_on_dig(p_under, n, playersao);
2572 // Send unusual result (that is, node not being removed)
2573 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2575 // Re-send block to revert change on client-side
2576 RemoteClient *client = getClient(peer_id);
2577 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2578 client->SetBlockNotSent(blockpos);
2584 3: place block or right-click object
2586 else if(action == 3)
2588 ItemStack item = playersao->getWieldedItem();
2590 // Reset build time counter
2591 if(pointed.type == POINTEDTHING_NODE &&
2592 item.getDefinition(m_itemdef).type == ITEM_NODE)
2593 getClient(peer_id)->m_time_from_building = 0.0;
2595 if(pointed.type == POINTEDTHING_OBJECT)
2597 // Right click object
2599 // Skip if object has been removed
2600 if(pointed_object->m_removed)
2603 actionstream<<player->getName()<<" right-clicks object "
2604 <<pointed.object_id<<": "
2605 <<pointed_object->getDescription()<<std::endl;
2608 pointed_object->rightClick(playersao);
2610 else if(m_script->item_OnPlace(
2611 item, playersao, pointed))
2613 // Placement was handled in lua
2615 // Apply returned ItemStack
2616 playersao->setWieldedItem(item);
2619 // If item has node placement prediction, always send the
2620 // blocks to make sure the client knows what exactly happened
2621 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2622 RemoteClient *client = getClient(peer_id);
2623 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2624 client->SetBlockNotSent(blockpos);
2625 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2626 if(blockpos2 != blockpos){
2627 client->SetBlockNotSent(blockpos2);
2635 else if(action == 4)
2637 ItemStack item = playersao->getWieldedItem();
2639 actionstream<<player->getName()<<" uses "<<item.name
2640 <<", pointing at "<<pointed.dump()<<std::endl;
2642 if(m_script->item_OnUse(
2643 item, playersao, pointed))
2645 // Apply returned ItemStack
2646 playersao->setWieldedItem(item);
2653 Catch invalid actions
2657 infostream<<"WARNING: Server: Invalid action "
2658 <<action<<std::endl;
2661 else if(command == TOSERVER_REMOVED_SOUNDS)
2663 std::string datastring((char*)&data[2], datasize-2);
2664 std::istringstream is(datastring, std::ios_base::binary);
2666 int num = readU16(is);
2667 for(int k=0; k<num; k++){
2668 s32 id = readS32(is);
2669 std::map<s32, ServerPlayingSound>::iterator i =
2670 m_playing_sounds.find(id);
2671 if(i == m_playing_sounds.end())
2673 ServerPlayingSound &psound = i->second;
2674 psound.clients.erase(peer_id);
2675 if(psound.clients.size() == 0)
2676 m_playing_sounds.erase(i++);
2679 else if(command == TOSERVER_NODEMETA_FIELDS)
2681 std::string datastring((char*)&data[2], datasize-2);
2682 std::istringstream is(datastring, std::ios_base::binary);
2684 v3s16 p = readV3S16(is);
2685 std::string formname = deSerializeString(is);
2686 int num = readU16(is);
2687 std::map<std::string, std::string> fields;
2688 for(int k=0; k<num; k++){
2689 std::string fieldname = deSerializeString(is);
2690 std::string fieldvalue = deSerializeLongString(is);
2691 fields[fieldname] = fieldvalue;
2694 // If something goes wrong, this player is to blame
2695 RollbackScopeActor rollback_scope(m_rollback,
2696 std::string("player:")+player->getName());
2698 // Check the target node for rollback data; leave others unnoticed
2699 RollbackNode rn_old(&m_env->getMap(), p, this);
2701 m_script->node_on_receive_fields(p, formname, fields,playersao);
2703 // Report rollback data
2704 RollbackNode rn_new(&m_env->getMap(), p, this);
2705 if(rollback() && rn_new != rn_old){
2706 RollbackAction action;
2707 action.setSetNode(p, rn_old, rn_new);
2708 rollback()->reportAction(action);
2711 else if(command == TOSERVER_INVENTORY_FIELDS)
2713 std::string datastring((char*)&data[2], datasize-2);
2714 std::istringstream is(datastring, std::ios_base::binary);
2716 std::string formname = deSerializeString(is);
2717 int num = readU16(is);
2718 std::map<std::string, std::string> fields;
2719 for(int k=0; k<num; k++){
2720 std::string fieldname = deSerializeString(is);
2721 std::string fieldvalue = deSerializeLongString(is);
2722 fields[fieldname] = fieldvalue;
2725 m_script->on_playerReceiveFields(playersao, formname, fields);
2729 infostream<<"Server::ProcessData(): Ignoring "
2730 "unknown command "<<command<<std::endl;
2734 catch(SendFailedException &e)
2736 errorstream<<"Server::ProcessData(): SendFailedException: "
2742 void Server::setTimeOfDay(u32 time)
2744 m_env->setTimeOfDay(time);
2745 m_time_of_day_send_timer = 0;
2748 void Server::onMapEditEvent(MapEditEvent *event)
2750 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2751 if(m_ignore_map_edit_events)
2753 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2755 MapEditEvent *e = event->clone();
2756 m_unsent_map_edit_queue.push_back(e);
2759 Inventory* Server::getInventory(const InventoryLocation &loc)
2762 case InventoryLocation::UNDEFINED:
2765 case InventoryLocation::CURRENT_PLAYER:
2768 case InventoryLocation::PLAYER:
2770 Player *player = m_env->getPlayer(loc.name.c_str());
2773 PlayerSAO *playersao = player->getPlayerSAO();
2776 return playersao->getInventory();
2779 case InventoryLocation::NODEMETA:
2781 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2784 return meta->getInventory();
2787 case InventoryLocation::DETACHED:
2789 if(m_detached_inventories.count(loc.name) == 0)
2791 return m_detached_inventories[loc.name];
2799 void Server::setInventoryModified(const InventoryLocation &loc)
2802 case InventoryLocation::UNDEFINED:
2805 case InventoryLocation::PLAYER:
2807 Player *player = m_env->getPlayer(loc.name.c_str());
2810 PlayerSAO *playersao = player->getPlayerSAO();
2813 playersao->m_inventory_not_sent = true;
2814 playersao->m_wielded_item_not_sent = true;
2817 case InventoryLocation::NODEMETA:
2819 v3s16 blockpos = getNodeBlockPos(loc.p);
2821 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2823 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2825 setBlockNotSent(blockpos);
2828 case InventoryLocation::DETACHED:
2830 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2838 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2840 std::list<u16> clients = m_clients.getClientIDs();
2842 // Set the modified blocks unsent for all the clients
2843 for (std::list<u16>::iterator
2844 i = clients.begin();
2845 i != clients.end(); ++i) {
2846 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2848 client->SetBlocksNotSent(block);
2853 void Server::peerAdded(con::Peer *peer)
2855 DSTACK(__FUNCTION_NAME);
2856 verbosestream<<"Server::peerAdded(): peer->id="
2857 <<peer->id<<std::endl;
2860 c.type = con::PEER_ADDED;
2861 c.peer_id = peer->id;
2863 m_peer_change_queue.push_back(c);
2866 void Server::deletingPeer(con::Peer *peer, bool timeout)
2868 DSTACK(__FUNCTION_NAME);
2869 verbosestream<<"Server::deletingPeer(): peer->id="
2870 <<peer->id<<", timeout="<<timeout<<std::endl;
2872 m_clients.event(peer->id,Disconnect);
2874 c.type = con::PEER_REMOVED;
2875 c.peer_id = peer->id;
2876 c.timeout = timeout;
2877 m_peer_change_queue.push_back(c);
2880 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2882 *retval = m_con.getPeerStat(peer_id,type);
2883 if (*retval == -1) return false;
2887 bool Server::getClientInfo(
2896 std::string* vers_string
2899 *state = m_clients.getClientState(peer_id);
2901 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2906 *uptime = client->uptime();
2907 *ser_vers = client->serialization_version;
2908 *prot_vers = client->net_proto_version;
2910 *major = client->getMajor();
2911 *minor = client->getMinor();
2912 *patch = client->getPatch();
2913 *vers_string = client->getPatch();
2920 void Server::handlePeerChanges()
2922 while(m_peer_change_queue.size() > 0)
2924 con::PeerChange c = m_peer_change_queue.pop_front();
2926 verbosestream<<"Server: Handling peer change: "
2927 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2932 case con::PEER_ADDED:
2933 m_clients.CreateClient(c.peer_id);
2936 case con::PEER_REMOVED:
2937 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2941 assert("Invalid peer change event received!" == 0);
2947 void Server::SendMovement(u16 peer_id)
2949 DSTACK(__FUNCTION_NAME);
2950 std::ostringstream os(std::ios_base::binary);
2952 writeU16(os, TOCLIENT_MOVEMENT);
2953 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2954 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2955 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2956 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2957 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2958 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2959 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2960 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2961 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2962 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2963 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2964 writeF1000(os, g_settings->getFloat("movement_gravity"));
2967 std::string s = os.str();
2968 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2970 m_clients.send(peer_id, 0, data, true);
2973 void Server::SendHP(u16 peer_id, u8 hp)
2975 DSTACK(__FUNCTION_NAME);
2976 std::ostringstream os(std::ios_base::binary);
2978 writeU16(os, TOCLIENT_HP);
2982 std::string s = os.str();
2983 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2985 m_clients.send(peer_id, 0, data, true);
2988 void Server::SendBreath(u16 peer_id, u16 breath)
2990 DSTACK(__FUNCTION_NAME);
2991 std::ostringstream os(std::ios_base::binary);
2993 writeU16(os, TOCLIENT_BREATH);
2994 writeU16(os, breath);
2997 std::string s = os.str();
2998 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3000 m_clients.send(peer_id, 0, data, true);
3003 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3005 DSTACK(__FUNCTION_NAME);
3006 std::ostringstream os(std::ios_base::binary);
3008 writeU16(os, TOCLIENT_ACCESS_DENIED);
3009 os<<serializeWideString(reason);
3012 std::string s = os.str();
3013 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3015 m_clients.send(peer_id, 0, data, true);
3018 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3019 v3f camera_point_target)
3021 DSTACK(__FUNCTION_NAME);
3022 std::ostringstream os(std::ios_base::binary);
3024 writeU16(os, TOCLIENT_DEATHSCREEN);
3025 writeU8(os, set_camera_point_target);
3026 writeV3F1000(os, camera_point_target);
3029 std::string s = os.str();
3030 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3032 m_clients.send(peer_id, 0, data, true);
3035 void Server::SendItemDef(u16 peer_id,
3036 IItemDefManager *itemdef, u16 protocol_version)
3038 DSTACK(__FUNCTION_NAME);
3039 std::ostringstream os(std::ios_base::binary);
3043 u32 length of the next item
3044 zlib-compressed serialized ItemDefManager
3046 writeU16(os, TOCLIENT_ITEMDEF);
3047 std::ostringstream tmp_os(std::ios::binary);
3048 itemdef->serialize(tmp_os, protocol_version);
3049 std::ostringstream tmp_os2(std::ios::binary);
3050 compressZlib(tmp_os.str(), tmp_os2);
3051 os<<serializeLongString(tmp_os2.str());
3054 std::string s = os.str();
3055 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3056 <<"): size="<<s.size()<<std::endl;
3057 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3059 m_clients.send(peer_id, 0, data, true);
3062 void Server::SendNodeDef(u16 peer_id,
3063 INodeDefManager *nodedef, u16 protocol_version)
3065 DSTACK(__FUNCTION_NAME);
3066 std::ostringstream os(std::ios_base::binary);
3070 u32 length of the next item
3071 zlib-compressed serialized NodeDefManager
3073 writeU16(os, TOCLIENT_NODEDEF);
3074 std::ostringstream tmp_os(std::ios::binary);
3075 nodedef->serialize(tmp_os, protocol_version);
3076 std::ostringstream tmp_os2(std::ios::binary);
3077 compressZlib(tmp_os.str(), tmp_os2);
3078 os<<serializeLongString(tmp_os2.str());
3081 std::string s = os.str();
3082 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3083 <<"): size="<<s.size()<<std::endl;
3084 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3086 m_clients.send(peer_id, 0, data, true);
3090 Non-static send methods
3093 void Server::SendInventory(u16 peer_id)
3095 DSTACK(__FUNCTION_NAME);
3097 PlayerSAO *playersao = getPlayerSAO(peer_id);
3100 playersao->m_inventory_not_sent = false;
3106 std::ostringstream os;
3107 playersao->getInventory()->serialize(os);
3109 std::string s = os.str();
3111 SharedBuffer<u8> data(s.size()+2);
3112 writeU16(&data[0], TOCLIENT_INVENTORY);
3113 memcpy(&data[2], s.c_str(), s.size());
3116 m_clients.send(peer_id, 0, data, true);
3119 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3121 DSTACK(__FUNCTION_NAME);
3123 std::ostringstream os(std::ios_base::binary);
3127 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3128 os.write((char*)buf, 2);
3131 writeU16(buf, message.size());
3132 os.write((char*)buf, 2);
3135 for(u32 i=0; i<message.size(); i++)
3139 os.write((char*)buf, 2);
3143 std::string s = os.str();
3144 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3146 if (peer_id != PEER_ID_INEXISTENT)
3149 m_clients.send(peer_id, 0, data, true);
3153 m_clients.sendToAll(0,data,true);
3157 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3158 const std::string &formname)
3160 DSTACK(__FUNCTION_NAME);
3162 std::ostringstream os(std::ios_base::binary);
3166 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3167 os.write((char*)buf, 2);
3168 os<<serializeLongString(formspec);
3169 os<<serializeString(formname);
3172 std::string s = os.str();
3173 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3175 m_clients.send(peer_id, 0, data, true);
3178 // Spawns a particle on peer with peer_id
3179 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3180 float expirationtime, float size, bool collisiondetection,
3181 bool vertical, std::string texture)
3183 DSTACK(__FUNCTION_NAME);
3185 std::ostringstream os(std::ios_base::binary);
3186 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3187 writeV3F1000(os, pos);
3188 writeV3F1000(os, velocity);
3189 writeV3F1000(os, acceleration);
3190 writeF1000(os, expirationtime);
3191 writeF1000(os, size);
3192 writeU8(os, collisiondetection);
3193 os<<serializeLongString(texture);
3194 writeU8(os, vertical);
3197 std::string s = os.str();
3198 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3200 if (peer_id != PEER_ID_INEXISTENT)
3203 m_clients.send(peer_id, 0, data, true);
3207 m_clients.sendToAll(0,data,true);
3211 // Adds a ParticleSpawner on peer with peer_id
3212 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3213 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3214 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3216 DSTACK(__FUNCTION_NAME);
3218 std::ostringstream os(std::ios_base::binary);
3219 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3221 writeU16(os, amount);
3222 writeF1000(os, spawntime);
3223 writeV3F1000(os, minpos);
3224 writeV3F1000(os, maxpos);
3225 writeV3F1000(os, minvel);
3226 writeV3F1000(os, maxvel);
3227 writeV3F1000(os, minacc);
3228 writeV3F1000(os, maxacc);
3229 writeF1000(os, minexptime);
3230 writeF1000(os, maxexptime);
3231 writeF1000(os, minsize);
3232 writeF1000(os, maxsize);
3233 writeU8(os, collisiondetection);
3234 os<<serializeLongString(texture);
3236 writeU8(os, vertical);
3239 std::string s = os.str();
3240 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3242 if (peer_id != PEER_ID_INEXISTENT)
3245 m_clients.send(peer_id, 0, data, true);
3248 m_clients.sendToAll(0,data,true);
3252 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3254 DSTACK(__FUNCTION_NAME);
3256 std::ostringstream os(std::ios_base::binary);
3257 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3262 std::string s = os.str();
3263 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3265 if (peer_id != PEER_ID_INEXISTENT) {
3267 m_clients.send(peer_id, 0, data, true);
3270 m_clients.sendToAll(0,data,true);
3275 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3277 std::ostringstream os(std::ios_base::binary);
3280 writeU16(os, TOCLIENT_HUDADD);
3282 writeU8(os, (u8)form->type);
3283 writeV2F1000(os, form->pos);
3284 os << serializeString(form->name);
3285 writeV2F1000(os, form->scale);
3286 os << serializeString(form->text);
3287 writeU32(os, form->number);
3288 writeU32(os, form->item);
3289 writeU32(os, form->dir);
3290 writeV2F1000(os, form->align);
3291 writeV2F1000(os, form->offset);
3292 writeV3F1000(os, form->world_pos);
3293 writeV2S32(os,form->size);
3296 std::string s = os.str();
3297 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3299 m_clients.send(peer_id, 1, data, true);
3302 void Server::SendHUDRemove(u16 peer_id, u32 id)
3304 std::ostringstream os(std::ios_base::binary);
3307 writeU16(os, TOCLIENT_HUDRM);
3311 std::string s = os.str();
3312 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3315 m_clients.send(peer_id, 1, data, true);
3318 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3320 std::ostringstream os(std::ios_base::binary);
3323 writeU16(os, TOCLIENT_HUDCHANGE);
3325 writeU8(os, (u8)stat);
3328 case HUD_STAT_SCALE:
3329 case HUD_STAT_ALIGN:
3330 case HUD_STAT_OFFSET:
3331 writeV2F1000(os, *(v2f *)value);
3335 os << serializeString(*(std::string *)value);
3337 case HUD_STAT_WORLD_POS:
3338 writeV3F1000(os, *(v3f *)value);
3341 writeV2S32(os,*(v2s32 *)value);
3343 case HUD_STAT_NUMBER:
3347 writeU32(os, *(u32 *)value);
3352 std::string s = os.str();
3353 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3355 m_clients.send(peer_id, 0, data, true);
3358 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3360 std::ostringstream os(std::ios_base::binary);
3363 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3364 writeU32(os, flags);
3368 std::string s = os.str();
3369 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3371 m_clients.send(peer_id, 0, data, true);
3374 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3376 std::ostringstream os(std::ios_base::binary);
3379 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3380 writeU16(os, param);
3381 os<<serializeString(value);
3384 std::string s = os.str();
3385 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3387 m_clients.send(peer_id, 0, data, true);
3390 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3391 const std::string &type, const std::vector<std::string> ¶ms)
3393 std::ostringstream os(std::ios_base::binary);
3396 writeU16(os, TOCLIENT_SET_SKY);
3397 writeARGB8(os, bgcolor);
3398 os<<serializeString(type);
3399 writeU16(os, params.size());
3400 for(size_t i=0; i<params.size(); i++)
3401 os<<serializeString(params[i]);
3404 std::string s = os.str();
3405 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3407 m_clients.send(peer_id, 0, data, true);
3410 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3413 std::ostringstream os(std::ios_base::binary);
3416 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3417 writeU8(os, do_override);
3418 writeU16(os, ratio*65535);
3421 std::string s = os.str();
3422 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3424 m_clients.send(peer_id, 0, data, true);
3427 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3429 DSTACK(__FUNCTION_NAME);
3432 SharedBuffer<u8> data(2+2+4);
3433 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3434 writeU16(&data[2], time);
3435 writeF1000(&data[4], time_speed);
3437 if (peer_id == PEER_ID_INEXISTENT) {
3438 m_clients.sendToAll(0,data,true);
3442 m_clients.send(peer_id, 0, data, true);
3446 void Server::SendPlayerHP(u16 peer_id)
3448 DSTACK(__FUNCTION_NAME);
3449 PlayerSAO *playersao = getPlayerSAO(peer_id);
3451 playersao->m_hp_not_sent = false;
3452 SendHP(peer_id, playersao->getHP());
3453 m_script->player_event(playersao,"health_changed");
3455 // Send to other clients
3456 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3457 ActiveObjectMessage aom(playersao->getId(), true, str);
3458 playersao->m_messages_out.push_back(aom);
3461 void Server::SendPlayerBreath(u16 peer_id)
3463 DSTACK(__FUNCTION_NAME);
3464 PlayerSAO *playersao = getPlayerSAO(peer_id);
3466 playersao->m_breath_not_sent = false;
3467 m_script->player_event(playersao,"breath_changed");
3468 SendBreath(peer_id, playersao->getBreath());
3471 void Server::SendMovePlayer(u16 peer_id)
3473 DSTACK(__FUNCTION_NAME);
3474 Player *player = m_env->getPlayer(peer_id);
3477 std::ostringstream os(std::ios_base::binary);
3478 writeU16(os, TOCLIENT_MOVE_PLAYER);
3479 writeV3F1000(os, player->getPosition());
3480 writeF1000(os, player->getPitch());
3481 writeF1000(os, player->getYaw());
3484 v3f pos = player->getPosition();
3485 f32 pitch = player->getPitch();
3486 f32 yaw = player->getYaw();
3487 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3488 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3495 std::string s = os.str();
3496 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3498 m_clients.send(peer_id, 0, data, true);
3501 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3503 std::ostringstream os(std::ios_base::binary);
3505 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3506 writeV2S32(os, animation_frames[0]);
3507 writeV2S32(os, animation_frames[1]);
3508 writeV2S32(os, animation_frames[2]);
3509 writeV2S32(os, animation_frames[3]);
3510 writeF1000(os, animation_speed);
3513 std::string s = os.str();
3514 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3516 m_clients.send(peer_id, 0, data, true);
3519 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3521 std::ostringstream os(std::ios_base::binary);
3523 writeU16(os, TOCLIENT_EYE_OFFSET);
3524 writeV3F1000(os, first);
3525 writeV3F1000(os, third);
3528 std::string s = os.str();
3529 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3531 m_clients.send(peer_id, 0, data, true);
3533 void Server::SendPlayerPrivileges(u16 peer_id)
3535 Player *player = m_env->getPlayer(peer_id);
3537 if(player->peer_id == PEER_ID_INEXISTENT)
3540 std::set<std::string> privs;
3541 m_script->getAuth(player->getName(), NULL, &privs);
3543 std::ostringstream os(std::ios_base::binary);
3544 writeU16(os, TOCLIENT_PRIVILEGES);
3545 writeU16(os, privs.size());
3546 for(std::set<std::string>::const_iterator i = privs.begin();
3547 i != privs.end(); i++){
3548 os<<serializeString(*i);
3552 std::string s = os.str();
3553 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3555 m_clients.send(peer_id, 0, data, true);
3558 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3560 Player *player = m_env->getPlayer(peer_id);
3562 if(player->peer_id == PEER_ID_INEXISTENT)
3565 std::ostringstream os(std::ios_base::binary);
3566 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3567 os<<serializeLongString(player->inventory_formspec);
3570 std::string s = os.str();
3571 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3573 m_clients.send(peer_id, 0, data, true);
3576 s32 Server::playSound(const SimpleSoundSpec &spec,
3577 const ServerSoundParams ¶ms)
3579 // Find out initial position of sound
3580 bool pos_exists = false;
3581 v3f pos = params.getPos(m_env, &pos_exists);
3582 // If position is not found while it should be, cancel sound
3583 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3586 // Filter destination clients
3587 std::list<u16> dst_clients;
3588 if(params.to_player != "")
3590 Player *player = m_env->getPlayer(params.to_player.c_str());
3592 infostream<<"Server::playSound: Player \""<<params.to_player
3593 <<"\" not found"<<std::endl;
3596 if(player->peer_id == PEER_ID_INEXISTENT){
3597 infostream<<"Server::playSound: Player \""<<params.to_player
3598 <<"\" not connected"<<std::endl;
3601 dst_clients.push_back(player->peer_id);
3605 std::list<u16> clients = m_clients.getClientIDs();
3607 for(std::list<u16>::iterator
3608 i = clients.begin(); i != clients.end(); ++i)
3610 Player *player = m_env->getPlayer(*i);
3614 if(player->getPosition().getDistanceFrom(pos) >
3615 params.max_hear_distance)
3618 dst_clients.push_back(*i);
3621 if(dst_clients.size() == 0)
3625 s32 id = m_next_sound_id++;
3626 // The sound will exist as a reference in m_playing_sounds
3627 m_playing_sounds[id] = ServerPlayingSound();
3628 ServerPlayingSound &psound = m_playing_sounds[id];
3629 psound.params = params;
3630 for(std::list<u16>::iterator i = dst_clients.begin();
3631 i != dst_clients.end(); i++)
3632 psound.clients.insert(*i);
3634 std::ostringstream os(std::ios_base::binary);
3635 writeU16(os, TOCLIENT_PLAY_SOUND);
3637 os<<serializeString(spec.name);
3638 writeF1000(os, spec.gain * params.gain);
3639 writeU8(os, params.type);
3640 writeV3F1000(os, pos);
3641 writeU16(os, params.object);
3642 writeU8(os, params.loop);
3644 std::string s = os.str();
3645 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3647 for(std::list<u16>::iterator i = dst_clients.begin();
3648 i != dst_clients.end(); i++){
3650 m_clients.send(*i, 0, data, true);
3654 void Server::stopSound(s32 handle)
3656 // Get sound reference
3657 std::map<s32, ServerPlayingSound>::iterator i =
3658 m_playing_sounds.find(handle);
3659 if(i == m_playing_sounds.end())
3661 ServerPlayingSound &psound = i->second;
3663 std::ostringstream os(std::ios_base::binary);
3664 writeU16(os, TOCLIENT_STOP_SOUND);
3665 writeS32(os, handle);
3667 std::string s = os.str();
3668 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3670 for(std::set<u16>::iterator i = psound.clients.begin();
3671 i != psound.clients.end(); i++){
3673 m_clients.send(*i, 0, data, true);
3675 // Remove sound reference
3676 m_playing_sounds.erase(i);
3679 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3680 std::list<u16> *far_players, float far_d_nodes)
3682 float maxd = far_d_nodes*BS;
3683 v3f p_f = intToFloat(p, BS);
3687 SharedBuffer<u8> reply(replysize);
3688 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3689 writeS16(&reply[2], p.X);
3690 writeS16(&reply[4], p.Y);
3691 writeS16(&reply[6], p.Z);
3693 std::list<u16> clients = m_clients.getClientIDs();
3694 for(std::list<u16>::iterator
3695 i = clients.begin();
3696 i != clients.end(); ++i)
3701 Player *player = m_env->getPlayer(*i);
3704 // If player is far away, only set modified blocks not sent
3705 v3f player_pos = player->getPosition();
3706 if(player_pos.getDistanceFrom(p_f) > maxd)
3708 far_players->push_back(*i);
3715 m_clients.send(*i, 0, reply, true);
3719 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3720 std::list<u16> *far_players, float far_d_nodes,
3721 bool remove_metadata)
3723 float maxd = far_d_nodes*BS;
3724 v3f p_f = intToFloat(p, BS);
3726 std::list<u16> clients = m_clients.getClientIDs();
3727 for(std::list<u16>::iterator
3728 i = clients.begin();
3729 i != clients.end(); ++i)
3735 Player *player = m_env->getPlayer(*i);
3738 // If player is far away, only set modified blocks not sent
3739 v3f player_pos = player->getPosition();
3740 if(player_pos.getDistanceFrom(p_f) > maxd)
3742 far_players->push_back(*i);
3747 SharedBuffer<u8> reply(0);
3749 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3753 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3754 reply = SharedBuffer<u8>(replysize);
3755 writeU16(&reply[0], TOCLIENT_ADDNODE);
3756 writeS16(&reply[2], p.X);
3757 writeS16(&reply[4], p.Y);
3758 writeS16(&reply[6], p.Z);
3759 n.serialize(&reply[8], client->serialization_version);
3760 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3761 writeU8(&reply[index], remove_metadata ? 0 : 1);
3763 if (!remove_metadata) {
3764 if (client->net_proto_version <= 21) {
3765 // Old clients always clear metadata; fix it
3766 // by sending the full block again.
3767 client->SetBlockNotSent(p);
3774 if (reply.getSize() > 0)
3775 m_clients.send(*i, 0, reply, true);
3779 void Server::setBlockNotSent(v3s16 p)
3781 std::list<u16> clients = m_clients.getClientIDs();
3783 for(std::list<u16>::iterator
3784 i = clients.begin();
3785 i != clients.end(); ++i)
3787 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3788 client->SetBlockNotSent(p);
3793 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3795 DSTACK(__FUNCTION_NAME);
3797 v3s16 p = block->getPos();
3801 bool completely_air = true;
3802 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3803 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3804 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3806 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3808 completely_air = false;
3809 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3814 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3816 infostream<<"[completely air] ";
3817 infostream<<std::endl;
3821 Create a packet with the block in the right format
3824 std::ostringstream os(std::ios_base::binary);
3825 block->serialize(os, ver, false);
3826 block->serializeNetworkSpecific(os, net_proto_version);
3827 std::string s = os.str();
3828 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3830 u32 replysize = 8 + blockdata.getSize();
3831 SharedBuffer<u8> reply(replysize);
3832 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3833 writeS16(&reply[2], p.X);
3834 writeS16(&reply[4], p.Y);
3835 writeS16(&reply[6], p.Z);
3836 memcpy(&reply[8], *blockdata, blockdata.getSize());
3838 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3839 <<": \tpacket size: "<<replysize<<std::endl;*/
3844 m_clients.send(peer_id, 2, reply, true);
3847 void Server::SendBlocks(float dtime)
3849 DSTACK(__FUNCTION_NAME);
3851 JMutexAutoLock envlock(m_env_mutex);
3852 //TODO check if one big lock could be faster then multiple small ones
3854 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3856 std::vector<PrioritySortedBlockTransfer> queue;
3858 s32 total_sending = 0;
3861 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3863 std::list<u16> clients = m_clients.getClientIDs();
3866 for(std::list<u16>::iterator
3867 i = clients.begin();
3868 i != clients.end(); ++i)
3870 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3875 total_sending += client->SendingCount();
3876 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3882 // Lowest priority number comes first.
3883 // Lowest is most important.
3884 std::sort(queue.begin(), queue.end());
3887 for(u32 i=0; i<queue.size(); i++)
3889 //TODO: Calculate limit dynamically
3890 if(total_sending >= g_settings->getS32
3891 ("max_simultaneous_block_sends_server_total"))
3894 PrioritySortedBlockTransfer q = queue[i];
3896 MapBlock *block = NULL;
3899 block = m_env->getMap().getBlockNoCreate(q.pos);
3901 catch(InvalidPositionException &e)
3906 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3911 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3913 client->SentBlock(q.pos);
3919 void Server::fillMediaCache()
3921 DSTACK(__FUNCTION_NAME);
3923 infostream<<"Server: Calculating media file checksums"<<std::endl;
3925 // Collect all media file paths
3926 std::list<std::string> paths;
3927 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3928 i != m_mods.end(); i++){
3929 const ModSpec &mod = *i;
3930 paths.push_back(mod.path + DIR_DELIM + "textures");
3931 paths.push_back(mod.path + DIR_DELIM + "sounds");
3932 paths.push_back(mod.path + DIR_DELIM + "media");
3933 paths.push_back(mod.path + DIR_DELIM + "models");
3935 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3937 // Collect media file information from paths into cache
3938 for(std::list<std::string>::iterator i = paths.begin();
3939 i != paths.end(); i++)
3941 std::string mediapath = *i;
3942 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3943 for(u32 j=0; j<dirlist.size(); j++){
3944 if(dirlist[j].dir) // Ignode dirs
3946 std::string filename = dirlist[j].name;
3947 // If name contains illegal characters, ignore the file
3948 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3949 infostream<<"Server: ignoring illegal file name: \""
3950 <<filename<<"\""<<std::endl;
3953 // If name is not in a supported format, ignore it
3954 const char *supported_ext[] = {
3955 ".png", ".jpg", ".bmp", ".tga",
3956 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3958 ".x", ".b3d", ".md2", ".obj",
3961 if(removeStringEnd(filename, supported_ext) == ""){
3962 infostream<<"Server: ignoring unsupported file extension: \""
3963 <<filename<<"\""<<std::endl;
3966 // Ok, attempt to load the file and add to cache
3967 std::string filepath = mediapath + DIR_DELIM + filename;
3969 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3970 if(fis.good() == false){
3971 errorstream<<"Server::fillMediaCache(): Could not open \""
3972 <<filename<<"\" for reading"<<std::endl;
3975 std::ostringstream tmp_os(std::ios_base::binary);
3979 fis.read(buf, 1024);
3980 std::streamsize len = fis.gcount();
3981 tmp_os.write(buf, len);
3990 errorstream<<"Server::fillMediaCache(): Failed to read \""
3991 <<filename<<"\""<<std::endl;
3994 if(tmp_os.str().length() == 0){
3995 errorstream<<"Server::fillMediaCache(): Empty file \""
3996 <<filepath<<"\""<<std::endl;
4001 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4003 unsigned char *digest = sha1.getDigest();
4004 std::string sha1_base64 = base64_encode(digest, 20);
4005 std::string sha1_hex = hex_encode((char*)digest, 20);
4009 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4010 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4015 struct SendableMediaAnnouncement
4018 std::string sha1_digest;
4020 SendableMediaAnnouncement(const std::string &name_="",
4021 const std::string &sha1_digest_=""):
4023 sha1_digest(sha1_digest_)
4027 void Server::sendMediaAnnouncement(u16 peer_id)
4029 DSTACK(__FUNCTION_NAME);
4031 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4034 std::list<SendableMediaAnnouncement> file_announcements;
4036 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4037 i != m_media.end(); i++){
4039 file_announcements.push_back(
4040 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4044 std::ostringstream os(std::ios_base::binary);
4052 u16 length of sha1_digest
4057 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4058 writeU16(os, file_announcements.size());
4060 for(std::list<SendableMediaAnnouncement>::iterator
4061 j = file_announcements.begin();
4062 j != file_announcements.end(); ++j){
4063 os<<serializeString(j->name);
4064 os<<serializeString(j->sha1_digest);
4066 os<<serializeString(g_settings->get("remote_media"));
4069 std::string s = os.str();
4070 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4073 m_clients.send(peer_id, 0, data, true);
4076 struct SendableMedia
4082 SendableMedia(const std::string &name_="", const std::string &path_="",
4083 const std::string &data_=""):
4090 void Server::sendRequestedMedia(u16 peer_id,
4091 const std::list<std::string> &tosend)
4093 DSTACK(__FUNCTION_NAME);
4095 verbosestream<<"Server::sendRequestedMedia(): "
4096 <<"Sending files to client"<<std::endl;
4100 // Put 5kB in one bunch (this is not accurate)
4101 u32 bytes_per_bunch = 5000;
4103 std::vector< std::list<SendableMedia> > file_bunches;
4104 file_bunches.push_back(std::list<SendableMedia>());
4106 u32 file_size_bunch_total = 0;
4108 for(std::list<std::string>::const_iterator i = tosend.begin();
4109 i != tosend.end(); ++i)
4111 const std::string &name = *i;
4113 if(m_media.find(name) == m_media.end()){
4114 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4115 <<"unknown file \""<<(name)<<"\""<<std::endl;
4119 //TODO get path + name
4120 std::string tpath = m_media[name].path;
4123 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4124 if(fis.good() == false){
4125 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4126 <<tpath<<"\" for reading"<<std::endl;
4129 std::ostringstream tmp_os(std::ios_base::binary);
4133 fis.read(buf, 1024);
4134 std::streamsize len = fis.gcount();
4135 tmp_os.write(buf, len);
4136 file_size_bunch_total += len;
4145 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4146 <<name<<"\""<<std::endl;
4149 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4150 <<tname<<"\""<<std::endl;*/
4152 file_bunches[file_bunches.size()-1].push_back(
4153 SendableMedia(name, tpath, tmp_os.str()));
4155 // Start next bunch if got enough data
4156 if(file_size_bunch_total >= bytes_per_bunch){
4157 file_bunches.push_back(std::list<SendableMedia>());
4158 file_size_bunch_total = 0;
4163 /* Create and send packets */
4165 u32 num_bunches = file_bunches.size();
4166 for(u32 i=0; i<num_bunches; i++)
4168 std::ostringstream os(std::ios_base::binary);
4172 u16 total number of texture bunches
4173 u16 index of this bunch
4174 u32 number of files in this bunch
4183 writeU16(os, TOCLIENT_MEDIA);
4184 writeU16(os, num_bunches);
4186 writeU32(os, file_bunches[i].size());
4188 for(std::list<SendableMedia>::iterator
4189 j = file_bunches[i].begin();
4190 j != file_bunches[i].end(); ++j){
4191 os<<serializeString(j->name);
4192 os<<serializeLongString(j->data);
4196 std::string s = os.str();
4197 verbosestream<<"Server::sendRequestedMedia(): bunch "
4198 <<i<<"/"<<num_bunches
4199 <<" files="<<file_bunches[i].size()
4200 <<" size=" <<s.size()<<std::endl;
4201 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4203 m_clients.send(peer_id, 2, data, true);
4207 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4209 if(m_detached_inventories.count(name) == 0){
4210 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4213 Inventory *inv = m_detached_inventories[name];
4215 std::ostringstream os(std::ios_base::binary);
4216 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4217 os<<serializeString(name);
4221 std::string s = os.str();
4222 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4224 if (peer_id != PEER_ID_INEXISTENT)
4227 m_clients.send(peer_id, 0, data, true);
4231 m_clients.sendToAll(0,data,true);
4235 void Server::sendDetachedInventories(u16 peer_id)
4237 DSTACK(__FUNCTION_NAME);
4239 for(std::map<std::string, Inventory*>::iterator
4240 i = m_detached_inventories.begin();
4241 i != m_detached_inventories.end(); i++){
4242 const std::string &name = i->first;
4243 //Inventory *inv = i->second;
4244 sendDetachedInventory(name, peer_id);
4252 void Server::DiePlayer(u16 peer_id)
4254 DSTACK(__FUNCTION_NAME);
4256 PlayerSAO *playersao = getPlayerSAO(peer_id);
4259 infostream<<"Server::DiePlayer(): Player "
4260 <<playersao->getPlayer()->getName()
4261 <<" dies"<<std::endl;
4263 playersao->setHP(0);
4265 // Trigger scripted stuff
4266 m_script->on_dieplayer(playersao);
4268 SendPlayerHP(peer_id);
4269 SendDeathscreen(peer_id, false, v3f(0,0,0));
4272 void Server::RespawnPlayer(u16 peer_id)
4274 DSTACK(__FUNCTION_NAME);
4276 PlayerSAO *playersao = getPlayerSAO(peer_id);
4279 infostream<<"Server::RespawnPlayer(): Player "
4280 <<playersao->getPlayer()->getName()
4281 <<" respawns"<<std::endl;
4283 playersao->setHP(PLAYER_MAX_HP);
4285 bool repositioned = m_script->on_respawnplayer(playersao);
4287 v3f pos = findSpawnPos(m_env->getServerMap());
4288 playersao->setPos(pos);
4292 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4294 DSTACK(__FUNCTION_NAME);
4296 SendAccessDenied(peer_id, reason);
4297 m_clients.event(peer_id,SetDenied);
4298 m_con.DisconnectPeer(peer_id);
4301 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4303 DSTACK(__FUNCTION_NAME);
4304 std::wstring message;
4307 Clear references to playing sounds
4309 for(std::map<s32, ServerPlayingSound>::iterator
4310 i = m_playing_sounds.begin();
4311 i != m_playing_sounds.end();)
4313 ServerPlayingSound &psound = i->second;
4314 psound.clients.erase(peer_id);
4315 if(psound.clients.size() == 0)
4316 m_playing_sounds.erase(i++);
4321 Player *player = m_env->getPlayer(peer_id);
4323 // Collect information about leaving in chat
4325 if(player != NULL && reason != CDR_DENY)
4327 std::wstring name = narrow_to_wide(player->getName());
4330 message += L" left the game.";
4331 if(reason == CDR_TIMEOUT)
4332 message += L" (timed out)";
4336 /* Run scripts and remove from environment */
4340 PlayerSAO *playersao = player->getPlayerSAO();
4343 m_script->on_leaveplayer(playersao);
4345 playersao->disconnected();
4353 if(player != NULL && reason != CDR_DENY)
4355 std::ostringstream os(std::ios_base::binary);
4356 std::list<u16> clients = m_clients.getClientIDs();
4358 for(std::list<u16>::iterator
4359 i = clients.begin();
4360 i != clients.end(); ++i)
4363 Player *player = m_env->getPlayer(*i);
4366 // Get name of player
4367 os<<player->getName()<<" ";
4370 actionstream<<player->getName()<<" "
4371 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4372 <<" List of players: "<<os.str()<<std::endl;
4376 JMutexAutoLock env_lock(m_env_mutex);
4377 m_clients.DeleteClient(peer_id);
4381 // Send leave chat message to all remaining clients
4382 if(message.length() != 0)
4383 SendChatMessage(PEER_ID_INEXISTENT,message);
4386 void Server::UpdateCrafting(u16 peer_id)
4388 DSTACK(__FUNCTION_NAME);
4390 Player* player = m_env->getPlayer(peer_id);
4393 // Get a preview for crafting
4395 InventoryLocation loc;
4396 loc.setPlayer(player->getName());
4397 getCraftingResult(&player->inventory, preview, false, this);
4398 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4400 // Put the new preview in
4401 InventoryList *plist = player->inventory.getList("craftpreview");
4403 assert(plist->getSize() >= 1);
4404 plist->changeItem(0, preview);
4407 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4409 RemoteClient *client = getClientNoEx(peer_id,state_min);
4411 throw ClientNotFoundException("Client not found");
4415 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4417 return m_clients.getClientNoEx(peer_id, state_min);
4420 std::string Server::getPlayerName(u16 peer_id)
4422 Player *player = m_env->getPlayer(peer_id);
4424 return "[id="+itos(peer_id)+"]";
4425 return player->getName();
4428 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4430 Player *player = m_env->getPlayer(peer_id);
4433 return player->getPlayerSAO();
4436 std::wstring Server::getStatusString()
4438 std::wostringstream os(std::ios_base::binary);
4441 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4443 os<<L", uptime="<<m_uptime.get();
4445 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4446 // Information about clients
4449 std::list<u16> clients = m_clients.getClientIDs();
4450 for(std::list<u16>::iterator i = clients.begin();
4451 i != clients.end(); ++i)
4454 Player *player = m_env->getPlayer(*i);
4455 // Get name of player
4456 std::wstring name = L"unknown";
4458 name = narrow_to_wide(player->getName());
4459 // Add name to information string
4467 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4468 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4469 if(g_settings->get("motd") != "")
4470 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4474 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4476 std::set<std::string> privs;
4477 m_script->getAuth(name, NULL, &privs);
4481 bool Server::checkPriv(const std::string &name, const std::string &priv)
4483 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4484 return (privs.count(priv) != 0);
4487 void Server::reportPrivsModified(const std::string &name)
4490 std::list<u16> clients = m_clients.getClientIDs();
4491 for(std::list<u16>::iterator
4492 i = clients.begin();
4493 i != clients.end(); ++i){
4494 Player *player = m_env->getPlayer(*i);
4495 reportPrivsModified(player->getName());
4498 Player *player = m_env->getPlayer(name.c_str());
4501 SendPlayerPrivileges(player->peer_id);
4502 PlayerSAO *sao = player->getPlayerSAO();
4505 sao->updatePrivileges(
4506 getPlayerEffectivePrivs(name),
4511 void Server::reportInventoryFormspecModified(const std::string &name)
4513 Player *player = m_env->getPlayer(name.c_str());
4516 SendPlayerInventoryFormspec(player->peer_id);
4519 void Server::setIpBanned(const std::string &ip, const std::string &name)
4521 m_banmanager->add(ip, name);
4524 void Server::unsetIpBanned(const std::string &ip_or_name)
4526 m_banmanager->remove(ip_or_name);
4529 std::string Server::getBanDescription(const std::string &ip_or_name)
4531 return m_banmanager->getBanDescription(ip_or_name);
4534 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4536 Player *player = m_env->getPlayer(name);
4540 if (player->peer_id == PEER_ID_INEXISTENT)
4543 SendChatMessage(player->peer_id, msg);
4546 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4548 Player *player = m_env->getPlayer(playername);
4552 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4556 SendShowFormspecMessage(player->peer_id, formspec, formname);
4560 u32 Server::hudAdd(Player *player, HudElement *form) {
4564 u32 id = player->getFreeHudID();
4565 if (id < player->hud.size())
4566 player->hud[id] = form;
4568 player->hud.push_back(form);
4570 SendHUDAdd(player->peer_id, id, form);
4574 bool Server::hudRemove(Player *player, u32 id) {
4575 if (!player || id >= player->hud.size() || !player->hud[id])
4578 delete player->hud[id];
4579 player->hud[id] = NULL;
4581 SendHUDRemove(player->peer_id, id);
4585 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4589 SendHUDChange(player->peer_id, id, stat, data);
4593 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4597 SendHUDSetFlags(player->peer_id, flags, mask);
4599 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4603 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4606 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4609 std::ostringstream os(std::ios::binary);
4610 writeS32(os, hotbar_itemcount);
4611 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4615 void Server::hudSetHotbarImage(Player *player, std::string name) {
4619 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4622 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4626 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4629 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4634 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4638 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4643 SendEyeOffset(player->peer_id, first, third);
4647 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4648 const std::string &type, const std::vector<std::string> ¶ms)
4653 SendSetSky(player->peer_id, bgcolor, type, params);
4657 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4663 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4667 void Server::notifyPlayers(const std::wstring &msg)
4669 SendChatMessage(PEER_ID_INEXISTENT,msg);
4672 void Server::spawnParticle(const char *playername, v3f pos,
4673 v3f velocity, v3f acceleration,
4674 float expirationtime, float size, bool
4675 collisiondetection, bool vertical, std::string texture)
4677 Player *player = m_env->getPlayer(playername);
4680 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4681 expirationtime, size, collisiondetection, vertical, texture);
4684 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4685 float expirationtime, float size,
4686 bool collisiondetection, bool vertical, std::string texture)
4688 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4689 expirationtime, size, collisiondetection, vertical, texture);
4692 u32 Server::addParticleSpawner(const char *playername,
4693 u16 amount, float spawntime,
4694 v3f minpos, v3f maxpos,
4695 v3f minvel, v3f maxvel,
4696 v3f minacc, v3f maxacc,
4697 float minexptime, float maxexptime,
4698 float minsize, float maxsize,
4699 bool collisiondetection, bool vertical, std::string texture)
4701 Player *player = m_env->getPlayer(playername);
4706 for(;;) // look for unused particlespawner id
4709 if (std::find(m_particlespawner_ids.begin(),
4710 m_particlespawner_ids.end(), id)
4711 == m_particlespawner_ids.end())
4713 m_particlespawner_ids.push_back(id);
4718 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4719 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4720 minexptime, maxexptime, minsize, maxsize,
4721 collisiondetection, vertical, texture, id);
4726 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4727 v3f minpos, v3f maxpos,
4728 v3f minvel, v3f maxvel,
4729 v3f minacc, v3f maxacc,
4730 float minexptime, float maxexptime,
4731 float minsize, float maxsize,
4732 bool collisiondetection, bool vertical, std::string texture)
4735 for(;;) // look for unused particlespawner id
4738 if (std::find(m_particlespawner_ids.begin(),
4739 m_particlespawner_ids.end(), id)
4740 == m_particlespawner_ids.end())
4742 m_particlespawner_ids.push_back(id);
4747 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4748 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4749 minexptime, maxexptime, minsize, maxsize,
4750 collisiondetection, vertical, texture, id);
4755 void Server::deleteParticleSpawner(const char *playername, u32 id)
4757 Player *player = m_env->getPlayer(playername);
4761 m_particlespawner_ids.erase(
4762 std::remove(m_particlespawner_ids.begin(),
4763 m_particlespawner_ids.end(), id),
4764 m_particlespawner_ids.end());
4765 SendDeleteParticleSpawner(player->peer_id, id);
4768 void Server::deleteParticleSpawnerAll(u32 id)
4770 m_particlespawner_ids.erase(
4771 std::remove(m_particlespawner_ids.begin(),
4772 m_particlespawner_ids.end(), id),
4773 m_particlespawner_ids.end());
4774 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4777 Inventory* Server::createDetachedInventory(const std::string &name)
4779 if(m_detached_inventories.count(name) > 0){
4780 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4781 delete m_detached_inventories[name];
4783 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4785 Inventory *inv = new Inventory(m_itemdef);
4787 m_detached_inventories[name] = inv;
4788 //TODO find a better way to do this
4789 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4796 BoolScopeSet(bool *dst, bool val):
4799 m_orig_state = *m_dst;
4804 *m_dst = m_orig_state;
4811 // actions: time-reversed list
4812 // Return value: success/failure
4813 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4814 std::list<std::string> *log)
4816 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4817 ServerMap *map = (ServerMap*)(&m_env->getMap());
4818 // Disable rollback report sink while reverting
4819 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4821 // Fail if no actions to handle
4822 if(actions.empty()){
4823 log->push_back("Nothing to do.");
4830 for(std::list<RollbackAction>::const_iterator
4831 i = actions.begin();
4832 i != actions.end(); i++)
4834 const RollbackAction &action = *i;
4836 bool success = action.applyRevert(map, this, this);
4839 std::ostringstream os;
4840 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4841 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4843 log->push_back(os.str());
4845 std::ostringstream os;
4846 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4847 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4849 log->push_back(os.str());
4853 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4854 <<" failed"<<std::endl;
4856 // Call it done if less than half failed
4857 return num_failed <= num_tried/2;
4860 // IGameDef interface
4862 IItemDefManager* Server::getItemDefManager()
4866 INodeDefManager* Server::getNodeDefManager()
4870 ICraftDefManager* Server::getCraftDefManager()
4874 ITextureSource* Server::getTextureSource()
4878 IShaderSource* Server::getShaderSource()
4882 u16 Server::allocateUnknownNodeId(const std::string &name)
4884 return m_nodedef->allocateDummy(name);
4886 ISoundManager* Server::getSoundManager()
4888 return &dummySoundManager;
4890 MtEventManager* Server::getEventManager()
4894 IRollbackReportSink* Server::getRollbackReportSink()
4896 if(!m_enable_rollback_recording)
4898 if(!m_rollback_sink_enabled)
4903 IWritableItemDefManager* Server::getWritableItemDefManager()
4907 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4911 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4916 const ModSpec* Server::getModSpec(const std::string &modname)
4918 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4919 i != m_mods.end(); i++){
4920 const ModSpec &mod = *i;
4921 if(mod.name == modname)
4926 void Server::getModNames(std::list<std::string> &modlist)
4928 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4930 modlist.push_back(i->name);
4933 std::string Server::getBuiltinLuaPath()
4935 return porting::path_share + DIR_DELIM + "builtin";
4938 v3f findSpawnPos(ServerMap &map)
4940 //return v3f(50,50,50)*BS;
4945 nodepos = v2s16(0,0);
4950 s16 water_level = map.getWaterLevel();
4952 // Try to find a good place a few times
4953 for(s32 i=0; i<1000; i++)
4956 // We're going to try to throw the player to this position
4957 v2s16 nodepos2d = v2s16(
4958 -range + (myrand() % (range * 2)),
4959 -range + (myrand() % (range * 2)));
4961 // Get ground height at point
4962 s16 groundheight = map.findGroundLevel(nodepos2d);
4963 if (groundheight <= water_level) // Don't go underwater
4965 if (groundheight > water_level + 6) // Don't go to high places
4968 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4969 bool is_good = false;
4971 for (s32 i = 0; i < 10; i++) {
4972 v3s16 blockpos = getNodeBlockPos(nodepos);
4973 map.emergeBlock(blockpos, true);
4974 content_t c = map.getNodeNoEx(nodepos).getContent();
4975 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4977 if (air_count >= 2){
4985 // Found a good place
4986 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4992 return intToFloat(nodepos, BS);
4995 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4997 RemotePlayer *player = NULL;
4998 bool newplayer = false;
5001 Try to get an existing player
5003 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5005 // If player is already connected, cancel
5006 if(player != NULL && player->peer_id != 0)
5008 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5013 If player with the wanted peer_id already exists, cancel.
5015 if(m_env->getPlayer(peer_id) != NULL)
5017 infostream<<"emergePlayer(): Player with wrong name but same"
5018 " peer_id already exists"<<std::endl;
5023 Create a new player if it doesn't exist yet
5028 player = new RemotePlayer(this);
5029 player->updateName(name);
5031 /* Set player position */
5032 infostream<<"Server: Finding spawn place for player \""
5033 <<name<<"\""<<std::endl;
5034 v3f pos = findSpawnPos(m_env->getServerMap());
5035 player->setPosition(pos);
5037 /* Add player to environment */
5038 m_env->addPlayer(player);
5042 Create a new player active object
5044 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5045 getPlayerEffectivePrivs(player->getName()),
5048 /* Clean up old HUD elements from previous sessions */
5049 player->hud.clear();
5051 /* Add object to environment */
5052 m_env->addActiveObject(playersao);
5056 m_script->on_newplayer(playersao);
5061 void dedicated_server_loop(Server &server, bool &kill)
5063 DSTACK(__FUNCTION_NAME);
5065 verbosestream<<"dedicated_server_loop()"<<std::endl;
5067 IntervalLimiter m_profiler_interval;
5071 float steplen = g_settings->getFloat("dedicated_server_step");
5072 // This is kind of a hack but can be done like this
5073 // because server.step() is very light
5075 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5076 sleep_ms((int)(steplen*1000.0));
5078 server.step(steplen);
5080 if(server.getShutdownRequested() || kill)
5082 infostream<<"Dedicated server quitting"<<std::endl;
5084 if(g_settings->getBool("server_announce") == true)
5085 ServerList::sendAnnounce("delete");
5093 float profiler_print_interval =
5094 g_settings->getFloat("profiler_print_interval");
5095 if(profiler_print_interval != 0)
5097 if(m_profiler_interval.step(steplen, profiler_print_interval))
5099 infostream<<"Profiler:"<<std::endl;
5100 g_profiler->print(infostream);
5101 g_profiler->clear();