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_enable_rollback_recording(false),
187 m_itemdef(createItemDefManager()),
188 m_nodedef(createNodeDefManager()),
189 m_craftdef(createCraftDefManager()),
190 m_event(new EventManager()),
192 m_time_of_day_send_timer(0),
195 m_shutdown_requested(false),
196 m_ignore_map_edit_events(false),
197 m_ignore_map_edit_events_peer_id(0)
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 // Create rollback manager
247 m_rollback = new RollbackManager(m_path_world, this);
249 ModConfiguration modconf(m_path_world);
250 m_mods = modconf.getMods();
251 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
252 // complain about mods with unsatisfied dependencies
253 if(!modconf.isConsistent())
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
259 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
260 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
261 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
262 errorstream << " \"" << *dep_it << "\"";
263 errorstream << std::endl;
267 Settings worldmt_settings;
268 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
269 worldmt_settings.readConfigFile(worldmt.c_str());
270 std::vector<std::string> names = worldmt_settings.getNames();
271 std::set<std::string> load_mod_names;
272 for(std::vector<std::string>::iterator it = names.begin();
273 it != names.end(); ++it)
275 std::string name = *it;
276 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
277 load_mod_names.insert(name.substr(9));
279 // complain about mods declared to be loaded, but not found
280 for(std::vector<ModSpec>::iterator it = m_mods.begin();
281 it != m_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
284 it != unsatisfied_mods.end(); ++it)
285 load_mod_names.erase((*it).name);
286 if(!load_mod_names.empty())
288 errorstream << "The following mods could not be found:";
289 for(std::set<std::string>::iterator it = load_mod_names.begin();
290 it != load_mod_names.end(); ++it)
291 errorstream << " \"" << (*it) << "\"";
292 errorstream << std::endl;
296 JMutexAutoLock envlock(m_env_mutex);
298 // Load mapgen params from Settings
299 m_emerge->loadMapgenParams();
301 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
302 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
304 // Initialize scripting
305 infostream<<"Server: Initializing Lua"<<std::endl;
307 m_script = new GameScripting(this);
309 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
311 if (!m_script->loadScript(scriptpath))
312 throw ModError("Failed to load and run " + scriptpath);
315 infostream<<"Server: Loading mods: ";
316 for(std::vector<ModSpec>::iterator i = m_mods.begin();
317 i != m_mods.end(); i++){
318 const ModSpec &mod = *i;
319 infostream<<mod.name<<" ";
321 infostream<<std::endl;
322 // Load and run "mod" scripts
323 for(std::vector<ModSpec>::iterator i = m_mods.begin();
324 i != m_mods.end(); i++){
325 const ModSpec &mod = *i;
326 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
327 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
328 <<scriptpath<<"\"]"<<std::endl;
329 bool success = m_script->loadMod(scriptpath, mod.name);
331 errorstream<<"Server: Failed to load and run "
332 <<scriptpath<<std::endl;
333 throw ModError("Failed to load and run "+scriptpath);
337 // Read Textures and calculate sha1 sums
340 // Apply item aliases in the node definition manager
341 m_nodedef->updateAliases(m_itemdef);
343 m_nodedef->setNodeRegistrationStatus(true);
345 // Perform pending node name resolutions
346 m_nodedef->runNodeResolverCallbacks();
348 // Initialize Environment
349 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
351 m_clients.setEnv(m_env);
353 // Initialize mapgens
354 m_emerge->initMapgens();
356 // Give environment reference to scripting api
357 m_script->initializeEnvironment(m_env);
359 // Register us to receive map edit events
360 servermap->addEventReceiver(this);
362 // If file exists, load environment metadata
363 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
365 infostream<<"Server: Loading environment metadata"<<std::endl;
369 // Add some test ActiveBlockModifiers to environment
370 add_legacy_abms(m_env, m_nodedef);
372 m_liquid_transform_every = g_settings->getFloat("liquid_update");
377 infostream<<"Server destructing"<<std::endl;
379 // Send shutdown message
380 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
383 JMutexAutoLock envlock(m_env_mutex);
385 // Execute script shutdown hooks
386 m_script->on_shutdown();
388 infostream<<"Server: Saving players"<<std::endl;
389 m_env->saveLoadedPlayers();
391 infostream<<"Server: Saving environment metadata"<<std::endl;
399 // stop all emerge threads before deleting players that may have
400 // requested blocks to be emerged
401 m_emerge->stopThreads();
403 // Delete things in the reverse order of creation
406 // N.B. the EmergeManager should be deleted after the Environment since Map
407 // depends on EmergeManager to write its current params to the map meta
416 // Deinitialize scripting
417 infostream<<"Server: Deinitializing scripting"<<std::endl;
420 // Delete detached inventories
421 for (std::map<std::string, Inventory*>::iterator
422 i = m_detached_inventories.begin();
423 i != m_detached_inventories.end(); i++) {
428 void Server::start(Address bind_addr)
430 DSTACK(__FUNCTION_NAME);
431 infostream<<"Starting server on "
432 << bind_addr.serializeString() <<"..."<<std::endl;
434 // Stop thread if already running
437 // Initialize connection
438 m_con.SetTimeoutMs(30);
439 m_con.Serve(bind_addr);
444 // ASCII art for the win!
446 <<" .__ __ __ "<<std::endl
447 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
448 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
449 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
450 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
451 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
452 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
453 actionstream<<"Server for gameid=\""<<m_gamespec.id
454 <<"\" listening on "<<bind_addr.serializeString()<<":"
455 <<bind_addr.getPort() << "."<<std::endl;
460 DSTACK(__FUNCTION_NAME);
462 infostream<<"Server: Stopping and waiting threads"<<std::endl;
464 // Stop threads (set run=false first so both start stopping)
466 //m_emergethread.setRun(false);
468 //m_emergethread.stop();
470 infostream<<"Server: Threads stopped"<<std::endl;
473 void Server::step(float dtime)
475 DSTACK(__FUNCTION_NAME);
480 JMutexAutoLock lock(m_step_dtime_mutex);
481 m_step_dtime += dtime;
483 // Throw if fatal error occurred in thread
484 std::string async_err = m_async_fatal_error.get();
486 throw ServerError(async_err);
490 void Server::AsyncRunStep(bool initial_step)
492 DSTACK(__FUNCTION_NAME);
494 g_profiler->add("Server::AsyncRunStep (num)", 1);
498 JMutexAutoLock lock1(m_step_dtime_mutex);
499 dtime = m_step_dtime;
503 // Send blocks to clients
507 if((dtime < 0.001) && (initial_step == false))
510 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
512 //infostream<<"Server steps "<<dtime<<std::endl;
513 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
516 JMutexAutoLock lock1(m_step_dtime_mutex);
517 m_step_dtime -= dtime;
524 m_uptime.set(m_uptime.get() + dtime);
530 Update time of day and overall game time
533 JMutexAutoLock envlock(m_env_mutex);
535 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
538 Send to clients at constant intervals
541 m_time_of_day_send_timer -= dtime;
542 if(m_time_of_day_send_timer < 0.0)
544 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
545 u16 time = m_env->getTimeOfDay();
546 float time_speed = g_settings->getFloat("time_speed");
547 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
552 JMutexAutoLock lock(m_env_mutex);
553 // Figure out and report maximum lag to environment
554 float max_lag = m_env->getMaxLagEstimate();
555 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
557 if(dtime > 0.1 && dtime > max_lag * 2.0)
558 infostream<<"Server: Maximum lag peaked to "<<dtime
562 m_env->reportMaxLagEstimate(max_lag);
564 ScopeProfiler sp(g_profiler, "SEnv step");
565 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
569 static const float map_timer_and_unload_dtime = 2.92;
570 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
572 JMutexAutoLock lock(m_env_mutex);
573 // Run Map's timers and unload unused data
574 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
575 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
576 g_settings->getFloat("server_unload_unused_data_timeout"));
587 JMutexAutoLock lock(m_env_mutex);
589 std::list<u16> clientids = m_clients.getClientIDs();
591 ScopeProfiler sp(g_profiler, "Server: handle players");
593 for(std::list<u16>::iterator
594 i = clientids.begin();
595 i != clientids.end(); ++i)
597 PlayerSAO *playersao = getPlayerSAO(*i);
598 if(playersao == NULL)
602 Handle player HPs (die if hp=0)
604 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
606 if(playersao->getHP() == 0)
613 Send player breath if changed
615 if(playersao->m_breath_not_sent) {
616 SendPlayerBreath(*i);
620 Send player inventories if necessary
622 if(playersao->m_moved){
624 playersao->m_moved = false;
626 if(playersao->m_inventory_not_sent){
633 /* Transform liquids */
634 m_liquid_transform_timer += dtime;
635 if(m_liquid_transform_timer >= m_liquid_transform_every)
637 m_liquid_transform_timer -= m_liquid_transform_every;
639 JMutexAutoLock lock(m_env_mutex);
641 ScopeProfiler sp(g_profiler, "Server: liquid transform");
643 std::map<v3s16, MapBlock*> modified_blocks;
644 m_env->getMap().transformLiquids(modified_blocks);
649 core::map<v3s16, MapBlock*> lighting_modified_blocks;
650 ServerMap &map = ((ServerMap&)m_env->getMap());
651 map.updateLighting(modified_blocks, lighting_modified_blocks);
653 // Add blocks modified by lighting to modified_blocks
654 for(core::map<v3s16, MapBlock*>::Iterator
655 i = lighting_modified_blocks.getIterator();
656 i.atEnd() == false; i++)
658 MapBlock *block = i.getNode()->getValue();
659 modified_blocks.insert(block->getPos(), block);
663 Set the modified blocks unsent for all the clients
665 if(!modified_blocks.empty())
667 SetBlocksNotSent(modified_blocks);
670 m_clients.step(dtime);
672 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
674 // send masterserver announce
676 float &counter = m_masterserver_timer;
677 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
678 g_settings->getBool("server_announce"))
680 ServerList::sendAnnounce(counter ? "update" : "start",
681 m_clients.getPlayerNames(),
683 m_env->getGameTime(),
686 m_emerge->params.mg_name,
695 Check added and deleted active objects
698 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
699 JMutexAutoLock envlock(m_env_mutex);
702 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
703 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
705 // Radius inside which objects are active
706 s16 radius = g_settings->getS16("active_object_send_range_blocks");
707 s16 player_radius = g_settings->getS16("player_transfer_distance");
709 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
710 !g_settings->getBool("unlimited_player_transfer_distance"))
711 player_radius = radius;
713 radius *= MAP_BLOCKSIZE;
714 player_radius *= MAP_BLOCKSIZE;
716 for(std::map<u16, RemoteClient*>::iterator
718 i != clients.end(); ++i)
720 RemoteClient *client = i->second;
722 // If definitions and textures have not been sent, don't
723 // send objects either
724 if (client->getState() < CS_DefinitionsSent)
727 Player *player = m_env->getPlayer(client->peer_id);
730 // This can happen if the client timeouts somehow
731 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
733 <<" has no associated player"<<std::endl;*/
736 v3s16 pos = floatToInt(player->getPosition(), BS);
738 std::set<u16> removed_objects;
739 std::set<u16> added_objects;
740 m_env->getRemovedActiveObjects(pos, radius, player_radius,
741 client->m_known_objects, removed_objects);
742 m_env->getAddedActiveObjects(pos, radius, player_radius,
743 client->m_known_objects, added_objects);
745 // Ignore if nothing happened
746 if(removed_objects.empty() && added_objects.empty())
748 //infostream<<"active objects: none changed"<<std::endl;
752 std::string data_buffer;
756 // Handle removed objects
757 writeU16((u8*)buf, removed_objects.size());
758 data_buffer.append(buf, 2);
759 for(std::set<u16>::iterator
760 i = removed_objects.begin();
761 i != removed_objects.end(); ++i)
765 ServerActiveObject* obj = m_env->getActiveObject(id);
767 // Add to data buffer for sending
768 writeU16((u8*)buf, id);
769 data_buffer.append(buf, 2);
771 // Remove from known objects
772 client->m_known_objects.erase(id);
774 if(obj && obj->m_known_by_count > 0)
775 obj->m_known_by_count--;
778 // Handle added objects
779 writeU16((u8*)buf, added_objects.size());
780 data_buffer.append(buf, 2);
781 for(std::set<u16>::iterator
782 i = added_objects.begin();
783 i != added_objects.end(); ++i)
787 ServerActiveObject* obj = m_env->getActiveObject(id);
790 u8 type = ACTIVEOBJECT_TYPE_INVALID;
792 infostream<<"WARNING: "<<__FUNCTION_NAME
793 <<": NULL object"<<std::endl;
795 type = obj->getSendType();
797 // Add to data buffer for sending
798 writeU16((u8*)buf, id);
799 data_buffer.append(buf, 2);
800 writeU8((u8*)buf, type);
801 data_buffer.append(buf, 1);
804 data_buffer.append(serializeLongString(
805 obj->getClientInitializationData(client->net_proto_version)));
807 data_buffer.append(serializeLongString(""));
809 // Add to known objects
810 client->m_known_objects.insert(id);
813 obj->m_known_by_count++;
817 SharedBuffer<u8> reply(2 + data_buffer.size());
818 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
819 memcpy((char*)&reply[2], data_buffer.c_str(),
822 m_clients.send(client->peer_id, 0, reply, true);
824 verbosestream<<"Server: Sent object remove/add: "
825 <<removed_objects.size()<<" removed, "
826 <<added_objects.size()<<" added, "
827 <<"packet size is "<<reply.getSize()<<std::endl;
832 Collect a list of all the objects known by the clients
833 and report it back to the environment.
836 core::map<u16, bool> all_known_objects;
838 for(core::map<u16, RemoteClient*>::Iterator
839 i = m_clients.getIterator();
840 i.atEnd() == false; i++)
842 RemoteClient *client = i.getNode()->getValue();
843 // Go through all known objects of client
844 for(core::map<u16, bool>::Iterator
845 i = client->m_known_objects.getIterator();
846 i.atEnd()==false; i++)
848 u16 id = i.getNode()->getKey();
849 all_known_objects[id] = true;
853 m_env->setKnownActiveObjects(whatever);
862 JMutexAutoLock envlock(m_env_mutex);
863 ScopeProfiler sp(g_profiler, "Server: sending object messages");
866 // Value = data sent by object
867 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
869 // Get active object messages from environment
872 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
876 std::list<ActiveObjectMessage>* message_list = NULL;
877 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
878 n = buffered_messages.find(aom.id);
879 if(n == buffered_messages.end())
881 message_list = new std::list<ActiveObjectMessage>;
882 buffered_messages[aom.id] = message_list;
886 message_list = n->second;
888 message_list->push_back(aom);
892 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
893 // Route data to every client
894 for(std::map<u16, RemoteClient*>::iterator
896 i != clients.end(); ++i)
898 RemoteClient *client = i->second;
899 std::string reliable_data;
900 std::string unreliable_data;
901 // Go through all objects in message buffer
902 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
903 j = buffered_messages.begin();
904 j != buffered_messages.end(); ++j)
906 // If object is not known by client, skip it
908 if(client->m_known_objects.find(id) == client->m_known_objects.end())
910 // Get message list of object
911 std::list<ActiveObjectMessage>* list = j->second;
912 // Go through every message
913 for(std::list<ActiveObjectMessage>::iterator
914 k = list->begin(); k != list->end(); ++k)
916 // Compose the full new data with header
917 ActiveObjectMessage aom = *k;
918 std::string new_data;
921 writeU16((u8*)&buf[0], aom.id);
922 new_data.append(buf, 2);
924 new_data += serializeString(aom.datastring);
925 // Add data to buffer
927 reliable_data += new_data;
929 unreliable_data += new_data;
933 reliable_data and unreliable_data are now ready.
936 if(reliable_data.size() > 0)
938 SharedBuffer<u8> reply(2 + reliable_data.size());
939 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
940 memcpy((char*)&reply[2], reliable_data.c_str(),
941 reliable_data.size());
943 m_clients.send(client->peer_id, 0, reply, true);
945 if(unreliable_data.size() > 0)
947 SharedBuffer<u8> reply(2 + unreliable_data.size());
948 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
949 memcpy((char*)&reply[2], unreliable_data.c_str(),
950 unreliable_data.size());
951 // Send as unreliable
952 m_clients.send(client->peer_id, 1, reply, false);
955 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
957 infostream<<"Server: Size of object message data: "
958 <<"reliable: "<<reliable_data.size()
959 <<", unreliable: "<<unreliable_data.size()
965 // Clear buffered_messages
966 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
967 i = buffered_messages.begin();
968 i != buffered_messages.end(); ++i)
975 Send queued-for-sending map edit events.
978 // We will be accessing the environment
979 JMutexAutoLock lock(m_env_mutex);
981 // Don't send too many at a time
984 // Single change sending is disabled if queue size is not small
985 bool disable_single_change_sending = false;
986 if(m_unsent_map_edit_queue.size() >= 4)
987 disable_single_change_sending = true;
989 int event_count = m_unsent_map_edit_queue.size();
991 // We'll log the amount of each
994 while(m_unsent_map_edit_queue.size() != 0)
996 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
998 // Players far away from the change are stored here.
999 // Instead of sending the changes, MapBlocks are set not sent
1001 std::list<u16> far_players;
1003 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1005 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1006 prof.add("MEET_ADDNODE", 1);
1007 if(disable_single_change_sending)
1008 sendAddNode(event->p, event->n, event->already_known_by_peer,
1009 &far_players, 5, event->type == MEET_ADDNODE);
1011 sendAddNode(event->p, event->n, event->already_known_by_peer,
1012 &far_players, 30, event->type == MEET_ADDNODE);
1014 else if(event->type == MEET_REMOVENODE)
1016 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1017 prof.add("MEET_REMOVENODE", 1);
1018 if(disable_single_change_sending)
1019 sendRemoveNode(event->p, event->already_known_by_peer,
1022 sendRemoveNode(event->p, event->already_known_by_peer,
1025 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1027 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1028 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1029 setBlockNotSent(event->p);
1031 else if(event->type == MEET_OTHER)
1033 infostream<<"Server: MEET_OTHER"<<std::endl;
1034 prof.add("MEET_OTHER", 1);
1035 for(std::set<v3s16>::iterator
1036 i = event->modified_blocks.begin();
1037 i != event->modified_blocks.end(); ++i)
1039 setBlockNotSent(*i);
1044 prof.add("unknown", 1);
1045 infostream<<"WARNING: Server: Unknown MapEditEvent "
1046 <<((u32)event->type)<<std::endl;
1050 Set blocks not sent to far players
1052 if(!far_players.empty())
1054 // Convert list format to that wanted by SetBlocksNotSent
1055 std::map<v3s16, MapBlock*> modified_blocks2;
1056 for(std::set<v3s16>::iterator
1057 i = event->modified_blocks.begin();
1058 i != event->modified_blocks.end(); ++i)
1060 modified_blocks2[*i] =
1061 m_env->getMap().getBlockNoCreateNoEx(*i);
1063 // Set blocks not sent
1064 for(std::list<u16>::iterator
1065 i = far_players.begin();
1066 i != far_players.end(); ++i)
1069 RemoteClient *client = getClient(peer_id);
1072 client->SetBlocksNotSent(modified_blocks2);
1078 /*// Don't send too many at a time
1080 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1084 if(event_count >= 5){
1085 infostream<<"Server: MapEditEvents:"<<std::endl;
1086 prof.print(infostream);
1087 } else if(event_count != 0){
1088 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1089 prof.print(verbosestream);
1095 Trigger emergethread (it somehow gets to a non-triggered but
1096 bysy state sometimes)
1099 float &counter = m_emergethread_trigger_timer;
1105 m_emerge->startThreads();
1107 // Update m_enable_rollback_recording here too
1108 m_enable_rollback_recording =
1109 g_settings->getBool("enable_rollback_recording");
1113 // Save map, players and auth stuff
1115 float &counter = m_savemap_timer;
1117 if(counter >= g_settings->getFloat("server_map_save_interval"))
1120 JMutexAutoLock lock(m_env_mutex);
1122 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1125 if (m_banmanager->isModified()) {
1126 m_banmanager->save();
1129 // Save changed parts of map
1130 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1133 m_env->saveLoadedPlayers();
1135 // Save environment metadata
1141 void Server::Receive()
1143 DSTACK(__FUNCTION_NAME);
1144 SharedBuffer<u8> data;
1148 datasize = m_con.Receive(peer_id,data);
1149 ProcessData(*data, datasize, peer_id);
1151 catch(con::InvalidIncomingDataException &e)
1153 infostream<<"Server::Receive(): "
1154 "InvalidIncomingDataException: what()="
1155 <<e.what()<<std::endl;
1157 catch(SerializationError &e) {
1158 infostream<<"Server::Receive(): "
1159 "SerializationError: what()="
1160 <<e.what()<<std::endl;
1162 catch(ClientStateError &e)
1164 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1165 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1166 L"Try reconnecting or updating your client");
1168 catch(con::PeerNotFoundException &e)
1174 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1176 std::string playername = "";
1177 PlayerSAO *playersao = NULL;
1180 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1181 if (client != NULL) {
1182 playername = client->getName();
1183 playersao = emergePlayer(playername.c_str(), peer_id);
1185 } catch (std::exception &e) {
1191 RemotePlayer *player =
1192 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1194 // If failed, cancel
1195 if((playersao == NULL) || (player == NULL))
1197 if(player && player->peer_id != 0){
1198 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1199 <<" (player allocated to an another client)"<<std::endl;
1200 DenyAccess(peer_id, L"Another client is connected with this "
1201 L"name. If your client closed unexpectedly, try again in "
1204 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1206 DenyAccess(peer_id, L"Could not allocate player.");
1212 Send complete position information
1214 SendMovePlayer(peer_id);
1217 SendPlayerPrivileges(peer_id);
1219 // Send inventory formspec
1220 SendPlayerInventoryFormspec(peer_id);
1223 UpdateCrafting(peer_id);
1224 SendInventory(peer_id);
1227 if(g_settings->getBool("enable_damage"))
1228 SendPlayerHP(peer_id);
1231 SendPlayerBreath(peer_id);
1233 // Show death screen if necessary
1235 SendDeathscreen(peer_id, false, v3f(0,0,0));
1237 // Note things in chat if not in simple singleplayer mode
1238 if(!m_simple_singleplayer_mode)
1240 // Send information about server to player in chat
1241 SendChatMessage(peer_id, getStatusString());
1243 // Send information about joining in chat
1245 std::wstring name = L"unknown";
1246 Player *player = m_env->getPlayer(peer_id);
1248 name = narrow_to_wide(player->getName());
1250 std::wstring message;
1253 message += L" joined the game.";
1254 SendChatMessage(PEER_ID_INEXISTENT,message);
1257 Address addr = getPeerAddress(player->peer_id);
1258 std::string ip_str = addr.serializeString();
1259 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1264 std::vector<std::string> names = m_clients.getPlayerNames();
1266 actionstream<<player->getName() <<" joins game. List of players: ";
1268 for (std::vector<std::string>::iterator i = names.begin();
1269 i != names.end(); i++)
1271 actionstream << *i << " ";
1274 actionstream << player->getName() <<std::endl;
1279 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1281 DSTACK(__FUNCTION_NAME);
1282 // Environment is locked first.
1283 JMutexAutoLock envlock(m_env_mutex);
1285 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1289 Address address = getPeerAddress(peer_id);
1290 addr_s = address.serializeString();
1292 // drop player if is ip is banned
1293 if(m_banmanager->isIpBanned(addr_s)){
1294 std::string ban_name = m_banmanager->getBanName(addr_s);
1295 infostream<<"Server: A banned client tried to connect from "
1296 <<addr_s<<"; banned name was "
1297 <<ban_name<<std::endl;
1298 // This actually doesn't seem to transfer to the client
1299 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1300 +narrow_to_wide(ban_name));
1304 catch(con::PeerNotFoundException &e)
1307 * no peer for this packet found
1308 * most common reason is peer timeout, e.g. peer didn't
1309 * respond for some time, your server was overloaded or
1312 infostream<<"Server::ProcessData(): Cancelling: peer "
1313 <<peer_id<<" not found"<<std::endl;
1323 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1325 if(command == TOSERVER_INIT)
1327 // [0] u16 TOSERVER_INIT
1328 // [2] u8 SER_FMT_VER_HIGHEST_READ
1329 // [3] u8[20] player_name
1330 // [23] u8[28] password <--- can be sent without this, from old versions
1332 if(datasize < 2+1+PLAYERNAME_SIZE)
1335 RemoteClient* client = getClient(peer_id, CS_Created);
1337 // If net_proto_version is set, this client has already been handled
1338 if(client->getState() > CS_Created)
1340 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1341 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1345 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1346 <<peer_id<<")"<<std::endl;
1348 // Do not allow multiple players in simple singleplayer mode.
1349 // This isn't a perfect way to do it, but will suffice for now
1350 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1351 infostream<<"Server: Not allowing another client ("<<addr_s
1352 <<") to connect in simple singleplayer mode"<<std::endl;
1353 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1357 // First byte after command is maximum supported
1358 // serialization version
1359 u8 client_max = data[2];
1360 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1361 // Use the highest version supported by both
1362 int deployed = std::min(client_max, our_max);
1363 // If it's lower than the lowest supported, give up.
1364 if(deployed < SER_FMT_VER_LOWEST)
1365 deployed = SER_FMT_VER_INVALID;
1367 if(deployed == SER_FMT_VER_INVALID)
1369 actionstream<<"Server: A mismatched client tried to connect from "
1370 <<addr_s<<std::endl;
1371 infostream<<"Server: Cannot negotiate serialization version with "
1372 <<addr_s<<std::endl;
1373 DenyAccess(peer_id, std::wstring(
1374 L"Your client's version is not supported.\n"
1375 L"Server version is ")
1376 + narrow_to_wide(minetest_version_simple) + L"."
1381 client->setPendingSerializationVersion(deployed);
1384 Read and check network protocol version
1387 u16 min_net_proto_version = 0;
1388 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1389 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1391 // Use same version as minimum and maximum if maximum version field
1392 // doesn't exist (backwards compatibility)
1393 u16 max_net_proto_version = min_net_proto_version;
1394 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1395 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1397 // Start with client's maximum version
1398 u16 net_proto_version = max_net_proto_version;
1400 // Figure out a working version if it is possible at all
1401 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1402 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1404 // If maximum is larger than our maximum, go with our maximum
1405 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1406 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1407 // Else go with client's maximum
1409 net_proto_version = max_net_proto_version;
1412 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1413 <<min_net_proto_version<<", max: "<<max_net_proto_version
1414 <<", chosen: "<<net_proto_version<<std::endl;
1416 client->net_proto_version = net_proto_version;
1418 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1419 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1421 actionstream<<"Server: A mismatched client tried to connect from "
1422 <<addr_s<<std::endl;
1423 DenyAccess(peer_id, std::wstring(
1424 L"Your client's version is not supported.\n"
1425 L"Server version is ")
1426 + narrow_to_wide(minetest_version_simple) + L",\n"
1427 + L"server's PROTOCOL_VERSION is "
1428 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1430 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1431 + L", client's PROTOCOL_VERSION is "
1432 + narrow_to_wide(itos(min_net_proto_version))
1434 + narrow_to_wide(itos(max_net_proto_version))
1439 if(g_settings->getBool("strict_protocol_version_checking"))
1441 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1443 actionstream<<"Server: A mismatched (strict) client tried to "
1444 <<"connect from "<<addr_s<<std::endl;
1445 DenyAccess(peer_id, std::wstring(
1446 L"Your client's version is not supported.\n"
1447 L"Server version is ")
1448 + narrow_to_wide(minetest_version_simple) + L",\n"
1449 + L"server's PROTOCOL_VERSION (strict) is "
1450 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1451 + L", client's PROTOCOL_VERSION is "
1452 + narrow_to_wide(itos(min_net_proto_version))
1454 + narrow_to_wide(itos(max_net_proto_version))
1463 char playername[PLAYERNAME_SIZE];
1464 unsigned int playername_length = 0;
1465 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1466 playername[playername_length] = data[3+playername_length];
1467 if (data[3+playername_length] == 0)
1471 if (playername_length == PLAYERNAME_SIZE) {
1472 actionstream<<"Server: Player with name exceeding max length "
1473 <<"tried to connect from "<<addr_s<<std::endl;
1474 DenyAccess(peer_id, L"Name too long");
1479 if(playername[0]=='\0')
1481 actionstream<<"Server: Player with an empty name "
1482 <<"tried to connect from "<<addr_s<<std::endl;
1483 DenyAccess(peer_id, L"Empty name");
1487 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1489 actionstream<<"Server: Player with an invalid name "
1490 <<"tried to connect from "<<addr_s<<std::endl;
1491 DenyAccess(peer_id, L"Name contains unallowed characters");
1495 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1497 actionstream<<"Server: Player with the name \"singleplayer\" "
1498 <<"tried to connect from "<<addr_s<<std::endl;
1499 DenyAccess(peer_id, L"Name is not allowed");
1505 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1507 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1508 <<"tried to connect from "<<addr_s<<" "
1509 <<"but it was disallowed for the following reason: "
1510 <<reason<<std::endl;
1511 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1516 infostream<<"Server: New connection: \""<<playername<<"\" from "
1517 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1520 char given_password[PASSWORD_SIZE];
1521 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1523 // old version - assume blank password
1524 given_password[0] = 0;
1528 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1530 given_password[i] = data[23+i];
1532 given_password[PASSWORD_SIZE-1] = 0;
1535 if(!base64_is_valid(given_password)){
1536 actionstream<<"Server: "<<playername
1537 <<" supplied invalid password hash"<<std::endl;
1538 DenyAccess(peer_id, L"Invalid password hash");
1542 // Enforce user limit.
1543 // Don't enforce for users that have some admin right
1544 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1545 !checkPriv(playername, "server") &&
1546 !checkPriv(playername, "ban") &&
1547 !checkPriv(playername, "privs") &&
1548 !checkPriv(playername, "password") &&
1549 playername != g_settings->get("name"))
1551 actionstream<<"Server: "<<playername<<" tried to join, but there"
1552 <<" are already max_users="
1553 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1554 DenyAccess(peer_id, L"Too many users.");
1558 std::string checkpwd; // Password hash to check against
1559 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1561 // If no authentication info exists for user, create it
1563 if(!isSingleplayer() &&
1564 g_settings->getBool("disallow_empty_password") &&
1565 std::string(given_password) == ""){
1566 actionstream<<"Server: "<<playername
1567 <<" supplied empty password"<<std::endl;
1568 DenyAccess(peer_id, L"Empty passwords are "
1569 L"disallowed. Set a password and try again.");
1572 std::wstring raw_default_password =
1573 narrow_to_wide(g_settings->get("default_password"));
1574 std::string initial_password =
1575 translatePassword(playername, raw_default_password);
1577 // If default_password is empty, allow any initial password
1578 if (raw_default_password.length() == 0)
1579 initial_password = given_password;
1581 m_script->createAuth(playername, initial_password);
1584 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1587 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1588 <<" (auth handler does not work?)"<<std::endl;
1589 DenyAccess(peer_id, L"Not allowed to login");
1593 if(given_password != checkpwd){
1594 actionstream<<"Server: "<<playername<<" supplied wrong password"
1596 DenyAccess(peer_id, L"Wrong password");
1600 RemotePlayer *player =
1601 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1603 if(player && player->peer_id != 0){
1604 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1605 <<" (player allocated to an another client)"<<std::endl;
1606 DenyAccess(peer_id, L"Another client is connected with this "
1607 L"name. If your client closed unexpectedly, try again in "
1611 m_clients.setPlayerName(peer_id,playername);
1614 Answer with a TOCLIENT_INIT
1617 SharedBuffer<u8> reply(2+1+6+8+4);
1618 writeU16(&reply[0], TOCLIENT_INIT);
1619 writeU8(&reply[2], deployed);
1620 //send dummy pos for legacy reasons only
1621 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1622 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1623 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1626 m_clients.send(peer_id, 0, reply, true);
1627 m_clients.event(peer_id, CSE_Init);
1633 if(command == TOSERVER_INIT2)
1636 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1637 <<peer_id<<std::endl;
1639 m_clients.event(peer_id, CSE_GotInit2);
1640 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1643 ///// begin compatibility code
1644 PlayerSAO* playersao = NULL;
1645 if (protocol_version <= 22) {
1646 playersao = StageTwoClientInit(peer_id);
1648 if (playersao == NULL) {
1650 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1651 << peer_id << std::endl;
1655 ///// end compatibility code
1658 Send some initialization data
1661 infostream<<"Server: Sending content to "
1662 <<getPlayerName(peer_id)<<std::endl;
1664 // Send player movement settings
1665 SendMovement(peer_id);
1667 // Send item definitions
1668 SendItemDef(peer_id, m_itemdef, protocol_version);
1670 // Send node definitions
1671 SendNodeDef(peer_id, m_nodedef, protocol_version);
1673 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1675 // Send media announcement
1676 sendMediaAnnouncement(peer_id);
1678 // Send detached inventories
1679 sendDetachedInventories(peer_id);
1682 u16 time = m_env->getTimeOfDay();
1683 float time_speed = g_settings->getFloat("time_speed");
1684 SendTimeOfDay(peer_id, time, time_speed);
1686 ///// begin compatibility code
1687 if (protocol_version <= 22) {
1688 m_clients.event(peer_id, CSE_SetClientReady);
1689 m_script->on_joinplayer(playersao);
1691 ///// end compatibility code
1693 // Warnings about protocol version can be issued here
1694 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1696 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1697 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1703 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1704 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1706 if(peer_ser_ver == SER_FMT_VER_INVALID)
1708 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1709 " serialization format invalid or not initialized."
1710 " Skipping incoming command="<<command<<std::endl;
1714 /* Handle commands relate to client startup */
1715 if(command == TOSERVER_REQUEST_MEDIA) {
1716 std::string datastring((char*)&data[2], datasize-2);
1717 std::istringstream is(datastring, std::ios_base::binary);
1719 std::list<std::string> tosend;
1720 u16 numfiles = readU16(is);
1722 infostream<<"Sending "<<numfiles<<" files to "
1723 <<getPlayerName(peer_id)<<std::endl;
1724 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1726 for(int i = 0; i < numfiles; i++) {
1727 std::string name = deSerializeString(is);
1728 tosend.push_back(name);
1729 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1733 sendRequestedMedia(peer_id, tosend);
1736 else if(command == TOSERVER_RECEIVED_MEDIA) {
1739 else if(command == TOSERVER_CLIENT_READY) {
1740 // clients <= protocol version 22 did not send ready message,
1741 // they're already initialized
1742 if (peer_proto_ver <= 22) {
1743 infostream << "Client sent message not expected by a "
1744 << "client using protocol version <= 22,"
1745 << "disconnecing peer_id: " << peer_id << std::endl;
1746 m_con.DisconnectPeer(peer_id);
1750 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1752 if (playersao == NULL) {
1754 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1755 << peer_id << std::endl;
1756 m_con.DisconnectPeer(peer_id);
1761 if(datasize < 2+8) {
1763 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1764 << peer_id << std::endl;
1765 m_con.DisconnectPeer(peer_id);
1769 m_clients.setClientVersion(
1771 data[2], data[3], data[4],
1772 std::string((char*) &data[8],(u16) data[6]));
1774 m_clients.event(peer_id, CSE_SetClientReady);
1775 m_script->on_joinplayer(playersao);
1778 else if(command == TOSERVER_GOTBLOCKS)
1791 u16 count = data[2];
1792 for(u16 i=0; i<count; i++)
1794 if((s16)datasize < 2+1+(i+1)*6)
1795 throw con::InvalidIncomingDataException
1796 ("GOTBLOCKS length is too short");
1797 v3s16 p = readV3S16(&data[2+1+i*6]);
1798 /*infostream<<"Server: GOTBLOCKS ("
1799 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1800 RemoteClient *client = getClient(peer_id);
1801 client->GotBlock(p);
1806 if (m_clients.getClientState(peer_id) < CS_Active)
1808 if (command == TOSERVER_PLAYERPOS) return;
1810 errorstream<<"Got packet command: " << command << " for peer id "
1811 << peer_id << " but client isn't active yet. Dropping packet "
1816 Player *player = m_env->getPlayer(peer_id);
1817 if(player == NULL) {
1818 errorstream<<"Server::ProcessData(): Cancelling: "
1819 "No player for peer_id="<<peer_id
1820 << " disconnecting peer!" <<std::endl;
1821 m_con.DisconnectPeer(peer_id);
1825 PlayerSAO *playersao = player->getPlayerSAO();
1826 if(playersao == NULL) {
1827 errorstream<<"Server::ProcessData(): Cancelling: "
1828 "No player object for peer_id="<<peer_id
1829 << " disconnecting peer!" <<std::endl;
1830 m_con.DisconnectPeer(peer_id);
1834 if(command == TOSERVER_PLAYERPOS)
1836 if(datasize < 2+12+12+4+4)
1840 v3s32 ps = readV3S32(&data[start+2]);
1841 v3s32 ss = readV3S32(&data[start+2+12]);
1842 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1843 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1845 if(datasize >= 2+12+12+4+4+4)
1846 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1847 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1848 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1849 pitch = wrapDegrees(pitch);
1850 yaw = wrapDegrees(yaw);
1852 player->setPosition(position);
1853 player->setSpeed(speed);
1854 player->setPitch(pitch);
1855 player->setYaw(yaw);
1856 player->keyPressed=keyPressed;
1857 player->control.up = (bool)(keyPressed&1);
1858 player->control.down = (bool)(keyPressed&2);
1859 player->control.left = (bool)(keyPressed&4);
1860 player->control.right = (bool)(keyPressed&8);
1861 player->control.jump = (bool)(keyPressed&16);
1862 player->control.aux1 = (bool)(keyPressed&32);
1863 player->control.sneak = (bool)(keyPressed&64);
1864 player->control.LMB = (bool)(keyPressed&128);
1865 player->control.RMB = (bool)(keyPressed&256);
1867 bool cheated = playersao->checkMovementCheat();
1870 m_script->on_cheat(playersao, "moved_too_fast");
1873 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1874 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1875 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1877 else if(command == TOSERVER_DELETEDBLOCKS)
1890 u16 count = data[2];
1891 for(u16 i=0; i<count; i++)
1893 if((s16)datasize < 2+1+(i+1)*6)
1894 throw con::InvalidIncomingDataException
1895 ("DELETEDBLOCKS length is too short");
1896 v3s16 p = readV3S16(&data[2+1+i*6]);
1897 /*infostream<<"Server: DELETEDBLOCKS ("
1898 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1899 RemoteClient *client = getClient(peer_id);
1900 client->SetBlockNotSent(p);
1903 else if(command == TOSERVER_CLICK_OBJECT)
1905 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1908 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1910 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1913 else if(command == TOSERVER_GROUND_ACTION)
1915 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1919 else if(command == TOSERVER_RELEASE)
1921 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1924 else if(command == TOSERVER_SIGNTEXT)
1926 infostream<<"Server: SIGNTEXT not supported anymore"
1930 else if(command == TOSERVER_SIGNNODETEXT)
1932 infostream<<"Server: SIGNNODETEXT not supported anymore"
1936 else if(command == TOSERVER_INVENTORY_ACTION)
1938 // Strip command and create a stream
1939 std::string datastring((char*)&data[2], datasize-2);
1940 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1941 std::istringstream is(datastring, std::ios_base::binary);
1943 InventoryAction *a = InventoryAction::deSerialize(is);
1946 infostream<<"TOSERVER_INVENTORY_ACTION: "
1947 <<"InventoryAction::deSerialize() returned NULL"
1952 // If something goes wrong, this player is to blame
1953 RollbackScopeActor rollback_scope(m_rollback,
1954 std::string("player:")+player->getName());
1957 Note: Always set inventory not sent, to repair cases
1958 where the client made a bad prediction.
1962 Handle restrictions and special cases of the move action
1964 if(a->getType() == IACTION_MOVE)
1966 IMoveAction *ma = (IMoveAction*)a;
1968 ma->from_inv.applyCurrentPlayer(player->getName());
1969 ma->to_inv.applyCurrentPlayer(player->getName());
1971 setInventoryModified(ma->from_inv);
1972 setInventoryModified(ma->to_inv);
1974 bool from_inv_is_current_player =
1975 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1976 (ma->from_inv.name == player->getName());
1978 bool to_inv_is_current_player =
1979 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1980 (ma->to_inv.name == player->getName());
1983 Disable moving items out of craftpreview
1985 if(ma->from_list == "craftpreview")
1987 infostream<<"Ignoring IMoveAction from "
1988 <<(ma->from_inv.dump())<<":"<<ma->from_list
1989 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1990 <<" because src is "<<ma->from_list<<std::endl;
1996 Disable moving items into craftresult and craftpreview
1998 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2000 infostream<<"Ignoring IMoveAction from "
2001 <<(ma->from_inv.dump())<<":"<<ma->from_list
2002 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2003 <<" because dst is "<<ma->to_list<<std::endl;
2008 // Disallow moving items in elsewhere than player's inventory
2009 // if not allowed to interact
2010 if(!checkPriv(player->getName(), "interact") &&
2011 (!from_inv_is_current_player ||
2012 !to_inv_is_current_player))
2014 infostream<<"Cannot move outside of player's inventory: "
2015 <<"No interact privilege"<<std::endl;
2021 Handle restrictions and special cases of the drop action
2023 else if(a->getType() == IACTION_DROP)
2025 IDropAction *da = (IDropAction*)a;
2027 da->from_inv.applyCurrentPlayer(player->getName());
2029 setInventoryModified(da->from_inv);
2032 Disable dropping items out of craftpreview
2034 if(da->from_list == "craftpreview")
2036 infostream<<"Ignoring IDropAction from "
2037 <<(da->from_inv.dump())<<":"<<da->from_list
2038 <<" because src is "<<da->from_list<<std::endl;
2043 // Disallow dropping items if not allowed to interact
2044 if(!checkPriv(player->getName(), "interact"))
2051 Handle restrictions and special cases of the craft action
2053 else if(a->getType() == IACTION_CRAFT)
2055 ICraftAction *ca = (ICraftAction*)a;
2057 ca->craft_inv.applyCurrentPlayer(player->getName());
2059 setInventoryModified(ca->craft_inv);
2061 //bool craft_inv_is_current_player =
2062 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2063 // (ca->craft_inv.name == player->getName());
2065 // Disallow crafting if not allowed to interact
2066 if(!checkPriv(player->getName(), "interact"))
2068 infostream<<"Cannot craft: "
2069 <<"No interact privilege"<<std::endl;
2076 a->apply(this, playersao, this);
2080 else if(command == TOSERVER_CHAT_MESSAGE)
2088 std::string datastring((char*)&data[2], datasize-2);
2089 std::istringstream is(datastring, std::ios_base::binary);
2092 is.read((char*)buf, 2);
2093 u16 len = readU16(buf);
2095 std::wstring message;
2096 for(u16 i=0; i<len; i++)
2098 is.read((char*)buf, 2);
2099 message += (wchar_t)readU16(buf);
2102 // If something goes wrong, this player is to blame
2103 RollbackScopeActor rollback_scope(m_rollback,
2104 std::string("player:")+player->getName());
2106 // Get player name of this client
2107 std::wstring name = narrow_to_wide(player->getName());
2110 bool ate = m_script->on_chat_message(player->getName(),
2111 wide_to_narrow(message));
2112 // If script ate the message, don't proceed
2116 // Line to send to players
2118 // Whether to send to the player that sent the line
2119 bool send_to_sender_only = false;
2121 // Commands are implemented in Lua, so only catch invalid
2122 // commands that were not "eaten" and send an error back
2123 if(message[0] == L'/')
2125 message = message.substr(1);
2126 send_to_sender_only = true;
2127 if(message.length() == 0)
2128 line += L"-!- Empty command";
2130 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2134 if(checkPriv(player->getName(), "shout")){
2140 line += L"-!- You don't have permission to shout.";
2141 send_to_sender_only = true;
2148 Send the message to sender
2150 if (send_to_sender_only)
2152 SendChatMessage(peer_id, line);
2155 Send the message to others
2159 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2161 std::list<u16> clients = m_clients.getClientIDs();
2163 for(std::list<u16>::iterator
2164 i = clients.begin();
2165 i != clients.end(); ++i)
2168 SendChatMessage(*i, line);
2173 else if(command == TOSERVER_DAMAGE)
2175 std::string datastring((char*)&data[2], datasize-2);
2176 std::istringstream is(datastring, std::ios_base::binary);
2177 u8 damage = readU8(is);
2179 if(g_settings->getBool("enable_damage"))
2181 actionstream<<player->getName()<<" damaged by "
2182 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2185 playersao->setHP(playersao->getHP() - damage);
2187 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2190 if(playersao->m_hp_not_sent)
2191 SendPlayerHP(peer_id);
2194 else if(command == TOSERVER_BREATH)
2196 std::string datastring((char*)&data[2], datasize-2);
2197 std::istringstream is(datastring, std::ios_base::binary);
2198 u16 breath = readU16(is);
2199 playersao->setBreath(breath);
2200 m_script->player_event(playersao,"breath_changed");
2202 else if(command == TOSERVER_PASSWORD)
2205 [0] u16 TOSERVER_PASSWORD
2206 [2] u8[28] old password
2207 [30] u8[28] new password
2210 if(datasize != 2+PASSWORD_SIZE*2)
2212 /*char password[PASSWORD_SIZE];
2213 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2214 password[i] = data[2+i];
2215 password[PASSWORD_SIZE-1] = 0;*/
2217 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2225 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2227 char c = data[2+PASSWORD_SIZE+i];
2233 if(!base64_is_valid(newpwd)){
2234 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2235 // Wrong old password supplied!!
2236 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2240 infostream<<"Server: Client requests a password change from "
2241 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2243 std::string playername = player->getName();
2245 std::string checkpwd;
2246 m_script->getAuth(playername, &checkpwd, NULL);
2248 if(oldpwd != checkpwd)
2250 infostream<<"Server: invalid old password"<<std::endl;
2251 // Wrong old password supplied!!
2252 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2256 bool success = m_script->setPassword(playername, newpwd);
2258 actionstream<<player->getName()<<" changes password"<<std::endl;
2259 SendChatMessage(peer_id, L"Password change successful.");
2261 actionstream<<player->getName()<<" tries to change password but "
2262 <<"it fails"<<std::endl;
2263 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2266 else if(command == TOSERVER_PLAYERITEM)
2271 u16 item = readU16(&data[2]);
2272 playersao->setWieldIndex(item);
2274 else if(command == TOSERVER_RESPAWN)
2276 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2279 RespawnPlayer(peer_id);
2281 actionstream<<player->getName()<<" respawns at "
2282 <<PP(player->getPosition()/BS)<<std::endl;
2284 // ActiveObject is added to environment in AsyncRunStep after
2285 // the previous addition has been succesfully removed
2287 else if(command == TOSERVER_INTERACT)
2289 std::string datastring((char*)&data[2], datasize-2);
2290 std::istringstream is(datastring, std::ios_base::binary);
2296 [5] u32 length of the next item
2297 [9] serialized PointedThing
2299 0: start digging (from undersurface) or use
2300 1: stop digging (all parameters ignored)
2301 2: digging completed
2302 3: place block or item (to abovesurface)
2305 u8 action = readU8(is);
2306 u16 item_i = readU16(is);
2307 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2308 PointedThing pointed;
2309 pointed.deSerialize(tmp_is);
2311 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2312 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2316 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2317 <<" tried to interact, but is dead!"<<std::endl;
2321 v3f player_pos = playersao->getLastGoodPosition();
2323 // Update wielded item
2324 playersao->setWieldIndex(item_i);
2326 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2327 v3s16 p_under = pointed.node_undersurface;
2328 v3s16 p_above = pointed.node_abovesurface;
2330 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2331 ServerActiveObject *pointed_object = NULL;
2332 if(pointed.type == POINTEDTHING_OBJECT)
2334 pointed_object = m_env->getActiveObject(pointed.object_id);
2335 if(pointed_object == NULL)
2337 verbosestream<<"TOSERVER_INTERACT: "
2338 "pointed object is NULL"<<std::endl;
2344 v3f pointed_pos_under = player_pos;
2345 v3f pointed_pos_above = player_pos;
2346 if(pointed.type == POINTEDTHING_NODE)
2348 pointed_pos_under = intToFloat(p_under, BS);
2349 pointed_pos_above = intToFloat(p_above, BS);
2351 else if(pointed.type == POINTEDTHING_OBJECT)
2353 pointed_pos_under = pointed_object->getBasePosition();
2354 pointed_pos_above = pointed_pos_under;
2358 Check that target is reasonably close
2359 (only when digging or placing things)
2361 if(action == 0 || action == 2 || action == 3)
2363 float d = player_pos.getDistanceFrom(pointed_pos_under);
2364 float max_d = BS * 14; // Just some large enough value
2366 actionstream<<"Player "<<player->getName()
2367 <<" tried to access "<<pointed.dump()
2369 <<"d="<<d<<", max_d="<<max_d
2370 <<". ignoring."<<std::endl;
2371 // Re-send block to revert change on client-side
2372 RemoteClient *client = getClient(peer_id);
2373 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2374 client->SetBlockNotSent(blockpos);
2376 m_script->on_cheat(playersao, "interacted_too_far");
2383 Make sure the player is allowed to do it
2385 if(!checkPriv(player->getName(), "interact"))
2387 actionstream<<player->getName()<<" attempted to interact with "
2388 <<pointed.dump()<<" without 'interact' privilege"
2390 // Re-send block to revert change on client-side
2391 RemoteClient *client = getClient(peer_id);
2392 // Digging completed -> under
2394 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2395 client->SetBlockNotSent(blockpos);
2397 // Placement -> above
2399 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2400 client->SetBlockNotSent(blockpos);
2406 If something goes wrong, this player is to blame
2408 RollbackScopeActor rollback_scope(m_rollback,
2409 std::string("player:")+player->getName());
2412 0: start digging or punch object
2416 if(pointed.type == POINTEDTHING_NODE)
2419 NOTE: This can be used in the future to check if
2420 somebody is cheating, by checking the timing.
2422 MapNode n(CONTENT_IGNORE);
2424 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2426 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2429 infostream<<"Server: Not punching: Node not found."
2430 <<" Adding block to emerge queue."
2432 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2435 if(n.getContent() != CONTENT_IGNORE)
2436 m_script->node_on_punch(p_under, n, playersao, pointed);
2438 playersao->noCheatDigStart(p_under);
2440 else if(pointed.type == POINTEDTHING_OBJECT)
2442 // Skip if object has been removed
2443 if(pointed_object->m_removed)
2446 actionstream<<player->getName()<<" punches object "
2447 <<pointed.object_id<<": "
2448 <<pointed_object->getDescription()<<std::endl;
2450 ItemStack punchitem = playersao->getWieldedItem();
2451 ToolCapabilities toolcap =
2452 punchitem.getToolCapabilities(m_itemdef);
2453 v3f dir = (pointed_object->getBasePosition() -
2454 (player->getPosition() + player->getEyeOffset())
2456 float time_from_last_punch =
2457 playersao->resetTimeFromLastPunch();
2458 pointed_object->punch(dir, &toolcap, playersao,
2459 time_from_last_punch);
2467 else if(action == 1)
2472 2: Digging completed
2474 else if(action == 2)
2476 // Only digging of nodes
2477 if(pointed.type == POINTEDTHING_NODE)
2480 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2482 infostream << "Server: Not finishing digging: Node not found."
2483 << " Adding block to emerge queue."
2485 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2488 /* Cheat prevention */
2489 bool is_valid_dig = true;
2490 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2492 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2493 float nocheat_t = playersao->getNoCheatDigTime();
2494 playersao->noCheatDigEnd();
2495 // If player didn't start digging this, ignore dig
2496 if(nocheat_p != p_under){
2497 infostream<<"Server: NoCheat: "<<player->getName()
2498 <<" started digging "
2499 <<PP(nocheat_p)<<" and completed digging "
2500 <<PP(p_under)<<"; not digging."<<std::endl;
2501 is_valid_dig = false;
2503 m_script->on_cheat(playersao, "finished_unknown_dig");
2505 // Get player's wielded item
2506 ItemStack playeritem;
2507 InventoryList *mlist = playersao->getInventory()->getList("main");
2509 playeritem = mlist->getItem(playersao->getWieldIndex());
2510 ToolCapabilities playeritem_toolcap =
2511 playeritem.getToolCapabilities(m_itemdef);
2512 // Get diggability and expected digging time
2513 DigParams params = getDigParams(m_nodedef->get(n).groups,
2514 &playeritem_toolcap);
2515 // If can't dig, try hand
2516 if(!params.diggable){
2517 const ItemDefinition &hand = m_itemdef->get("");
2518 const ToolCapabilities *tp = hand.tool_capabilities;
2520 params = getDigParams(m_nodedef->get(n).groups, tp);
2522 // If can't dig, ignore dig
2523 if(!params.diggable){
2524 infostream<<"Server: NoCheat: "<<player->getName()
2525 <<" completed digging "<<PP(p_under)
2526 <<", which is not diggable with tool. not digging."
2528 is_valid_dig = false;
2530 m_script->on_cheat(playersao, "dug_unbreakable");
2532 // Check digging time
2533 // If already invalidated, we don't have to
2535 // Well not our problem then
2537 // Clean and long dig
2538 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2539 // All is good, but grab time from pool; don't care if
2540 // it's actually available
2541 playersao->getDigPool().grab(params.time);
2543 // Short or laggy dig
2544 // Try getting the time from pool
2545 else if(playersao->getDigPool().grab(params.time)){
2550 infostream<<"Server: NoCheat: "<<player->getName()
2551 <<" completed digging "<<PP(p_under)
2552 <<"too fast; not digging."<<std::endl;
2553 is_valid_dig = false;
2555 m_script->on_cheat(playersao, "dug_too_fast");
2559 /* Actually dig node */
2561 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2562 m_script->node_on_dig(p_under, n, playersao);
2564 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2565 RemoteClient *client = getClient(peer_id);
2566 // Send unusual result (that is, node not being removed)
2567 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2569 // Re-send block to revert change on client-side
2570 client->SetBlockNotSent(blockpos);
2573 client->ResendBlockIfOnWire(blockpos);
2579 3: place block or right-click object
2581 else if(action == 3)
2583 ItemStack item = playersao->getWieldedItem();
2585 // Reset build time counter
2586 if(pointed.type == POINTEDTHING_NODE &&
2587 item.getDefinition(m_itemdef).type == ITEM_NODE)
2588 getClient(peer_id)->m_time_from_building = 0.0;
2590 if(pointed.type == POINTEDTHING_OBJECT)
2592 // Right click object
2594 // Skip if object has been removed
2595 if(pointed_object->m_removed)
2598 actionstream<<player->getName()<<" right-clicks object "
2599 <<pointed.object_id<<": "
2600 <<pointed_object->getDescription()<<std::endl;
2603 pointed_object->rightClick(playersao);
2605 else if(m_script->item_OnPlace(
2606 item, playersao, pointed))
2608 // Placement was handled in lua
2610 // Apply returned ItemStack
2611 playersao->setWieldedItem(item);
2614 // If item has node placement prediction, always send the
2615 // blocks to make sure the client knows what exactly happened
2616 RemoteClient *client = getClient(peer_id);
2617 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2618 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2619 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2620 client->SetBlockNotSent(blockpos);
2621 if(blockpos2 != blockpos) {
2622 client->SetBlockNotSent(blockpos2);
2626 client->ResendBlockIfOnWire(blockpos);
2627 if(blockpos2 != blockpos) {
2628 client->ResendBlockIfOnWire(blockpos2);
2636 else if(action == 4)
2638 ItemStack item = playersao->getWieldedItem();
2640 actionstream<<player->getName()<<" uses "<<item.name
2641 <<", pointing at "<<pointed.dump()<<std::endl;
2643 if(m_script->item_OnUse(
2644 item, playersao, pointed))
2646 // Apply returned ItemStack
2647 playersao->setWieldedItem(item);
2654 Catch invalid actions
2658 infostream<<"WARNING: Server: Invalid action "
2659 <<action<<std::endl;
2662 else if(command == TOSERVER_REMOVED_SOUNDS)
2664 std::string datastring((char*)&data[2], datasize-2);
2665 std::istringstream is(datastring, std::ios_base::binary);
2667 int num = readU16(is);
2668 for(int k=0; k<num; k++){
2669 s32 id = readS32(is);
2670 std::map<s32, ServerPlayingSound>::iterator i =
2671 m_playing_sounds.find(id);
2672 if(i == m_playing_sounds.end())
2674 ServerPlayingSound &psound = i->second;
2675 psound.clients.erase(peer_id);
2676 if(psound.clients.empty())
2677 m_playing_sounds.erase(i++);
2680 else if(command == TOSERVER_NODEMETA_FIELDS)
2682 std::string datastring((char*)&data[2], datasize-2);
2683 std::istringstream is(datastring, std::ios_base::binary);
2685 v3s16 p = readV3S16(is);
2686 std::string formname = deSerializeString(is);
2687 int num = readU16(is);
2688 std::map<std::string, std::string> fields;
2689 for(int k=0; k<num; k++){
2690 std::string fieldname = deSerializeString(is);
2691 std::string fieldvalue = deSerializeLongString(is);
2692 fields[fieldname] = fieldvalue;
2695 // If something goes wrong, this player is to blame
2696 RollbackScopeActor rollback_scope(m_rollback,
2697 std::string("player:")+player->getName());
2699 // Check the target node for rollback data; leave others unnoticed
2700 RollbackNode rn_old(&m_env->getMap(), p, this);
2702 m_script->node_on_receive_fields(p, formname, fields,playersao);
2704 // Report rollback data
2705 RollbackNode rn_new(&m_env->getMap(), p, this);
2706 if(rollback() && rn_new != rn_old){
2707 RollbackAction action;
2708 action.setSetNode(p, rn_old, rn_new);
2709 rollback()->reportAction(action);
2712 else if(command == TOSERVER_INVENTORY_FIELDS)
2714 std::string datastring((char*)&data[2], datasize-2);
2715 std::istringstream is(datastring, std::ios_base::binary);
2717 std::string formname = deSerializeString(is);
2718 int num = readU16(is);
2719 std::map<std::string, std::string> fields;
2720 for(int k=0; k<num; k++){
2721 std::string fieldname = deSerializeString(is);
2722 std::string fieldvalue = deSerializeLongString(is);
2723 fields[fieldname] = fieldvalue;
2726 m_script->on_playerReceiveFields(playersao, formname, fields);
2730 infostream<<"Server::ProcessData(): Ignoring "
2731 "unknown command "<<command<<std::endl;
2735 catch(SendFailedException &e)
2737 errorstream<<"Server::ProcessData(): SendFailedException: "
2743 void Server::setTimeOfDay(u32 time)
2745 m_env->setTimeOfDay(time);
2746 m_time_of_day_send_timer = 0;
2749 void Server::onMapEditEvent(MapEditEvent *event)
2751 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2752 if(m_ignore_map_edit_events)
2754 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2756 MapEditEvent *e = event->clone();
2757 m_unsent_map_edit_queue.push_back(e);
2760 Inventory* Server::getInventory(const InventoryLocation &loc)
2763 case InventoryLocation::UNDEFINED:
2766 case InventoryLocation::CURRENT_PLAYER:
2769 case InventoryLocation::PLAYER:
2771 Player *player = m_env->getPlayer(loc.name.c_str());
2774 PlayerSAO *playersao = player->getPlayerSAO();
2777 return playersao->getInventory();
2780 case InventoryLocation::NODEMETA:
2782 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2785 return meta->getInventory();
2788 case InventoryLocation::DETACHED:
2790 if(m_detached_inventories.count(loc.name) == 0)
2792 return m_detached_inventories[loc.name];
2800 void Server::setInventoryModified(const InventoryLocation &loc)
2803 case InventoryLocation::UNDEFINED:
2806 case InventoryLocation::PLAYER:
2808 Player *player = m_env->getPlayer(loc.name.c_str());
2811 PlayerSAO *playersao = player->getPlayerSAO();
2814 playersao->m_inventory_not_sent = true;
2815 playersao->m_wielded_item_not_sent = true;
2818 case InventoryLocation::NODEMETA:
2820 v3s16 blockpos = getNodeBlockPos(loc.p);
2822 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2824 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2826 setBlockNotSent(blockpos);
2829 case InventoryLocation::DETACHED:
2831 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2839 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2841 std::list<u16> clients = m_clients.getClientIDs();
2843 // Set the modified blocks unsent for all the clients
2844 for (std::list<u16>::iterator
2845 i = clients.begin();
2846 i != clients.end(); ++i) {
2847 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2849 client->SetBlocksNotSent(block);
2854 void Server::peerAdded(con::Peer *peer)
2856 DSTACK(__FUNCTION_NAME);
2857 verbosestream<<"Server::peerAdded(): peer->id="
2858 <<peer->id<<std::endl;
2861 c.type = con::PEER_ADDED;
2862 c.peer_id = peer->id;
2864 m_peer_change_queue.push_back(c);
2867 void Server::deletingPeer(con::Peer *peer, bool timeout)
2869 DSTACK(__FUNCTION_NAME);
2870 verbosestream<<"Server::deletingPeer(): peer->id="
2871 <<peer->id<<", timeout="<<timeout<<std::endl;
2873 m_clients.event(peer->id, CSE_Disconnect);
2875 c.type = con::PEER_REMOVED;
2876 c.peer_id = peer->id;
2877 c.timeout = timeout;
2878 m_peer_change_queue.push_back(c);
2881 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2883 *retval = m_con.getPeerStat(peer_id,type);
2884 if (*retval == -1) return false;
2888 bool Server::getClientInfo(
2897 std::string* vers_string
2900 *state = m_clients.getClientState(peer_id);
2902 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2904 if (client == NULL) {
2909 *uptime = client->uptime();
2910 *ser_vers = client->serialization_version;
2911 *prot_vers = client->net_proto_version;
2913 *major = client->getMajor();
2914 *minor = client->getMinor();
2915 *patch = client->getPatch();
2916 *vers_string = client->getPatch();
2923 void Server::handlePeerChanges()
2925 while(m_peer_change_queue.size() > 0)
2927 con::PeerChange c = m_peer_change_queue.pop_front();
2929 verbosestream<<"Server: Handling peer change: "
2930 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2935 case con::PEER_ADDED:
2936 m_clients.CreateClient(c.peer_id);
2939 case con::PEER_REMOVED:
2940 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2944 assert("Invalid peer change event received!" == 0);
2950 void Server::SendMovement(u16 peer_id)
2952 DSTACK(__FUNCTION_NAME);
2953 std::ostringstream os(std::ios_base::binary);
2955 writeU16(os, TOCLIENT_MOVEMENT);
2956 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2957 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2958 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2959 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2960 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2961 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2962 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2963 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2964 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2965 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2966 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2967 writeF1000(os, g_settings->getFloat("movement_gravity"));
2970 std::string s = os.str();
2971 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2973 m_clients.send(peer_id, 0, data, true);
2976 void Server::SendHP(u16 peer_id, u8 hp)
2978 DSTACK(__FUNCTION_NAME);
2979 std::ostringstream os(std::ios_base::binary);
2981 writeU16(os, TOCLIENT_HP);
2985 std::string s = os.str();
2986 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2988 m_clients.send(peer_id, 0, data, true);
2991 void Server::SendBreath(u16 peer_id, u16 breath)
2993 DSTACK(__FUNCTION_NAME);
2994 std::ostringstream os(std::ios_base::binary);
2996 writeU16(os, TOCLIENT_BREATH);
2997 writeU16(os, breath);
3000 std::string s = os.str();
3001 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3003 m_clients.send(peer_id, 0, data, true);
3006 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3008 DSTACK(__FUNCTION_NAME);
3009 std::ostringstream os(std::ios_base::binary);
3011 writeU16(os, TOCLIENT_ACCESS_DENIED);
3012 os<<serializeWideString(reason);
3015 std::string s = os.str();
3016 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3018 m_clients.send(peer_id, 0, data, true);
3021 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3022 v3f camera_point_target)
3024 DSTACK(__FUNCTION_NAME);
3025 std::ostringstream os(std::ios_base::binary);
3027 writeU16(os, TOCLIENT_DEATHSCREEN);
3028 writeU8(os, set_camera_point_target);
3029 writeV3F1000(os, camera_point_target);
3032 std::string s = os.str();
3033 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3035 m_clients.send(peer_id, 0, data, true);
3038 void Server::SendItemDef(u16 peer_id,
3039 IItemDefManager *itemdef, u16 protocol_version)
3041 DSTACK(__FUNCTION_NAME);
3042 std::ostringstream os(std::ios_base::binary);
3046 u32 length of the next item
3047 zlib-compressed serialized ItemDefManager
3049 writeU16(os, TOCLIENT_ITEMDEF);
3050 std::ostringstream tmp_os(std::ios::binary);
3051 itemdef->serialize(tmp_os, protocol_version);
3052 std::ostringstream tmp_os2(std::ios::binary);
3053 compressZlib(tmp_os.str(), tmp_os2);
3054 os<<serializeLongString(tmp_os2.str());
3057 std::string s = os.str();
3058 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3059 <<"): size="<<s.size()<<std::endl;
3060 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3062 m_clients.send(peer_id, 0, data, true);
3065 void Server::SendNodeDef(u16 peer_id,
3066 INodeDefManager *nodedef, u16 protocol_version)
3068 DSTACK(__FUNCTION_NAME);
3069 std::ostringstream os(std::ios_base::binary);
3073 u32 length of the next item
3074 zlib-compressed serialized NodeDefManager
3076 writeU16(os, TOCLIENT_NODEDEF);
3077 std::ostringstream tmp_os(std::ios::binary);
3078 nodedef->serialize(tmp_os, protocol_version);
3079 std::ostringstream tmp_os2(std::ios::binary);
3080 compressZlib(tmp_os.str(), tmp_os2);
3081 os<<serializeLongString(tmp_os2.str());
3084 std::string s = os.str();
3085 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3086 <<"): size="<<s.size()<<std::endl;
3087 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3089 m_clients.send(peer_id, 0, data, true);
3093 Non-static send methods
3096 void Server::SendInventory(u16 peer_id)
3098 DSTACK(__FUNCTION_NAME);
3100 PlayerSAO *playersao = getPlayerSAO(peer_id);
3103 playersao->m_inventory_not_sent = false;
3109 std::ostringstream os;
3110 playersao->getInventory()->serialize(os);
3112 std::string s = os.str();
3114 SharedBuffer<u8> data(s.size()+2);
3115 writeU16(&data[0], TOCLIENT_INVENTORY);
3116 memcpy(&data[2], s.c_str(), s.size());
3119 m_clients.send(peer_id, 0, data, true);
3122 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3124 DSTACK(__FUNCTION_NAME);
3126 std::ostringstream os(std::ios_base::binary);
3130 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3131 os.write((char*)buf, 2);
3134 writeU16(buf, message.size());
3135 os.write((char*)buf, 2);
3138 for(u32 i=0; i<message.size(); i++)
3142 os.write((char*)buf, 2);
3146 std::string s = os.str();
3147 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3149 if (peer_id != PEER_ID_INEXISTENT)
3152 m_clients.send(peer_id, 0, data, true);
3156 m_clients.sendToAll(0,data,true);
3160 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3161 const std::string &formname)
3163 DSTACK(__FUNCTION_NAME);
3165 std::ostringstream os(std::ios_base::binary);
3170 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3171 os.write((char*)buf, 2);
3172 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3173 os<<serializeString(formname);
3176 std::string s = os.str();
3177 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3179 m_clients.send(peer_id, 0, data, true);
3182 // Spawns a particle on peer with peer_id
3183 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3184 float expirationtime, float size, bool collisiondetection,
3185 bool vertical, std::string texture)
3187 DSTACK(__FUNCTION_NAME);
3189 std::ostringstream os(std::ios_base::binary);
3190 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3191 writeV3F1000(os, pos);
3192 writeV3F1000(os, velocity);
3193 writeV3F1000(os, acceleration);
3194 writeF1000(os, expirationtime);
3195 writeF1000(os, size);
3196 writeU8(os, collisiondetection);
3197 os<<serializeLongString(texture);
3198 writeU8(os, vertical);
3201 std::string s = os.str();
3202 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3204 if (peer_id != PEER_ID_INEXISTENT)
3207 m_clients.send(peer_id, 0, data, true);
3211 m_clients.sendToAll(0,data,true);
3215 // Adds a ParticleSpawner on peer with peer_id
3216 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3217 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3218 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3220 DSTACK(__FUNCTION_NAME);
3222 std::ostringstream os(std::ios_base::binary);
3223 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3225 writeU16(os, amount);
3226 writeF1000(os, spawntime);
3227 writeV3F1000(os, minpos);
3228 writeV3F1000(os, maxpos);
3229 writeV3F1000(os, minvel);
3230 writeV3F1000(os, maxvel);
3231 writeV3F1000(os, minacc);
3232 writeV3F1000(os, maxacc);
3233 writeF1000(os, minexptime);
3234 writeF1000(os, maxexptime);
3235 writeF1000(os, minsize);
3236 writeF1000(os, maxsize);
3237 writeU8(os, collisiondetection);
3238 os<<serializeLongString(texture);
3240 writeU8(os, vertical);
3243 std::string s = os.str();
3244 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3246 if (peer_id != PEER_ID_INEXISTENT)
3249 m_clients.send(peer_id, 0, data, true);
3252 m_clients.sendToAll(0,data,true);
3256 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3258 DSTACK(__FUNCTION_NAME);
3260 std::ostringstream os(std::ios_base::binary);
3261 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3266 std::string s = os.str();
3267 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3269 if (peer_id != PEER_ID_INEXISTENT) {
3271 m_clients.send(peer_id, 0, data, true);
3274 m_clients.sendToAll(0,data,true);
3279 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3281 std::ostringstream os(std::ios_base::binary);
3284 writeU16(os, TOCLIENT_HUDADD);
3286 writeU8(os, (u8)form->type);
3287 writeV2F1000(os, form->pos);
3288 os << serializeString(form->name);
3289 writeV2F1000(os, form->scale);
3290 os << serializeString(form->text);
3291 writeU32(os, form->number);
3292 writeU32(os, form->item);
3293 writeU32(os, form->dir);
3294 writeV2F1000(os, form->align);
3295 writeV2F1000(os, form->offset);
3296 writeV3F1000(os, form->world_pos);
3297 writeV2S32(os,form->size);
3300 std::string s = os.str();
3301 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3303 m_clients.send(peer_id, 1, data, true);
3306 void Server::SendHUDRemove(u16 peer_id, u32 id)
3308 std::ostringstream os(std::ios_base::binary);
3311 writeU16(os, TOCLIENT_HUDRM);
3315 std::string s = os.str();
3316 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3319 m_clients.send(peer_id, 1, data, true);
3322 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3324 std::ostringstream os(std::ios_base::binary);
3327 writeU16(os, TOCLIENT_HUDCHANGE);
3329 writeU8(os, (u8)stat);
3332 case HUD_STAT_SCALE:
3333 case HUD_STAT_ALIGN:
3334 case HUD_STAT_OFFSET:
3335 writeV2F1000(os, *(v2f *)value);
3339 os << serializeString(*(std::string *)value);
3341 case HUD_STAT_WORLD_POS:
3342 writeV3F1000(os, *(v3f *)value);
3345 writeV2S32(os,*(v2s32 *)value);
3347 case HUD_STAT_NUMBER:
3351 writeU32(os, *(u32 *)value);
3356 std::string s = os.str();
3357 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3359 m_clients.send(peer_id, 0, data, true);
3362 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3364 std::ostringstream os(std::ios_base::binary);
3367 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3369 //////////////////////////// compatibility code to be removed //////////////
3370 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3371 ////////////////////////////////////////////////////////////////////////////
3372 writeU32(os, flags);
3376 std::string s = os.str();
3377 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3379 m_clients.send(peer_id, 0, data, true);
3382 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3384 std::ostringstream os(std::ios_base::binary);
3387 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3388 writeU16(os, param);
3389 os<<serializeString(value);
3392 std::string s = os.str();
3393 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3395 m_clients.send(peer_id, 0, data, true);
3398 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3399 const std::string &type, const std::vector<std::string> ¶ms)
3401 std::ostringstream os(std::ios_base::binary);
3404 writeU16(os, TOCLIENT_SET_SKY);
3405 writeARGB8(os, bgcolor);
3406 os<<serializeString(type);
3407 writeU16(os, params.size());
3408 for(size_t i=0; i<params.size(); i++)
3409 os<<serializeString(params[i]);
3412 std::string s = os.str();
3413 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3415 m_clients.send(peer_id, 0, data, true);
3418 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3421 std::ostringstream os(std::ios_base::binary);
3424 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3425 writeU8(os, do_override);
3426 writeU16(os, ratio*65535);
3429 std::string s = os.str();
3430 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3432 m_clients.send(peer_id, 0, data, true);
3435 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3437 DSTACK(__FUNCTION_NAME);
3440 SharedBuffer<u8> data(2+2+4);
3441 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3442 writeU16(&data[2], time);
3443 writeF1000(&data[4], time_speed);
3445 if (peer_id == PEER_ID_INEXISTENT) {
3446 m_clients.sendToAll(0,data,true);
3450 m_clients.send(peer_id, 0, data, true);
3454 void Server::SendPlayerHP(u16 peer_id)
3456 DSTACK(__FUNCTION_NAME);
3457 PlayerSAO *playersao = getPlayerSAO(peer_id);
3459 playersao->m_hp_not_sent = false;
3460 SendHP(peer_id, playersao->getHP());
3461 m_script->player_event(playersao,"health_changed");
3463 // Send to other clients
3464 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3465 ActiveObjectMessage aom(playersao->getId(), true, str);
3466 playersao->m_messages_out.push_back(aom);
3469 void Server::SendPlayerBreath(u16 peer_id)
3471 DSTACK(__FUNCTION_NAME);
3472 PlayerSAO *playersao = getPlayerSAO(peer_id);
3474 playersao->m_breath_not_sent = false;
3475 m_script->player_event(playersao,"breath_changed");
3476 SendBreath(peer_id, playersao->getBreath());
3479 void Server::SendMovePlayer(u16 peer_id)
3481 DSTACK(__FUNCTION_NAME);
3482 Player *player = m_env->getPlayer(peer_id);
3485 std::ostringstream os(std::ios_base::binary);
3486 writeU16(os, TOCLIENT_MOVE_PLAYER);
3487 writeV3F1000(os, player->getPosition());
3488 writeF1000(os, player->getPitch());
3489 writeF1000(os, player->getYaw());
3492 v3f pos = player->getPosition();
3493 f32 pitch = player->getPitch();
3494 f32 yaw = player->getYaw();
3495 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3496 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3503 std::string s = os.str();
3504 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3506 m_clients.send(peer_id, 0, data, true);
3509 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3511 std::ostringstream os(std::ios_base::binary);
3513 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3514 writeV2S32(os, animation_frames[0]);
3515 writeV2S32(os, animation_frames[1]);
3516 writeV2S32(os, animation_frames[2]);
3517 writeV2S32(os, animation_frames[3]);
3518 writeF1000(os, animation_speed);
3521 std::string s = os.str();
3522 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3524 m_clients.send(peer_id, 0, data, true);
3527 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3529 std::ostringstream os(std::ios_base::binary);
3531 writeU16(os, TOCLIENT_EYE_OFFSET);
3532 writeV3F1000(os, first);
3533 writeV3F1000(os, third);
3536 std::string s = os.str();
3537 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3539 m_clients.send(peer_id, 0, data, true);
3541 void Server::SendPlayerPrivileges(u16 peer_id)
3543 Player *player = m_env->getPlayer(peer_id);
3545 if(player->peer_id == PEER_ID_INEXISTENT)
3548 std::set<std::string> privs;
3549 m_script->getAuth(player->getName(), NULL, &privs);
3551 std::ostringstream os(std::ios_base::binary);
3552 writeU16(os, TOCLIENT_PRIVILEGES);
3553 writeU16(os, privs.size());
3554 for(std::set<std::string>::const_iterator i = privs.begin();
3555 i != privs.end(); i++){
3556 os<<serializeString(*i);
3560 std::string s = os.str();
3561 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3563 m_clients.send(peer_id, 0, data, true);
3566 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3568 Player *player = m_env->getPlayer(peer_id);
3570 if(player->peer_id == PEER_ID_INEXISTENT)
3573 std::ostringstream os(std::ios_base::binary);
3574 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3575 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3578 std::string s = os.str();
3579 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3581 m_clients.send(peer_id, 0, data, true);
3584 s32 Server::playSound(const SimpleSoundSpec &spec,
3585 const ServerSoundParams ¶ms)
3587 // Find out initial position of sound
3588 bool pos_exists = false;
3589 v3f pos = params.getPos(m_env, &pos_exists);
3590 // If position is not found while it should be, cancel sound
3591 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3594 // Filter destination clients
3595 std::list<u16> dst_clients;
3596 if(params.to_player != "")
3598 Player *player = m_env->getPlayer(params.to_player.c_str());
3600 infostream<<"Server::playSound: Player \""<<params.to_player
3601 <<"\" not found"<<std::endl;
3604 if(player->peer_id == PEER_ID_INEXISTENT){
3605 infostream<<"Server::playSound: Player \""<<params.to_player
3606 <<"\" not connected"<<std::endl;
3609 dst_clients.push_back(player->peer_id);
3613 std::list<u16> clients = m_clients.getClientIDs();
3615 for(std::list<u16>::iterator
3616 i = clients.begin(); i != clients.end(); ++i)
3618 Player *player = m_env->getPlayer(*i);
3622 if(player->getPosition().getDistanceFrom(pos) >
3623 params.max_hear_distance)
3626 dst_clients.push_back(*i);
3629 if(dst_clients.empty())
3633 s32 id = m_next_sound_id++;
3634 // The sound will exist as a reference in m_playing_sounds
3635 m_playing_sounds[id] = ServerPlayingSound();
3636 ServerPlayingSound &psound = m_playing_sounds[id];
3637 psound.params = params;
3638 for(std::list<u16>::iterator i = dst_clients.begin();
3639 i != dst_clients.end(); i++)
3640 psound.clients.insert(*i);
3642 std::ostringstream os(std::ios_base::binary);
3643 writeU16(os, TOCLIENT_PLAY_SOUND);
3645 os<<serializeString(spec.name);
3646 writeF1000(os, spec.gain * params.gain);
3647 writeU8(os, params.type);
3648 writeV3F1000(os, pos);
3649 writeU16(os, params.object);
3650 writeU8(os, params.loop);
3652 std::string s = os.str();
3653 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3655 for(std::list<u16>::iterator i = dst_clients.begin();
3656 i != dst_clients.end(); i++){
3658 m_clients.send(*i, 0, data, true);
3662 void Server::stopSound(s32 handle)
3664 // Get sound reference
3665 std::map<s32, ServerPlayingSound>::iterator i =
3666 m_playing_sounds.find(handle);
3667 if(i == m_playing_sounds.end())
3669 ServerPlayingSound &psound = i->second;
3671 std::ostringstream os(std::ios_base::binary);
3672 writeU16(os, TOCLIENT_STOP_SOUND);
3673 writeS32(os, handle);
3675 std::string s = os.str();
3676 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3678 for(std::set<u16>::iterator i = psound.clients.begin();
3679 i != psound.clients.end(); i++){
3681 m_clients.send(*i, 0, data, true);
3683 // Remove sound reference
3684 m_playing_sounds.erase(i);
3687 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3688 std::list<u16> *far_players, float far_d_nodes)
3690 float maxd = far_d_nodes*BS;
3691 v3f p_f = intToFloat(p, BS);
3695 SharedBuffer<u8> reply(replysize);
3696 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3697 writeS16(&reply[2], p.X);
3698 writeS16(&reply[4], p.Y);
3699 writeS16(&reply[6], p.Z);
3701 std::list<u16> clients = m_clients.getClientIDs();
3702 for(std::list<u16>::iterator
3703 i = clients.begin();
3704 i != clients.end(); ++i)
3709 Player *player = m_env->getPlayer(*i);
3712 // If player is far away, only set modified blocks not sent
3713 v3f player_pos = player->getPosition();
3714 if(player_pos.getDistanceFrom(p_f) > maxd)
3716 far_players->push_back(*i);
3723 m_clients.send(*i, 0, reply, true);
3727 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3728 std::list<u16> *far_players, float far_d_nodes,
3729 bool remove_metadata)
3731 float maxd = far_d_nodes*BS;
3732 v3f p_f = intToFloat(p, BS);
3734 std::list<u16> clients = m_clients.getClientIDs();
3735 for(std::list<u16>::iterator
3736 i = clients.begin();
3737 i != clients.end(); ++i)
3743 Player *player = m_env->getPlayer(*i);
3746 // If player is far away, only set modified blocks not sent
3747 v3f player_pos = player->getPosition();
3748 if(player_pos.getDistanceFrom(p_f) > maxd)
3750 far_players->push_back(*i);
3755 SharedBuffer<u8> reply(0);
3757 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3761 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3762 reply = SharedBuffer<u8>(replysize);
3763 writeU16(&reply[0], TOCLIENT_ADDNODE);
3764 writeS16(&reply[2], p.X);
3765 writeS16(&reply[4], p.Y);
3766 writeS16(&reply[6], p.Z);
3767 n.serialize(&reply[8], client->serialization_version);
3768 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3769 writeU8(&reply[index], remove_metadata ? 0 : 1);
3771 if (!remove_metadata) {
3772 if (client->net_proto_version <= 21) {
3773 // Old clients always clear metadata; fix it
3774 // by sending the full block again.
3775 client->SetBlockNotSent(p);
3782 if (reply.getSize() > 0)
3783 m_clients.send(*i, 0, reply, true);
3787 void Server::setBlockNotSent(v3s16 p)
3789 std::list<u16> clients = m_clients.getClientIDs();
3791 for(std::list<u16>::iterator
3792 i = clients.begin();
3793 i != clients.end(); ++i)
3795 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3796 client->SetBlockNotSent(p);
3801 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3803 DSTACK(__FUNCTION_NAME);
3805 v3s16 p = block->getPos();
3809 bool completely_air = true;
3810 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3811 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3812 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3814 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3816 completely_air = false;
3817 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3822 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3824 infostream<<"[completely air] ";
3825 infostream<<std::endl;
3829 Create a packet with the block in the right format
3832 std::ostringstream os(std::ios_base::binary);
3833 block->serialize(os, ver, false);
3834 block->serializeNetworkSpecific(os, net_proto_version);
3835 std::string s = os.str();
3836 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3838 u32 replysize = 8 + blockdata.getSize();
3839 SharedBuffer<u8> reply(replysize);
3840 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3841 writeS16(&reply[2], p.X);
3842 writeS16(&reply[4], p.Y);
3843 writeS16(&reply[6], p.Z);
3844 memcpy(&reply[8], *blockdata, blockdata.getSize());
3846 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3847 <<": \tpacket size: "<<replysize<<std::endl;*/
3852 m_clients.send(peer_id, 2, reply, true);
3855 void Server::SendBlocks(float dtime)
3857 DSTACK(__FUNCTION_NAME);
3859 JMutexAutoLock envlock(m_env_mutex);
3860 //TODO check if one big lock could be faster then multiple small ones
3862 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3864 std::vector<PrioritySortedBlockTransfer> queue;
3866 s32 total_sending = 0;
3869 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3871 std::list<u16> clients = m_clients.getClientIDs();
3874 for(std::list<u16>::iterator
3875 i = clients.begin();
3876 i != clients.end(); ++i)
3878 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3883 total_sending += client->SendingCount();
3884 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3890 // Lowest priority number comes first.
3891 // Lowest is most important.
3892 std::sort(queue.begin(), queue.end());
3895 for(u32 i=0; i<queue.size(); i++)
3897 //TODO: Calculate limit dynamically
3898 if(total_sending >= g_settings->getS32
3899 ("max_simultaneous_block_sends_server_total"))
3902 PrioritySortedBlockTransfer q = queue[i];
3904 MapBlock *block = NULL;
3907 block = m_env->getMap().getBlockNoCreate(q.pos);
3909 catch(InvalidPositionException &e)
3914 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3919 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3921 client->SentBlock(q.pos);
3927 void Server::fillMediaCache()
3929 DSTACK(__FUNCTION_NAME);
3931 infostream<<"Server: Calculating media file checksums"<<std::endl;
3933 // Collect all media file paths
3934 std::list<std::string> paths;
3935 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3936 i != m_mods.end(); i++){
3937 const ModSpec &mod = *i;
3938 paths.push_back(mod.path + DIR_DELIM + "textures");
3939 paths.push_back(mod.path + DIR_DELIM + "sounds");
3940 paths.push_back(mod.path + DIR_DELIM + "media");
3941 paths.push_back(mod.path + DIR_DELIM + "models");
3943 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3945 // Collect media file information from paths into cache
3946 for(std::list<std::string>::iterator i = paths.begin();
3947 i != paths.end(); i++)
3949 std::string mediapath = *i;
3950 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3951 for(u32 j=0; j<dirlist.size(); j++){
3952 if(dirlist[j].dir) // Ignode dirs
3954 std::string filename = dirlist[j].name;
3955 // If name contains illegal characters, ignore the file
3956 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3957 infostream<<"Server: ignoring illegal file name: \""
3958 <<filename<<"\""<<std::endl;
3961 // If name is not in a supported format, ignore it
3962 const char *supported_ext[] = {
3963 ".png", ".jpg", ".bmp", ".tga",
3964 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3966 ".x", ".b3d", ".md2", ".obj",
3969 if(removeStringEnd(filename, supported_ext) == ""){
3970 infostream<<"Server: ignoring unsupported file extension: \""
3971 <<filename<<"\""<<std::endl;
3974 // Ok, attempt to load the file and add to cache
3975 std::string filepath = mediapath + DIR_DELIM + filename;
3977 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3978 if(fis.good() == false){
3979 errorstream<<"Server::fillMediaCache(): Could not open \""
3980 <<filename<<"\" for reading"<<std::endl;
3983 std::ostringstream tmp_os(std::ios_base::binary);
3987 fis.read(buf, 1024);
3988 std::streamsize len = fis.gcount();
3989 tmp_os.write(buf, len);
3998 errorstream<<"Server::fillMediaCache(): Failed to read \""
3999 <<filename<<"\""<<std::endl;
4002 if(tmp_os.str().length() == 0){
4003 errorstream<<"Server::fillMediaCache(): Empty file \""
4004 <<filepath<<"\""<<std::endl;
4009 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4011 unsigned char *digest = sha1.getDigest();
4012 std::string sha1_base64 = base64_encode(digest, 20);
4013 std::string sha1_hex = hex_encode((char*)digest, 20);
4017 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4018 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4023 struct SendableMediaAnnouncement
4026 std::string sha1_digest;
4028 SendableMediaAnnouncement(const std::string &name_="",
4029 const std::string &sha1_digest_=""):
4031 sha1_digest(sha1_digest_)
4035 void Server::sendMediaAnnouncement(u16 peer_id)
4037 DSTACK(__FUNCTION_NAME);
4039 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4042 std::list<SendableMediaAnnouncement> file_announcements;
4044 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4045 i != m_media.end(); i++){
4047 file_announcements.push_back(
4048 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4052 std::ostringstream os(std::ios_base::binary);
4060 u16 length of sha1_digest
4065 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4066 writeU16(os, file_announcements.size());
4068 for(std::list<SendableMediaAnnouncement>::iterator
4069 j = file_announcements.begin();
4070 j != file_announcements.end(); ++j){
4071 os<<serializeString(j->name);
4072 os<<serializeString(j->sha1_digest);
4074 os<<serializeString(g_settings->get("remote_media"));
4077 std::string s = os.str();
4078 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4081 m_clients.send(peer_id, 0, data, true);
4084 struct SendableMedia
4090 SendableMedia(const std::string &name_="", const std::string &path_="",
4091 const std::string &data_=""):
4098 void Server::sendRequestedMedia(u16 peer_id,
4099 const std::list<std::string> &tosend)
4101 DSTACK(__FUNCTION_NAME);
4103 verbosestream<<"Server::sendRequestedMedia(): "
4104 <<"Sending files to client"<<std::endl;
4108 // Put 5kB in one bunch (this is not accurate)
4109 u32 bytes_per_bunch = 5000;
4111 std::vector< std::list<SendableMedia> > file_bunches;
4112 file_bunches.push_back(std::list<SendableMedia>());
4114 u32 file_size_bunch_total = 0;
4116 for(std::list<std::string>::const_iterator i = tosend.begin();
4117 i != tosend.end(); ++i)
4119 const std::string &name = *i;
4121 if(m_media.find(name) == m_media.end()){
4122 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4123 <<"unknown file \""<<(name)<<"\""<<std::endl;
4127 //TODO get path + name
4128 std::string tpath = m_media[name].path;
4131 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4132 if(fis.good() == false){
4133 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4134 <<tpath<<"\" for reading"<<std::endl;
4137 std::ostringstream tmp_os(std::ios_base::binary);
4141 fis.read(buf, 1024);
4142 std::streamsize len = fis.gcount();
4143 tmp_os.write(buf, len);
4144 file_size_bunch_total += len;
4153 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4154 <<name<<"\""<<std::endl;
4157 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4158 <<tname<<"\""<<std::endl;*/
4160 file_bunches[file_bunches.size()-1].push_back(
4161 SendableMedia(name, tpath, tmp_os.str()));
4163 // Start next bunch if got enough data
4164 if(file_size_bunch_total >= bytes_per_bunch){
4165 file_bunches.push_back(std::list<SendableMedia>());
4166 file_size_bunch_total = 0;
4171 /* Create and send packets */
4173 u32 num_bunches = file_bunches.size();
4174 for(u32 i=0; i<num_bunches; i++)
4176 std::ostringstream os(std::ios_base::binary);
4180 u16 total number of texture bunches
4181 u16 index of this bunch
4182 u32 number of files in this bunch
4191 writeU16(os, TOCLIENT_MEDIA);
4192 writeU16(os, num_bunches);
4194 writeU32(os, file_bunches[i].size());
4196 for(std::list<SendableMedia>::iterator
4197 j = file_bunches[i].begin();
4198 j != file_bunches[i].end(); ++j){
4199 os<<serializeString(j->name);
4200 os<<serializeLongString(j->data);
4204 std::string s = os.str();
4205 verbosestream<<"Server::sendRequestedMedia(): bunch "
4206 <<i<<"/"<<num_bunches
4207 <<" files="<<file_bunches[i].size()
4208 <<" size=" <<s.size()<<std::endl;
4209 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4211 m_clients.send(peer_id, 2, data, true);
4215 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4217 if(m_detached_inventories.count(name) == 0){
4218 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4221 Inventory *inv = m_detached_inventories[name];
4223 std::ostringstream os(std::ios_base::binary);
4224 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4225 os<<serializeString(name);
4229 std::string s = os.str();
4230 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4232 if (peer_id != PEER_ID_INEXISTENT)
4235 m_clients.send(peer_id, 0, data, true);
4239 m_clients.sendToAll(0,data,true);
4243 void Server::sendDetachedInventories(u16 peer_id)
4245 DSTACK(__FUNCTION_NAME);
4247 for(std::map<std::string, Inventory*>::iterator
4248 i = m_detached_inventories.begin();
4249 i != m_detached_inventories.end(); i++){
4250 const std::string &name = i->first;
4251 //Inventory *inv = i->second;
4252 sendDetachedInventory(name, peer_id);
4260 void Server::DiePlayer(u16 peer_id)
4262 DSTACK(__FUNCTION_NAME);
4264 PlayerSAO *playersao = getPlayerSAO(peer_id);
4267 infostream<<"Server::DiePlayer(): Player "
4268 <<playersao->getPlayer()->getName()
4269 <<" dies"<<std::endl;
4271 playersao->setHP(0);
4273 // Trigger scripted stuff
4274 m_script->on_dieplayer(playersao);
4276 SendPlayerHP(peer_id);
4277 SendDeathscreen(peer_id, false, v3f(0,0,0));
4280 void Server::RespawnPlayer(u16 peer_id)
4282 DSTACK(__FUNCTION_NAME);
4284 PlayerSAO *playersao = getPlayerSAO(peer_id);
4287 infostream<<"Server::RespawnPlayer(): Player "
4288 <<playersao->getPlayer()->getName()
4289 <<" respawns"<<std::endl;
4291 playersao->setHP(PLAYER_MAX_HP);
4293 bool repositioned = m_script->on_respawnplayer(playersao);
4295 v3f pos = findSpawnPos(m_env->getServerMap());
4296 playersao->setPos(pos);
4300 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4302 DSTACK(__FUNCTION_NAME);
4304 SendAccessDenied(peer_id, reason);
4305 m_clients.event(peer_id, CSE_SetDenied);
4306 m_con.DisconnectPeer(peer_id);
4309 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4311 DSTACK(__FUNCTION_NAME);
4312 std::wstring message;
4315 Clear references to playing sounds
4317 for(std::map<s32, ServerPlayingSound>::iterator
4318 i = m_playing_sounds.begin();
4319 i != m_playing_sounds.end();)
4321 ServerPlayingSound &psound = i->second;
4322 psound.clients.erase(peer_id);
4323 if(psound.clients.empty())
4324 m_playing_sounds.erase(i++);
4329 Player *player = m_env->getPlayer(peer_id);
4331 // Collect information about leaving in chat
4333 if(player != NULL && reason != CDR_DENY)
4335 std::wstring name = narrow_to_wide(player->getName());
4338 message += L" left the game.";
4339 if(reason == CDR_TIMEOUT)
4340 message += L" (timed out)";
4344 /* Run scripts and remove from environment */
4348 PlayerSAO *playersao = player->getPlayerSAO();
4351 m_script->on_leaveplayer(playersao);
4353 playersao->disconnected();
4361 if(player != NULL && reason != CDR_DENY)
4363 std::ostringstream os(std::ios_base::binary);
4364 std::list<u16> clients = m_clients.getClientIDs();
4366 for(std::list<u16>::iterator
4367 i = clients.begin();
4368 i != clients.end(); ++i)
4371 Player *player = m_env->getPlayer(*i);
4374 // Get name of player
4375 os<<player->getName()<<" ";
4378 actionstream<<player->getName()<<" "
4379 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4380 <<" List of players: "<<os.str()<<std::endl;
4384 JMutexAutoLock env_lock(m_env_mutex);
4385 m_clients.DeleteClient(peer_id);
4389 // Send leave chat message to all remaining clients
4390 if(message.length() != 0)
4391 SendChatMessage(PEER_ID_INEXISTENT,message);
4394 void Server::UpdateCrafting(u16 peer_id)
4396 DSTACK(__FUNCTION_NAME);
4398 Player* player = m_env->getPlayer(peer_id);
4401 // Get a preview for crafting
4403 InventoryLocation loc;
4404 loc.setPlayer(player->getName());
4405 getCraftingResult(&player->inventory, preview, false, this);
4406 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4408 // Put the new preview in
4409 InventoryList *plist = player->inventory.getList("craftpreview");
4411 assert(plist->getSize() >= 1);
4412 plist->changeItem(0, preview);
4415 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4417 RemoteClient *client = getClientNoEx(peer_id,state_min);
4419 throw ClientNotFoundException("Client not found");
4423 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4425 return m_clients.getClientNoEx(peer_id, state_min);
4428 std::string Server::getPlayerName(u16 peer_id)
4430 Player *player = m_env->getPlayer(peer_id);
4432 return "[id="+itos(peer_id)+"]";
4433 return player->getName();
4436 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4438 Player *player = m_env->getPlayer(peer_id);
4441 return player->getPlayerSAO();
4444 std::wstring Server::getStatusString()
4446 std::wostringstream os(std::ios_base::binary);
4449 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4451 os<<L", uptime="<<m_uptime.get();
4453 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4454 // Information about clients
4457 std::list<u16> clients = m_clients.getClientIDs();
4458 for(std::list<u16>::iterator i = clients.begin();
4459 i != clients.end(); ++i)
4462 Player *player = m_env->getPlayer(*i);
4463 // Get name of player
4464 std::wstring name = L"unknown";
4466 name = narrow_to_wide(player->getName());
4467 // Add name to information string
4475 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4476 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4477 if(g_settings->get("motd") != "")
4478 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4482 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4484 std::set<std::string> privs;
4485 m_script->getAuth(name, NULL, &privs);
4489 bool Server::checkPriv(const std::string &name, const std::string &priv)
4491 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4492 return (privs.count(priv) != 0);
4495 void Server::reportPrivsModified(const std::string &name)
4498 std::list<u16> clients = m_clients.getClientIDs();
4499 for(std::list<u16>::iterator
4500 i = clients.begin();
4501 i != clients.end(); ++i){
4502 Player *player = m_env->getPlayer(*i);
4503 reportPrivsModified(player->getName());
4506 Player *player = m_env->getPlayer(name.c_str());
4509 SendPlayerPrivileges(player->peer_id);
4510 PlayerSAO *sao = player->getPlayerSAO();
4513 sao->updatePrivileges(
4514 getPlayerEffectivePrivs(name),
4519 void Server::reportInventoryFormspecModified(const std::string &name)
4521 Player *player = m_env->getPlayer(name.c_str());
4524 SendPlayerInventoryFormspec(player->peer_id);
4527 void Server::setIpBanned(const std::string &ip, const std::string &name)
4529 m_banmanager->add(ip, name);
4532 void Server::unsetIpBanned(const std::string &ip_or_name)
4534 m_banmanager->remove(ip_or_name);
4537 std::string Server::getBanDescription(const std::string &ip_or_name)
4539 return m_banmanager->getBanDescription(ip_or_name);
4542 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4544 Player *player = m_env->getPlayer(name);
4548 if (player->peer_id == PEER_ID_INEXISTENT)
4551 SendChatMessage(player->peer_id, msg);
4554 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4556 Player *player = m_env->getPlayer(playername);
4560 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4564 SendShowFormspecMessage(player->peer_id, formspec, formname);
4568 u32 Server::hudAdd(Player *player, HudElement *form) {
4572 u32 id = player->addHud(form);
4574 SendHUDAdd(player->peer_id, id, form);
4579 bool Server::hudRemove(Player *player, u32 id) {
4583 HudElement* todel = player->removeHud(id);
4590 SendHUDRemove(player->peer_id, id);
4594 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4598 SendHUDChange(player->peer_id, id, stat, data);
4602 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4606 SendHUDSetFlags(player->peer_id, flags, mask);
4607 player->hud_flags = flags;
4609 PlayerSAO* playersao = player->getPlayerSAO();
4611 if (playersao == NULL)
4614 m_script->player_event(playersao, "hud_changed");
4618 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4621 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4624 std::ostringstream os(std::ios::binary);
4625 writeS32(os, hotbar_itemcount);
4626 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4630 void Server::hudSetHotbarImage(Player *player, std::string name) {
4634 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4637 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4641 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4644 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4649 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4653 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4658 SendEyeOffset(player->peer_id, first, third);
4662 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4663 const std::string &type, const std::vector<std::string> ¶ms)
4668 SendSetSky(player->peer_id, bgcolor, type, params);
4672 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4678 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4682 void Server::notifyPlayers(const std::wstring &msg)
4684 SendChatMessage(PEER_ID_INEXISTENT,msg);
4687 void Server::spawnParticle(const char *playername, v3f pos,
4688 v3f velocity, v3f acceleration,
4689 float expirationtime, float size, bool
4690 collisiondetection, bool vertical, std::string texture)
4692 Player *player = m_env->getPlayer(playername);
4695 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4696 expirationtime, size, collisiondetection, vertical, texture);
4699 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4700 float expirationtime, float size,
4701 bool collisiondetection, bool vertical, std::string texture)
4703 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4704 expirationtime, size, collisiondetection, vertical, texture);
4707 u32 Server::addParticleSpawner(const char *playername,
4708 u16 amount, float spawntime,
4709 v3f minpos, v3f maxpos,
4710 v3f minvel, v3f maxvel,
4711 v3f minacc, v3f maxacc,
4712 float minexptime, float maxexptime,
4713 float minsize, float maxsize,
4714 bool collisiondetection, bool vertical, std::string texture)
4716 Player *player = m_env->getPlayer(playername);
4721 for(;;) // look for unused particlespawner id
4724 if (std::find(m_particlespawner_ids.begin(),
4725 m_particlespawner_ids.end(), id)
4726 == m_particlespawner_ids.end())
4728 m_particlespawner_ids.push_back(id);
4733 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4734 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4735 minexptime, maxexptime, minsize, maxsize,
4736 collisiondetection, vertical, texture, id);
4741 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4742 v3f minpos, v3f maxpos,
4743 v3f minvel, v3f maxvel,
4744 v3f minacc, v3f maxacc,
4745 float minexptime, float maxexptime,
4746 float minsize, float maxsize,
4747 bool collisiondetection, bool vertical, std::string texture)
4750 for(;;) // look for unused particlespawner id
4753 if (std::find(m_particlespawner_ids.begin(),
4754 m_particlespawner_ids.end(), id)
4755 == m_particlespawner_ids.end())
4757 m_particlespawner_ids.push_back(id);
4762 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4763 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4764 minexptime, maxexptime, minsize, maxsize,
4765 collisiondetection, vertical, texture, id);
4770 void Server::deleteParticleSpawner(const char *playername, u32 id)
4772 Player *player = m_env->getPlayer(playername);
4776 m_particlespawner_ids.erase(
4777 std::remove(m_particlespawner_ids.begin(),
4778 m_particlespawner_ids.end(), id),
4779 m_particlespawner_ids.end());
4780 SendDeleteParticleSpawner(player->peer_id, id);
4783 void Server::deleteParticleSpawnerAll(u32 id)
4785 m_particlespawner_ids.erase(
4786 std::remove(m_particlespawner_ids.begin(),
4787 m_particlespawner_ids.end(), id),
4788 m_particlespawner_ids.end());
4789 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4792 Inventory* Server::createDetachedInventory(const std::string &name)
4794 if(m_detached_inventories.count(name) > 0){
4795 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4796 delete m_detached_inventories[name];
4798 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4800 Inventory *inv = new Inventory(m_itemdef);
4802 m_detached_inventories[name] = inv;
4803 //TODO find a better way to do this
4804 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4811 BoolScopeSet(bool *dst, bool val):
4814 m_orig_state = *m_dst;
4819 *m_dst = m_orig_state;
4826 // actions: time-reversed list
4827 // Return value: success/failure
4828 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4829 std::list<std::string> *log)
4831 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4832 ServerMap *map = (ServerMap*)(&m_env->getMap());
4834 // Fail if no actions to handle
4835 if(actions.empty()){
4836 log->push_back("Nothing to do.");
4843 for(std::list<RollbackAction>::const_iterator
4844 i = actions.begin();
4845 i != actions.end(); i++)
4847 const RollbackAction &action = *i;
4849 bool success = action.applyRevert(map, this, this);
4852 std::ostringstream os;
4853 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4854 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4856 log->push_back(os.str());
4858 std::ostringstream os;
4859 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4860 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4862 log->push_back(os.str());
4866 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4867 <<" failed"<<std::endl;
4869 // Call it done if less than half failed
4870 return num_failed <= num_tried/2;
4873 // IGameDef interface
4875 IItemDefManager* Server::getItemDefManager()
4879 INodeDefManager* Server::getNodeDefManager()
4883 ICraftDefManager* Server::getCraftDefManager()
4887 ITextureSource* Server::getTextureSource()
4891 IShaderSource* Server::getShaderSource()
4895 scene::ISceneManager* Server::getSceneManager()
4900 u16 Server::allocateUnknownNodeId(const std::string &name)
4902 return m_nodedef->allocateDummy(name);
4904 ISoundManager* Server::getSoundManager()
4906 return &dummySoundManager;
4908 MtEventManager* Server::getEventManager()
4913 IWritableItemDefManager* Server::getWritableItemDefManager()
4917 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4921 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4926 const ModSpec* Server::getModSpec(const std::string &modname)
4928 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4929 i != m_mods.end(); i++){
4930 const ModSpec &mod = *i;
4931 if(mod.name == modname)
4936 void Server::getModNames(std::list<std::string> &modlist)
4938 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4940 modlist.push_back(i->name);
4943 std::string Server::getBuiltinLuaPath()
4945 return porting::path_share + DIR_DELIM + "builtin";
4948 v3f findSpawnPos(ServerMap &map)
4950 //return v3f(50,50,50)*BS;
4955 nodepos = v2s16(0,0);
4960 s16 water_level = map.getWaterLevel();
4962 // Try to find a good place a few times
4963 for(s32 i=0; i<1000; i++)
4966 // We're going to try to throw the player to this position
4967 v2s16 nodepos2d = v2s16(
4968 -range + (myrand() % (range * 2)),
4969 -range + (myrand() % (range * 2)));
4971 // Get ground height at point
4972 s16 groundheight = map.findGroundLevel(nodepos2d);
4973 if (groundheight <= water_level) // Don't go underwater
4975 if (groundheight > water_level + 6) // Don't go to high places
4978 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4979 bool is_good = false;
4981 for (s32 i = 0; i < 10; i++) {
4982 v3s16 blockpos = getNodeBlockPos(nodepos);
4983 map.emergeBlock(blockpos, true);
4984 content_t c = map.getNodeNoEx(nodepos).getContent();
4985 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4987 if (air_count >= 2){
4995 // Found a good place
4996 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5002 return intToFloat(nodepos, BS);
5005 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5007 RemotePlayer *player = NULL;
5008 bool newplayer = false;
5011 Try to get an existing player
5013 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5015 // If player is already connected, cancel
5016 if(player != NULL && player->peer_id != 0)
5018 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5023 If player with the wanted peer_id already exists, cancel.
5025 if(m_env->getPlayer(peer_id) != NULL)
5027 infostream<<"emergePlayer(): Player with wrong name but same"
5028 " peer_id already exists"<<std::endl;
5032 // Load player if it isn't already loaded
5034 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5037 // Create player if it doesn't exist
5040 player = new RemotePlayer(this, name);
5041 // Set player position
5042 infostream<<"Server: Finding spawn place for player \""
5043 <<name<<"\""<<std::endl;
5044 v3f pos = findSpawnPos(m_env->getServerMap());
5045 player->setPosition(pos);
5047 // Make sure the player is saved
5048 player->setModified(true);
5050 // Add player to environment
5051 m_env->addPlayer(player);
5054 // Create a new player active object
5055 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5056 getPlayerEffectivePrivs(player->getName()),
5059 /* Clean up old HUD elements from previous sessions */
5062 /* Add object to environment */
5063 m_env->addActiveObject(playersao);
5067 m_script->on_newplayer(playersao);
5073 void dedicated_server_loop(Server &server, bool &kill)
5075 DSTACK(__FUNCTION_NAME);
5077 verbosestream<<"dedicated_server_loop()"<<std::endl;
5079 IntervalLimiter m_profiler_interval;
5083 float steplen = g_settings->getFloat("dedicated_server_step");
5084 // This is kind of a hack but can be done like this
5085 // because server.step() is very light
5087 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5088 sleep_ms((int)(steplen*1000.0));
5090 server.step(steplen);
5092 if(server.getShutdownRequested() || kill)
5094 infostream<<"Dedicated server quitting"<<std::endl;
5096 if(g_settings->getBool("server_announce") == true)
5097 ServerList::sendAnnounce("delete");
5105 float profiler_print_interval =
5106 g_settings->getFloat("profiler_print_interval");
5107 if(profiler_print_interval != 0)
5109 if(m_profiler_interval.step(steplen, profiler_print_interval))
5111 infostream<<"Profiler:"<<std::endl;
5112 g_profiler->print(infostream);
5113 g_profiler->clear();