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),
201 m_liquid_transform_timer = 0.0;
202 m_liquid_transform_every = 1.0;
203 m_print_info_timer = 0.0;
204 m_masterserver_timer = 0.0;
205 m_objectdata_timer = 0.0;
206 m_emergethread_trigger_timer = 0.0;
207 m_savemap_timer = 0.0;
210 m_lag = g_settings->getFloat("dedicated_server_step");
213 throw ServerError("Supplied empty world path");
215 if(!gamespec.isValid())
216 throw ServerError("Supplied invalid gamespec");
218 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
219 if(m_simple_singleplayer_mode)
220 infostream<<" in simple singleplayer mode"<<std::endl;
222 infostream<<std::endl;
223 infostream<<"- world: "<<m_path_world<<std::endl;
224 infostream<<"- game: "<<m_gamespec.path<<std::endl;
226 // Initialize default settings and override defaults with those provided
228 set_default_settings(g_settings);
229 Settings gamedefaults;
230 getGameMinetestConfig(gamespec.path, gamedefaults);
231 override_default_settings(g_settings, &gamedefaults);
233 // Create server thread
234 m_thread = new ServerThread(this);
236 // Create emerge manager
237 m_emerge = new EmergeManager(this);
239 // Create world if it doesn't exist
240 if(!initializeWorld(m_path_world, m_gamespec.id))
241 throw ServerError("Failed to initialize world");
243 // Create ban manager
244 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
245 m_banmanager = new BanManager(ban_path);
247 // Create rollback manager
248 m_rollback = new RollbackManager(m_path_world, this);
250 ModConfiguration modconf(m_path_world);
251 m_mods = modconf.getMods();
252 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
253 // complain about mods with unsatisfied dependencies
254 if(!modconf.isConsistent())
256 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
257 it != unsatisfied_mods.end(); ++it)
260 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
261 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
262 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
263 errorstream << " \"" << *dep_it << "\"";
264 errorstream << std::endl;
268 Settings worldmt_settings;
269 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
270 worldmt_settings.readConfigFile(worldmt.c_str());
271 std::vector<std::string> names = worldmt_settings.getNames();
272 std::set<std::string> load_mod_names;
273 for(std::vector<std::string>::iterator it = names.begin();
274 it != names.end(); ++it)
276 std::string name = *it;
277 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
278 load_mod_names.insert(name.substr(9));
280 // complain about mods declared to be loaded, but not found
281 for(std::vector<ModSpec>::iterator it = m_mods.begin();
282 it != m_mods.end(); ++it)
283 load_mod_names.erase((*it).name);
284 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
285 it != unsatisfied_mods.end(); ++it)
286 load_mod_names.erase((*it).name);
287 if(!load_mod_names.empty())
289 errorstream << "The following mods could not be found:";
290 for(std::set<std::string>::iterator it = load_mod_names.begin();
291 it != load_mod_names.end(); ++it)
292 errorstream << " \"" << (*it) << "\"";
293 errorstream << std::endl;
297 JMutexAutoLock envlock(m_env_mutex);
299 // Load mapgen params from Settings
300 m_emerge->loadMapgenParams();
302 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
303 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
305 // Initialize scripting
306 infostream<<"Server: Initializing Lua"<<std::endl;
308 m_script = new GameScripting(this);
310 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
312 if (!m_script->loadScript(scriptpath))
313 throw ModError("Failed to load and run " + scriptpath);
316 infostream<<"Server: Loading mods: ";
317 for(std::vector<ModSpec>::iterator i = m_mods.begin();
318 i != m_mods.end(); i++){
319 const ModSpec &mod = *i;
320 infostream<<mod.name<<" ";
322 infostream<<std::endl;
323 // Load and run "mod" scripts
324 for(std::vector<ModSpec>::iterator i = m_mods.begin();
325 i != m_mods.end(); i++){
326 const ModSpec &mod = *i;
327 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
328 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
329 <<scriptpath<<"\"]"<<std::endl;
330 bool success = m_script->loadMod(scriptpath, mod.name);
332 errorstream<<"Server: Failed to load and run "
333 <<scriptpath<<std::endl;
334 throw ModError("Failed to load and run "+scriptpath);
338 // Read Textures and calculate sha1 sums
341 // Apply item aliases in the node definition manager
342 m_nodedef->updateAliases(m_itemdef);
344 m_nodedef->setNodeRegistrationStatus(true);
346 // Perform pending node name resolutions
347 m_nodedef->runNodeResolverCallbacks();
349 // Initialize Environment
350 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
352 m_clients.setEnv(m_env);
354 // Initialize mapgens
355 m_emerge->initMapgens();
357 // Give environment reference to scripting api
358 m_script->initializeEnvironment(m_env);
360 // Register us to receive map edit events
361 servermap->addEventReceiver(this);
363 // If file exists, load environment metadata
364 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
366 infostream<<"Server: Loading environment metadata"<<std::endl;
370 // Add some test ActiveBlockModifiers to environment
371 add_legacy_abms(m_env, m_nodedef);
373 m_liquid_transform_every = g_settings->getFloat("liquid_update");
378 infostream<<"Server destructing"<<std::endl;
380 // Send shutdown message
381 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
384 JMutexAutoLock envlock(m_env_mutex);
386 // Execute script shutdown hooks
387 m_script->on_shutdown();
389 infostream<<"Server: Saving players"<<std::endl;
390 m_env->saveLoadedPlayers();
392 infostream<<"Server: Saving environment metadata"<<std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
407 // N.B. the EmergeManager should be deleted after the Environment since Map
408 // depends on EmergeManager to write its current params to the map meta
417 // Deinitialize scripting
418 infostream<<"Server: Deinitializing scripting"<<std::endl;
421 // Delete detached inventories
422 for (std::map<std::string, Inventory*>::iterator
423 i = m_detached_inventories.begin();
424 i != m_detached_inventories.end(); i++) {
429 void Server::start(Address bind_addr)
431 DSTACK(__FUNCTION_NAME);
433 m_bind_addr = bind_addr;
435 infostream<<"Starting server on "
436 << bind_addr.serializeString() <<"..."<<std::endl;
438 // Stop thread if already running
441 // Initialize connection
442 m_con.SetTimeoutMs(30);
443 m_con.Serve(bind_addr);
448 // ASCII art for the win!
450 <<" .__ __ __ "<<std::endl
451 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
452 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
453 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
454 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
455 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
456 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
457 actionstream<<"Server for gameid=\""<<m_gamespec.id
458 <<"\" listening on "<<bind_addr.serializeString()<<":"
459 <<bind_addr.getPort() << "."<<std::endl;
464 DSTACK(__FUNCTION_NAME);
466 infostream<<"Server: Stopping and waiting threads"<<std::endl;
468 // Stop threads (set run=false first so both start stopping)
470 //m_emergethread.setRun(false);
472 //m_emergethread.stop();
474 infostream<<"Server: Threads stopped"<<std::endl;
477 void Server::step(float dtime)
479 DSTACK(__FUNCTION_NAME);
484 JMutexAutoLock lock(m_step_dtime_mutex);
485 m_step_dtime += dtime;
487 // Throw if fatal error occurred in thread
488 std::string async_err = m_async_fatal_error.get();
490 throw ServerError(async_err);
494 void Server::AsyncRunStep(bool initial_step)
496 DSTACK(__FUNCTION_NAME);
498 g_profiler->add("Server::AsyncRunStep (num)", 1);
502 JMutexAutoLock lock1(m_step_dtime_mutex);
503 dtime = m_step_dtime;
507 // Send blocks to clients
511 if((dtime < 0.001) && (initial_step == false))
514 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
516 //infostream<<"Server steps "<<dtime<<std::endl;
517 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
520 JMutexAutoLock lock1(m_step_dtime_mutex);
521 m_step_dtime -= dtime;
528 m_uptime.set(m_uptime.get() + dtime);
534 Update time of day and overall game time
537 JMutexAutoLock envlock(m_env_mutex);
539 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
542 Send to clients at constant intervals
545 m_time_of_day_send_timer -= dtime;
546 if(m_time_of_day_send_timer < 0.0)
548 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
549 u16 time = m_env->getTimeOfDay();
550 float time_speed = g_settings->getFloat("time_speed");
551 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
556 JMutexAutoLock lock(m_env_mutex);
557 // Figure out and report maximum lag to environment
558 float max_lag = m_env->getMaxLagEstimate();
559 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
561 if(dtime > 0.1 && dtime > max_lag * 2.0)
562 infostream<<"Server: Maximum lag peaked to "<<dtime
566 m_env->reportMaxLagEstimate(max_lag);
568 ScopeProfiler sp(g_profiler, "SEnv step");
569 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
573 static const float map_timer_and_unload_dtime = 2.92;
574 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
576 JMutexAutoLock lock(m_env_mutex);
577 // Run Map's timers and unload unused data
578 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
579 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
580 g_settings->getFloat("server_unload_unused_data_timeout"));
591 JMutexAutoLock lock(m_env_mutex);
593 std::list<u16> clientids = m_clients.getClientIDs();
595 ScopeProfiler sp(g_profiler, "Server: handle players");
597 for(std::list<u16>::iterator
598 i = clientids.begin();
599 i != clientids.end(); ++i)
601 PlayerSAO *playersao = getPlayerSAO(*i);
602 if(playersao == NULL)
606 Handle player HPs (die if hp=0)
608 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
610 if(playersao->getHP() == 0)
617 Send player breath if changed
619 if(playersao->m_breath_not_sent) {
620 SendPlayerBreath(*i);
624 Send player inventories if necessary
626 if(playersao->m_moved){
628 playersao->m_moved = false;
630 if(playersao->m_inventory_not_sent){
637 /* Transform liquids */
638 m_liquid_transform_timer += dtime;
639 if(m_liquid_transform_timer >= m_liquid_transform_every)
641 m_liquid_transform_timer -= m_liquid_transform_every;
643 JMutexAutoLock lock(m_env_mutex);
645 ScopeProfiler sp(g_profiler, "Server: liquid transform");
647 std::map<v3s16, MapBlock*> modified_blocks;
648 m_env->getMap().transformLiquids(modified_blocks);
653 core::map<v3s16, MapBlock*> lighting_modified_blocks;
654 ServerMap &map = ((ServerMap&)m_env->getMap());
655 map.updateLighting(modified_blocks, lighting_modified_blocks);
657 // Add blocks modified by lighting to modified_blocks
658 for(core::map<v3s16, MapBlock*>::Iterator
659 i = lighting_modified_blocks.getIterator();
660 i.atEnd() == false; i++)
662 MapBlock *block = i.getNode()->getValue();
663 modified_blocks.insert(block->getPos(), block);
667 Set the modified blocks unsent for all the clients
669 if(!modified_blocks.empty())
671 SetBlocksNotSent(modified_blocks);
674 m_clients.step(dtime);
676 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
678 // send masterserver announce
680 float &counter = m_masterserver_timer;
681 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
682 g_settings->getBool("server_announce"))
684 ServerList::sendAnnounce(counter ? "update" : "start",
685 m_bind_addr.getPort(),
686 m_clients.getPlayerNames(),
688 m_env->getGameTime(),
691 m_emerge->params.mg_name,
700 Check added and deleted active objects
703 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
704 JMutexAutoLock envlock(m_env_mutex);
707 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
708 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
710 // Radius inside which objects are active
711 s16 radius = g_settings->getS16("active_object_send_range_blocks");
712 s16 player_radius = g_settings->getS16("player_transfer_distance");
714 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
715 !g_settings->getBool("unlimited_player_transfer_distance"))
716 player_radius = radius;
718 radius *= MAP_BLOCKSIZE;
719 player_radius *= MAP_BLOCKSIZE;
721 for(std::map<u16, RemoteClient*>::iterator
723 i != clients.end(); ++i)
725 RemoteClient *client = i->second;
727 // If definitions and textures have not been sent, don't
728 // send objects either
729 if (client->getState() < CS_DefinitionsSent)
732 Player *player = m_env->getPlayer(client->peer_id);
735 // This can happen if the client timeouts somehow
736 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
738 <<" has no associated player"<<std::endl;*/
741 v3s16 pos = floatToInt(player->getPosition(), BS);
743 std::set<u16> removed_objects;
744 std::set<u16> added_objects;
745 m_env->getRemovedActiveObjects(pos, radius, player_radius,
746 client->m_known_objects, removed_objects);
747 m_env->getAddedActiveObjects(pos, radius, player_radius,
748 client->m_known_objects, added_objects);
750 // Ignore if nothing happened
751 if(removed_objects.empty() && added_objects.empty())
753 //infostream<<"active objects: none changed"<<std::endl;
757 std::string data_buffer;
761 // Handle removed objects
762 writeU16((u8*)buf, removed_objects.size());
763 data_buffer.append(buf, 2);
764 for(std::set<u16>::iterator
765 i = removed_objects.begin();
766 i != removed_objects.end(); ++i)
770 ServerActiveObject* obj = m_env->getActiveObject(id);
772 // Add to data buffer for sending
773 writeU16((u8*)buf, id);
774 data_buffer.append(buf, 2);
776 // Remove from known objects
777 client->m_known_objects.erase(id);
779 if(obj && obj->m_known_by_count > 0)
780 obj->m_known_by_count--;
783 // Handle added objects
784 writeU16((u8*)buf, added_objects.size());
785 data_buffer.append(buf, 2);
786 for(std::set<u16>::iterator
787 i = added_objects.begin();
788 i != added_objects.end(); ++i)
792 ServerActiveObject* obj = m_env->getActiveObject(id);
795 u8 type = ACTIVEOBJECT_TYPE_INVALID;
797 infostream<<"WARNING: "<<__FUNCTION_NAME
798 <<": NULL object"<<std::endl;
800 type = obj->getSendType();
802 // Add to data buffer for sending
803 writeU16((u8*)buf, id);
804 data_buffer.append(buf, 2);
805 writeU8((u8*)buf, type);
806 data_buffer.append(buf, 1);
809 data_buffer.append(serializeLongString(
810 obj->getClientInitializationData(client->net_proto_version)));
812 data_buffer.append(serializeLongString(""));
814 // Add to known objects
815 client->m_known_objects.insert(id);
818 obj->m_known_by_count++;
822 SharedBuffer<u8> reply(2 + data_buffer.size());
823 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
824 memcpy((char*)&reply[2], data_buffer.c_str(),
827 m_clients.send(client->peer_id, 0, reply, true);
829 verbosestream<<"Server: Sent object remove/add: "
830 <<removed_objects.size()<<" removed, "
831 <<added_objects.size()<<" added, "
832 <<"packet size is "<<reply.getSize()<<std::endl;
837 Collect a list of all the objects known by the clients
838 and report it back to the environment.
841 core::map<u16, bool> all_known_objects;
843 for(core::map<u16, RemoteClient*>::Iterator
844 i = m_clients.getIterator();
845 i.atEnd() == false; i++)
847 RemoteClient *client = i.getNode()->getValue();
848 // Go through all known objects of client
849 for(core::map<u16, bool>::Iterator
850 i = client->m_known_objects.getIterator();
851 i.atEnd()==false; i++)
853 u16 id = i.getNode()->getKey();
854 all_known_objects[id] = true;
858 m_env->setKnownActiveObjects(whatever);
867 JMutexAutoLock envlock(m_env_mutex);
868 ScopeProfiler sp(g_profiler, "Server: sending object messages");
871 // Value = data sent by object
872 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
874 // Get active object messages from environment
877 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
881 std::list<ActiveObjectMessage>* message_list = NULL;
882 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
883 n = buffered_messages.find(aom.id);
884 if(n == buffered_messages.end())
886 message_list = new std::list<ActiveObjectMessage>;
887 buffered_messages[aom.id] = message_list;
891 message_list = n->second;
893 message_list->push_back(aom);
897 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
898 // Route data to every client
899 for(std::map<u16, RemoteClient*>::iterator
901 i != clients.end(); ++i)
903 RemoteClient *client = i->second;
904 std::string reliable_data;
905 std::string unreliable_data;
906 // Go through all objects in message buffer
907 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
908 j = buffered_messages.begin();
909 j != buffered_messages.end(); ++j)
911 // If object is not known by client, skip it
913 if(client->m_known_objects.find(id) == client->m_known_objects.end())
915 // Get message list of object
916 std::list<ActiveObjectMessage>* list = j->second;
917 // Go through every message
918 for(std::list<ActiveObjectMessage>::iterator
919 k = list->begin(); k != list->end(); ++k)
921 // Compose the full new data with header
922 ActiveObjectMessage aom = *k;
923 std::string new_data;
926 writeU16((u8*)&buf[0], aom.id);
927 new_data.append(buf, 2);
929 new_data += serializeString(aom.datastring);
930 // Add data to buffer
932 reliable_data += new_data;
934 unreliable_data += new_data;
938 reliable_data and unreliable_data are now ready.
941 if(reliable_data.size() > 0)
943 SharedBuffer<u8> reply(2 + reliable_data.size());
944 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
945 memcpy((char*)&reply[2], reliable_data.c_str(),
946 reliable_data.size());
948 m_clients.send(client->peer_id, 0, reply, true);
950 if(unreliable_data.size() > 0)
952 SharedBuffer<u8> reply(2 + unreliable_data.size());
953 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
954 memcpy((char*)&reply[2], unreliable_data.c_str(),
955 unreliable_data.size());
956 // Send as unreliable
957 m_clients.send(client->peer_id, 1, reply, false);
960 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
962 infostream<<"Server: Size of object message data: "
963 <<"reliable: "<<reliable_data.size()
964 <<", unreliable: "<<unreliable_data.size()
970 // Clear buffered_messages
971 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
972 i = buffered_messages.begin();
973 i != buffered_messages.end(); ++i)
980 Send queued-for-sending map edit events.
983 // We will be accessing the environment
984 JMutexAutoLock lock(m_env_mutex);
986 // Don't send too many at a time
989 // Single change sending is disabled if queue size is not small
990 bool disable_single_change_sending = false;
991 if(m_unsent_map_edit_queue.size() >= 4)
992 disable_single_change_sending = true;
994 int event_count = m_unsent_map_edit_queue.size();
996 // We'll log the amount of each
999 while(m_unsent_map_edit_queue.size() != 0)
1001 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1003 // Players far away from the change are stored here.
1004 // Instead of sending the changes, MapBlocks are set not sent
1006 std::list<u16> far_players;
1008 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1010 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1011 prof.add("MEET_ADDNODE", 1);
1012 if(disable_single_change_sending)
1013 sendAddNode(event->p, event->n, event->already_known_by_peer,
1014 &far_players, 5, event->type == MEET_ADDNODE);
1016 sendAddNode(event->p, event->n, event->already_known_by_peer,
1017 &far_players, 30, event->type == MEET_ADDNODE);
1019 else if(event->type == MEET_REMOVENODE)
1021 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1022 prof.add("MEET_REMOVENODE", 1);
1023 if(disable_single_change_sending)
1024 sendRemoveNode(event->p, event->already_known_by_peer,
1027 sendRemoveNode(event->p, event->already_known_by_peer,
1030 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1032 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1033 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1034 setBlockNotSent(event->p);
1036 else if(event->type == MEET_OTHER)
1038 infostream<<"Server: MEET_OTHER"<<std::endl;
1039 prof.add("MEET_OTHER", 1);
1040 for(std::set<v3s16>::iterator
1041 i = event->modified_blocks.begin();
1042 i != event->modified_blocks.end(); ++i)
1044 setBlockNotSent(*i);
1049 prof.add("unknown", 1);
1050 infostream<<"WARNING: Server: Unknown MapEditEvent "
1051 <<((u32)event->type)<<std::endl;
1055 Set blocks not sent to far players
1057 if(!far_players.empty())
1059 // Convert list format to that wanted by SetBlocksNotSent
1060 std::map<v3s16, MapBlock*> modified_blocks2;
1061 for(std::set<v3s16>::iterator
1062 i = event->modified_blocks.begin();
1063 i != event->modified_blocks.end(); ++i)
1065 modified_blocks2[*i] =
1066 m_env->getMap().getBlockNoCreateNoEx(*i);
1068 // Set blocks not sent
1069 for(std::list<u16>::iterator
1070 i = far_players.begin();
1071 i != far_players.end(); ++i)
1074 RemoteClient *client = getClient(peer_id);
1077 client->SetBlocksNotSent(modified_blocks2);
1083 /*// Don't send too many at a time
1085 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1089 if(event_count >= 5){
1090 infostream<<"Server: MapEditEvents:"<<std::endl;
1091 prof.print(infostream);
1092 } else if(event_count != 0){
1093 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1094 prof.print(verbosestream);
1100 Trigger emergethread (it somehow gets to a non-triggered but
1101 bysy state sometimes)
1104 float &counter = m_emergethread_trigger_timer;
1110 m_emerge->startThreads();
1112 // Update m_enable_rollback_recording here too
1113 m_enable_rollback_recording =
1114 g_settings->getBool("enable_rollback_recording");
1118 // Save map, players and auth stuff
1120 float &counter = m_savemap_timer;
1122 if(counter >= g_settings->getFloat("server_map_save_interval"))
1125 JMutexAutoLock lock(m_env_mutex);
1127 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1130 if (m_banmanager->isModified()) {
1131 m_banmanager->save();
1134 // Save changed parts of map
1135 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1138 m_env->saveLoadedPlayers();
1140 // Save environment metadata
1146 void Server::Receive()
1148 DSTACK(__FUNCTION_NAME);
1149 SharedBuffer<u8> data;
1153 datasize = m_con.Receive(peer_id,data);
1154 ProcessData(*data, datasize, peer_id);
1156 catch(con::InvalidIncomingDataException &e)
1158 infostream<<"Server::Receive(): "
1159 "InvalidIncomingDataException: what()="
1160 <<e.what()<<std::endl;
1162 catch(SerializationError &e) {
1163 infostream<<"Server::Receive(): "
1164 "SerializationError: what()="
1165 <<e.what()<<std::endl;
1167 catch(ClientStateError &e)
1169 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1170 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1171 L"Try reconnecting or updating your client");
1173 catch(con::PeerNotFoundException &e)
1179 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1181 std::string playername = "";
1182 PlayerSAO *playersao = NULL;
1185 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1186 if (client != NULL) {
1187 playername = client->getName();
1188 playersao = emergePlayer(playername.c_str(), peer_id);
1190 } catch (std::exception &e) {
1196 RemotePlayer *player =
1197 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1199 // If failed, cancel
1200 if((playersao == NULL) || (player == NULL))
1202 if(player && player->peer_id != 0){
1203 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1204 <<" (player allocated to an another client)"<<std::endl;
1205 DenyAccess(peer_id, L"Another client is connected with this "
1206 L"name. If your client closed unexpectedly, try again in "
1209 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1211 DenyAccess(peer_id, L"Could not allocate player.");
1217 Send complete position information
1219 SendMovePlayer(peer_id);
1222 SendPlayerPrivileges(peer_id);
1224 // Send inventory formspec
1225 SendPlayerInventoryFormspec(peer_id);
1228 UpdateCrafting(peer_id);
1229 SendInventory(peer_id);
1232 if(g_settings->getBool("enable_damage"))
1233 SendPlayerHP(peer_id);
1236 SendPlayerBreath(peer_id);
1238 // Show death screen if necessary
1240 SendDeathscreen(peer_id, false, v3f(0,0,0));
1242 // Note things in chat if not in simple singleplayer mode
1243 if(!m_simple_singleplayer_mode)
1245 // Send information about server to player in chat
1246 SendChatMessage(peer_id, getStatusString());
1248 // Send information about joining in chat
1250 std::wstring name = L"unknown";
1251 Player *player = m_env->getPlayer(peer_id);
1253 name = narrow_to_wide(player->getName());
1255 std::wstring message;
1258 message += L" joined the game.";
1259 SendChatMessage(PEER_ID_INEXISTENT,message);
1262 Address addr = getPeerAddress(player->peer_id);
1263 std::string ip_str = addr.serializeString();
1264 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1269 std::vector<std::string> names = m_clients.getPlayerNames();
1271 actionstream<<player->getName() <<" joins game. List of players: ";
1273 for (std::vector<std::string>::iterator i = names.begin();
1274 i != names.end(); i++)
1276 actionstream << *i << " ";
1279 actionstream << player->getName() <<std::endl;
1284 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1286 DSTACK(__FUNCTION_NAME);
1287 // Environment is locked first.
1288 JMutexAutoLock envlock(m_env_mutex);
1290 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1294 Address address = getPeerAddress(peer_id);
1295 addr_s = address.serializeString();
1297 // drop player if is ip is banned
1298 if(m_banmanager->isIpBanned(addr_s)){
1299 std::string ban_name = m_banmanager->getBanName(addr_s);
1300 infostream<<"Server: A banned client tried to connect from "
1301 <<addr_s<<"; banned name was "
1302 <<ban_name<<std::endl;
1303 // This actually doesn't seem to transfer to the client
1304 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1305 +narrow_to_wide(ban_name));
1309 catch(con::PeerNotFoundException &e)
1312 * no peer for this packet found
1313 * most common reason is peer timeout, e.g. peer didn't
1314 * respond for some time, your server was overloaded or
1317 infostream<<"Server::ProcessData(): Cancelling: peer "
1318 <<peer_id<<" not found"<<std::endl;
1328 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1330 if(command == TOSERVER_INIT)
1332 // [0] u16 TOSERVER_INIT
1333 // [2] u8 SER_FMT_VER_HIGHEST_READ
1334 // [3] u8[20] player_name
1335 // [23] u8[28] password <--- can be sent without this, from old versions
1337 if(datasize < 2+1+PLAYERNAME_SIZE)
1340 RemoteClient* client = getClient(peer_id, CS_Created);
1342 // If net_proto_version is set, this client has already been handled
1343 if(client->getState() > CS_Created)
1345 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1346 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1350 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1351 <<peer_id<<")"<<std::endl;
1353 // Do not allow multiple players in simple singleplayer mode.
1354 // This isn't a perfect way to do it, but will suffice for now
1355 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1356 infostream<<"Server: Not allowing another client ("<<addr_s
1357 <<") to connect in simple singleplayer mode"<<std::endl;
1358 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1362 // First byte after command is maximum supported
1363 // serialization version
1364 u8 client_max = data[2];
1365 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1366 // Use the highest version supported by both
1367 int deployed = std::min(client_max, our_max);
1368 // If it's lower than the lowest supported, give up.
1369 if(deployed < SER_FMT_CLIENT_VER_LOWEST)
1370 deployed = SER_FMT_VER_INVALID;
1372 if(deployed == SER_FMT_VER_INVALID)
1374 actionstream<<"Server: A mismatched client tried to connect from "
1375 <<addr_s<<std::endl;
1376 infostream<<"Server: Cannot negotiate serialization version with "
1377 <<addr_s<<std::endl;
1378 DenyAccess(peer_id, std::wstring(
1379 L"Your client's version is not supported.\n"
1380 L"Server version is ")
1381 + narrow_to_wide(minetest_version_simple) + L"."
1386 client->setPendingSerializationVersion(deployed);
1389 Read and check network protocol version
1392 u16 min_net_proto_version = 0;
1393 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1394 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1396 // Use same version as minimum and maximum if maximum version field
1397 // doesn't exist (backwards compatibility)
1398 u16 max_net_proto_version = min_net_proto_version;
1399 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1400 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1402 // Start with client's maximum version
1403 u16 net_proto_version = max_net_proto_version;
1405 // Figure out a working version if it is possible at all
1406 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1407 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1409 // If maximum is larger than our maximum, go with our maximum
1410 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1411 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1412 // Else go with client's maximum
1414 net_proto_version = max_net_proto_version;
1417 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1418 <<min_net_proto_version<<", max: "<<max_net_proto_version
1419 <<", chosen: "<<net_proto_version<<std::endl;
1421 client->net_proto_version = net_proto_version;
1423 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1424 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1426 actionstream<<"Server: A mismatched client tried to connect from "
1427 <<addr_s<<std::endl;
1428 DenyAccess(peer_id, std::wstring(
1429 L"Your client's version is not supported.\n"
1430 L"Server version is ")
1431 + narrow_to_wide(minetest_version_simple) + L",\n"
1432 + L"server's PROTOCOL_VERSION is "
1433 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1435 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1436 + L", client's PROTOCOL_VERSION is "
1437 + narrow_to_wide(itos(min_net_proto_version))
1439 + narrow_to_wide(itos(max_net_proto_version))
1444 if(g_settings->getBool("strict_protocol_version_checking"))
1446 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1448 actionstream<<"Server: A mismatched (strict) client tried to "
1449 <<"connect from "<<addr_s<<std::endl;
1450 DenyAccess(peer_id, std::wstring(
1451 L"Your client's version is not supported.\n"
1452 L"Server version is ")
1453 + narrow_to_wide(minetest_version_simple) + L",\n"
1454 + L"server's PROTOCOL_VERSION (strict) is "
1455 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1456 + L", client's PROTOCOL_VERSION is "
1457 + narrow_to_wide(itos(min_net_proto_version))
1459 + narrow_to_wide(itos(max_net_proto_version))
1468 char playername[PLAYERNAME_SIZE];
1469 unsigned int playername_length = 0;
1470 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1471 playername[playername_length] = data[3+playername_length];
1472 if (data[3+playername_length] == 0)
1476 if (playername_length == PLAYERNAME_SIZE) {
1477 actionstream<<"Server: Player with name exceeding max length "
1478 <<"tried to connect from "<<addr_s<<std::endl;
1479 DenyAccess(peer_id, L"Name too long");
1484 if(playername[0]=='\0')
1486 actionstream<<"Server: Player with an empty name "
1487 <<"tried to connect from "<<addr_s<<std::endl;
1488 DenyAccess(peer_id, L"Empty name");
1492 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1494 actionstream<<"Server: Player with an invalid name "
1495 <<"tried to connect from "<<addr_s<<std::endl;
1496 DenyAccess(peer_id, L"Name contains unallowed characters");
1500 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1502 actionstream<<"Server: Player with the name \"singleplayer\" "
1503 <<"tried to connect from "<<addr_s<<std::endl;
1504 DenyAccess(peer_id, L"Name is not allowed");
1510 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1512 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1513 <<"tried to connect from "<<addr_s<<" "
1514 <<"but it was disallowed for the following reason: "
1515 <<reason<<std::endl;
1516 DenyAccess(peer_id, narrow_to_wide(reason));
1521 infostream<<"Server: New connection: \""<<playername<<"\" from "
1522 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1525 char given_password[PASSWORD_SIZE];
1526 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1528 // old version - assume blank password
1529 given_password[0] = 0;
1533 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1535 given_password[i] = data[23+i];
1537 given_password[PASSWORD_SIZE-1] = 0;
1540 if(!base64_is_valid(given_password)){
1541 actionstream<<"Server: "<<playername
1542 <<" supplied invalid password hash"<<std::endl;
1543 DenyAccess(peer_id, L"Invalid password hash");
1547 // Enforce user limit.
1548 // Don't enforce for users that have some admin right
1549 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1550 !checkPriv(playername, "server") &&
1551 !checkPriv(playername, "ban") &&
1552 !checkPriv(playername, "privs") &&
1553 !checkPriv(playername, "password") &&
1554 playername != g_settings->get("name"))
1556 actionstream<<"Server: "<<playername<<" tried to join, but there"
1557 <<" are already max_users="
1558 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1559 DenyAccess(peer_id, L"Too many users.");
1563 std::string checkpwd; // Password hash to check against
1564 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1566 // If no authentication info exists for user, create it
1568 if(!isSingleplayer() &&
1569 g_settings->getBool("disallow_empty_password") &&
1570 std::string(given_password) == ""){
1571 actionstream<<"Server: "<<playername
1572 <<" supplied empty password"<<std::endl;
1573 DenyAccess(peer_id, L"Empty passwords are "
1574 L"disallowed. Set a password and try again.");
1577 std::wstring raw_default_password =
1578 narrow_to_wide(g_settings->get("default_password"));
1579 std::string initial_password =
1580 translatePassword(playername, raw_default_password);
1582 // If default_password is empty, allow any initial password
1583 if (raw_default_password.length() == 0)
1584 initial_password = given_password;
1586 m_script->createAuth(playername, initial_password);
1589 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1592 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1593 <<" (auth handler does not work?)"<<std::endl;
1594 DenyAccess(peer_id, L"Not allowed to login");
1598 if(given_password != checkpwd){
1599 actionstream<<"Server: "<<playername<<" supplied wrong password"
1601 DenyAccess(peer_id, L"Wrong password");
1605 RemotePlayer *player =
1606 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1608 if(player && player->peer_id != 0){
1609 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1610 <<" (player allocated to an another client)"<<std::endl;
1611 DenyAccess(peer_id, L"Another client is connected with this "
1612 L"name. If your client closed unexpectedly, try again in "
1616 m_clients.setPlayerName(peer_id,playername);
1619 Answer with a TOCLIENT_INIT
1622 SharedBuffer<u8> reply(2+1+6+8+4);
1623 writeU16(&reply[0], TOCLIENT_INIT);
1624 writeU8(&reply[2], deployed);
1625 //send dummy pos for legacy reasons only
1626 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1627 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1628 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1631 m_clients.send(peer_id, 0, reply, true);
1632 m_clients.event(peer_id, CSE_Init);
1638 if(command == TOSERVER_INIT2)
1641 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1642 <<peer_id<<std::endl;
1644 m_clients.event(peer_id, CSE_GotInit2);
1645 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1648 ///// begin compatibility code
1649 PlayerSAO* playersao = NULL;
1650 if (protocol_version <= 22) {
1651 playersao = StageTwoClientInit(peer_id);
1653 if (playersao == NULL) {
1655 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1656 << peer_id << std::endl;
1660 ///// end compatibility code
1663 Send some initialization data
1666 infostream<<"Server: Sending content to "
1667 <<getPlayerName(peer_id)<<std::endl;
1669 // Send player movement settings
1670 SendMovement(peer_id);
1672 // Send item definitions
1673 SendItemDef(peer_id, m_itemdef, protocol_version);
1675 // Send node definitions
1676 SendNodeDef(peer_id, m_nodedef, protocol_version);
1678 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1680 // Send media announcement
1681 sendMediaAnnouncement(peer_id);
1683 // Send detached inventories
1684 sendDetachedInventories(peer_id);
1687 u16 time = m_env->getTimeOfDay();
1688 float time_speed = g_settings->getFloat("time_speed");
1689 SendTimeOfDay(peer_id, time, time_speed);
1691 ///// begin compatibility code
1692 if (protocol_version <= 22) {
1693 m_clients.event(peer_id, CSE_SetClientReady);
1694 m_script->on_joinplayer(playersao);
1696 ///// end compatibility code
1698 // Warnings about protocol version can be issued here
1699 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1701 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1702 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1708 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1709 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1711 if(peer_ser_ver == SER_FMT_VER_INVALID)
1713 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1714 " serialization format invalid or not initialized."
1715 " Skipping incoming command="<<command<<std::endl;
1719 /* Handle commands relate to client startup */
1720 if(command == TOSERVER_REQUEST_MEDIA) {
1721 std::string datastring((char*)&data[2], datasize-2);
1722 std::istringstream is(datastring, std::ios_base::binary);
1724 std::list<std::string> tosend;
1725 u16 numfiles = readU16(is);
1727 infostream<<"Sending "<<numfiles<<" files to "
1728 <<getPlayerName(peer_id)<<std::endl;
1729 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1731 for(int i = 0; i < numfiles; i++) {
1732 std::string name = deSerializeString(is);
1733 tosend.push_back(name);
1734 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1738 sendRequestedMedia(peer_id, tosend);
1741 else if(command == TOSERVER_RECEIVED_MEDIA) {
1744 else if(command == TOSERVER_CLIENT_READY) {
1745 // clients <= protocol version 22 did not send ready message,
1746 // they're already initialized
1747 if (peer_proto_ver <= 22) {
1748 infostream << "Client sent message not expected by a "
1749 << "client using protocol version <= 22,"
1750 << "disconnecing peer_id: " << peer_id << std::endl;
1751 m_con.DisconnectPeer(peer_id);
1755 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1757 if (playersao == NULL) {
1759 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1760 << peer_id << std::endl;
1761 m_con.DisconnectPeer(peer_id);
1766 if(datasize < 2+8) {
1768 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1769 << peer_id << std::endl;
1770 m_con.DisconnectPeer(peer_id);
1774 m_clients.setClientVersion(
1776 data[2], data[3], data[4],
1777 std::string((char*) &data[8],(u16) data[6]));
1779 m_clients.event(peer_id, CSE_SetClientReady);
1780 m_script->on_joinplayer(playersao);
1783 else if(command == TOSERVER_GOTBLOCKS)
1796 u16 count = data[2];
1797 for(u16 i=0; i<count; i++)
1799 if((s16)datasize < 2+1+(i+1)*6)
1800 throw con::InvalidIncomingDataException
1801 ("GOTBLOCKS length is too short");
1802 v3s16 p = readV3S16(&data[2+1+i*6]);
1803 /*infostream<<"Server: GOTBLOCKS ("
1804 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1805 RemoteClient *client = getClient(peer_id);
1806 client->GotBlock(p);
1811 if (m_clients.getClientState(peer_id) < CS_Active)
1813 if (command == TOSERVER_PLAYERPOS) return;
1815 errorstream<<"Got packet command: " << command << " for peer id "
1816 << peer_id << " but client isn't active yet. Dropping packet "
1821 Player *player = m_env->getPlayer(peer_id);
1822 if(player == NULL) {
1823 errorstream<<"Server::ProcessData(): Cancelling: "
1824 "No player for peer_id="<<peer_id
1825 << " disconnecting peer!" <<std::endl;
1826 m_con.DisconnectPeer(peer_id);
1830 PlayerSAO *playersao = player->getPlayerSAO();
1831 if(playersao == NULL) {
1832 errorstream<<"Server::ProcessData(): Cancelling: "
1833 "No player object for peer_id="<<peer_id
1834 << " disconnecting peer!" <<std::endl;
1835 m_con.DisconnectPeer(peer_id);
1839 if(command == TOSERVER_PLAYERPOS)
1841 if(datasize < 2+12+12+4+4)
1845 v3s32 ps = readV3S32(&data[start+2]);
1846 v3s32 ss = readV3S32(&data[start+2+12]);
1847 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1848 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1850 if(datasize >= 2+12+12+4+4+4)
1851 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1852 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1853 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1854 pitch = wrapDegrees(pitch);
1855 yaw = wrapDegrees(yaw);
1857 player->setPosition(position);
1858 player->setSpeed(speed);
1859 player->setPitch(pitch);
1860 player->setYaw(yaw);
1861 player->keyPressed=keyPressed;
1862 player->control.up = (bool)(keyPressed&1);
1863 player->control.down = (bool)(keyPressed&2);
1864 player->control.left = (bool)(keyPressed&4);
1865 player->control.right = (bool)(keyPressed&8);
1866 player->control.jump = (bool)(keyPressed&16);
1867 player->control.aux1 = (bool)(keyPressed&32);
1868 player->control.sneak = (bool)(keyPressed&64);
1869 player->control.LMB = (bool)(keyPressed&128);
1870 player->control.RMB = (bool)(keyPressed&256);
1872 bool cheated = playersao->checkMovementCheat();
1875 m_script->on_cheat(playersao, "moved_too_fast");
1878 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1879 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1880 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1882 else if(command == TOSERVER_DELETEDBLOCKS)
1895 u16 count = data[2];
1896 for(u16 i=0; i<count; i++)
1898 if((s16)datasize < 2+1+(i+1)*6)
1899 throw con::InvalidIncomingDataException
1900 ("DELETEDBLOCKS length is too short");
1901 v3s16 p = readV3S16(&data[2+1+i*6]);
1902 /*infostream<<"Server: DELETEDBLOCKS ("
1903 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1904 RemoteClient *client = getClient(peer_id);
1905 client->SetBlockNotSent(p);
1908 else if(command == TOSERVER_CLICK_OBJECT)
1910 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1913 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1915 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1918 else if(command == TOSERVER_GROUND_ACTION)
1920 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1924 else if(command == TOSERVER_RELEASE)
1926 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1929 else if(command == TOSERVER_SIGNTEXT)
1931 infostream<<"Server: SIGNTEXT not supported anymore"
1935 else if(command == TOSERVER_SIGNNODETEXT)
1937 infostream<<"Server: SIGNNODETEXT not supported anymore"
1941 else if(command == TOSERVER_INVENTORY_ACTION)
1943 // Strip command and create a stream
1944 std::string datastring((char*)&data[2], datasize-2);
1945 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1946 std::istringstream is(datastring, std::ios_base::binary);
1948 InventoryAction *a = InventoryAction::deSerialize(is);
1951 infostream<<"TOSERVER_INVENTORY_ACTION: "
1952 <<"InventoryAction::deSerialize() returned NULL"
1957 // If something goes wrong, this player is to blame
1958 RollbackScopeActor rollback_scope(m_rollback,
1959 std::string("player:")+player->getName());
1962 Note: Always set inventory not sent, to repair cases
1963 where the client made a bad prediction.
1967 Handle restrictions and special cases of the move action
1969 if(a->getType() == IACTION_MOVE)
1971 IMoveAction *ma = (IMoveAction*)a;
1973 ma->from_inv.applyCurrentPlayer(player->getName());
1974 ma->to_inv.applyCurrentPlayer(player->getName());
1976 setInventoryModified(ma->from_inv);
1977 setInventoryModified(ma->to_inv);
1979 bool from_inv_is_current_player =
1980 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1981 (ma->from_inv.name == player->getName());
1983 bool to_inv_is_current_player =
1984 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1985 (ma->to_inv.name == player->getName());
1988 Disable moving items out of craftpreview
1990 if(ma->from_list == "craftpreview")
1992 infostream<<"Ignoring IMoveAction from "
1993 <<(ma->from_inv.dump())<<":"<<ma->from_list
1994 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1995 <<" because src is "<<ma->from_list<<std::endl;
2001 Disable moving items into craftresult and craftpreview
2003 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2005 infostream<<"Ignoring IMoveAction from "
2006 <<(ma->from_inv.dump())<<":"<<ma->from_list
2007 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2008 <<" because dst is "<<ma->to_list<<std::endl;
2013 // Disallow moving items in elsewhere than player's inventory
2014 // if not allowed to interact
2015 if(!checkPriv(player->getName(), "interact") &&
2016 (!from_inv_is_current_player ||
2017 !to_inv_is_current_player))
2019 infostream<<"Cannot move outside of player's inventory: "
2020 <<"No interact privilege"<<std::endl;
2026 Handle restrictions and special cases of the drop action
2028 else if(a->getType() == IACTION_DROP)
2030 IDropAction *da = (IDropAction*)a;
2032 da->from_inv.applyCurrentPlayer(player->getName());
2034 setInventoryModified(da->from_inv);
2037 Disable dropping items out of craftpreview
2039 if(da->from_list == "craftpreview")
2041 infostream<<"Ignoring IDropAction from "
2042 <<(da->from_inv.dump())<<":"<<da->from_list
2043 <<" because src is "<<da->from_list<<std::endl;
2048 // Disallow dropping items if not allowed to interact
2049 if(!checkPriv(player->getName(), "interact"))
2056 Handle restrictions and special cases of the craft action
2058 else if(a->getType() == IACTION_CRAFT)
2060 ICraftAction *ca = (ICraftAction*)a;
2062 ca->craft_inv.applyCurrentPlayer(player->getName());
2064 setInventoryModified(ca->craft_inv);
2066 //bool craft_inv_is_current_player =
2067 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2068 // (ca->craft_inv.name == player->getName());
2070 // Disallow crafting if not allowed to interact
2071 if(!checkPriv(player->getName(), "interact"))
2073 infostream<<"Cannot craft: "
2074 <<"No interact privilege"<<std::endl;
2081 a->apply(this, playersao, this);
2085 else if(command == TOSERVER_CHAT_MESSAGE)
2093 std::string datastring((char*)&data[2], datasize-2);
2094 std::istringstream is(datastring, std::ios_base::binary);
2097 is.read((char*)buf, 2);
2098 u16 len = readU16(buf);
2100 std::wstring message;
2101 for(u16 i=0; i<len; i++)
2103 is.read((char*)buf, 2);
2104 message += (wchar_t)readU16(buf);
2107 // If something goes wrong, this player is to blame
2108 RollbackScopeActor rollback_scope(m_rollback,
2109 std::string("player:")+player->getName());
2111 // Get player name of this client
2112 std::wstring name = narrow_to_wide(player->getName());
2115 bool ate = m_script->on_chat_message(player->getName(),
2116 wide_to_narrow(message));
2117 // If script ate the message, don't proceed
2121 // Line to send to players
2123 // Whether to send to the player that sent the line
2124 bool send_to_sender_only = false;
2126 // Commands are implemented in Lua, so only catch invalid
2127 // commands that were not "eaten" and send an error back
2128 if(message[0] == L'/')
2130 message = message.substr(1);
2131 send_to_sender_only = true;
2132 if(message.length() == 0)
2133 line += L"-!- Empty command";
2135 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2139 if(checkPriv(player->getName(), "shout")){
2145 line += L"-!- You don't have permission to shout.";
2146 send_to_sender_only = true;
2153 Send the message to sender
2155 if (send_to_sender_only)
2157 SendChatMessage(peer_id, line);
2160 Send the message to others
2164 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2166 std::list<u16> clients = m_clients.getClientIDs();
2168 for(std::list<u16>::iterator
2169 i = clients.begin();
2170 i != clients.end(); ++i)
2173 SendChatMessage(*i, line);
2178 else if(command == TOSERVER_DAMAGE)
2180 std::string datastring((char*)&data[2], datasize-2);
2181 std::istringstream is(datastring, std::ios_base::binary);
2182 u8 damage = readU8(is);
2184 if(g_settings->getBool("enable_damage"))
2186 actionstream<<player->getName()<<" damaged by "
2187 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2190 playersao->setHP(playersao->getHP() - damage);
2192 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2195 if(playersao->m_hp_not_sent)
2196 SendPlayerHP(peer_id);
2199 else if(command == TOSERVER_BREATH)
2201 std::string datastring((char*)&data[2], datasize-2);
2202 std::istringstream is(datastring, std::ios_base::binary);
2203 u16 breath = readU16(is);
2204 playersao->setBreath(breath);
2205 m_script->player_event(playersao,"breath_changed");
2207 else if(command == TOSERVER_PASSWORD)
2210 [0] u16 TOSERVER_PASSWORD
2211 [2] u8[28] old password
2212 [30] u8[28] new password
2215 if(datasize != 2+PASSWORD_SIZE*2)
2217 /*char password[PASSWORD_SIZE];
2218 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2219 password[i] = data[2+i];
2220 password[PASSWORD_SIZE-1] = 0;*/
2222 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2230 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2232 char c = data[2+PASSWORD_SIZE+i];
2238 if(!base64_is_valid(newpwd)){
2239 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2240 // Wrong old password supplied!!
2241 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2245 infostream<<"Server: Client requests a password change from "
2246 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2248 std::string playername = player->getName();
2250 std::string checkpwd;
2251 m_script->getAuth(playername, &checkpwd, NULL);
2253 if(oldpwd != checkpwd)
2255 infostream<<"Server: invalid old password"<<std::endl;
2256 // Wrong old password supplied!!
2257 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2261 bool success = m_script->setPassword(playername, newpwd);
2263 actionstream<<player->getName()<<" changes password"<<std::endl;
2264 SendChatMessage(peer_id, L"Password change successful.");
2266 actionstream<<player->getName()<<" tries to change password but "
2267 <<"it fails"<<std::endl;
2268 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2271 else if(command == TOSERVER_PLAYERITEM)
2276 u16 item = readU16(&data[2]);
2277 playersao->setWieldIndex(item);
2279 else if(command == TOSERVER_RESPAWN)
2281 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2284 RespawnPlayer(peer_id);
2286 actionstream<<player->getName()<<" respawns at "
2287 <<PP(player->getPosition()/BS)<<std::endl;
2289 // ActiveObject is added to environment in AsyncRunStep after
2290 // the previous addition has been succesfully removed
2292 else if(command == TOSERVER_INTERACT)
2294 std::string datastring((char*)&data[2], datasize-2);
2295 std::istringstream is(datastring, std::ios_base::binary);
2301 [5] u32 length of the next item
2302 [9] serialized PointedThing
2304 0: start digging (from undersurface) or use
2305 1: stop digging (all parameters ignored)
2306 2: digging completed
2307 3: place block or item (to abovesurface)
2310 u8 action = readU8(is);
2311 u16 item_i = readU16(is);
2312 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2313 PointedThing pointed;
2314 pointed.deSerialize(tmp_is);
2316 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2317 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2321 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2322 <<" tried to interact, but is dead!"<<std::endl;
2326 v3f player_pos = playersao->getLastGoodPosition();
2328 // Update wielded item
2329 playersao->setWieldIndex(item_i);
2331 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2332 v3s16 p_under = pointed.node_undersurface;
2333 v3s16 p_above = pointed.node_abovesurface;
2335 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2336 ServerActiveObject *pointed_object = NULL;
2337 if(pointed.type == POINTEDTHING_OBJECT)
2339 pointed_object = m_env->getActiveObject(pointed.object_id);
2340 if(pointed_object == NULL)
2342 verbosestream<<"TOSERVER_INTERACT: "
2343 "pointed object is NULL"<<std::endl;
2349 v3f pointed_pos_under = player_pos;
2350 v3f pointed_pos_above = player_pos;
2351 if(pointed.type == POINTEDTHING_NODE)
2353 pointed_pos_under = intToFloat(p_under, BS);
2354 pointed_pos_above = intToFloat(p_above, BS);
2356 else if(pointed.type == POINTEDTHING_OBJECT)
2358 pointed_pos_under = pointed_object->getBasePosition();
2359 pointed_pos_above = pointed_pos_under;
2363 Check that target is reasonably close
2364 (only when digging or placing things)
2366 if(action == 0 || action == 2 || action == 3)
2368 float d = player_pos.getDistanceFrom(pointed_pos_under);
2369 float max_d = BS * 14; // Just some large enough value
2371 actionstream<<"Player "<<player->getName()
2372 <<" tried to access "<<pointed.dump()
2374 <<"d="<<d<<", max_d="<<max_d
2375 <<". ignoring."<<std::endl;
2376 // Re-send block to revert change on client-side
2377 RemoteClient *client = getClient(peer_id);
2378 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2379 client->SetBlockNotSent(blockpos);
2381 m_script->on_cheat(playersao, "interacted_too_far");
2388 Make sure the player is allowed to do it
2390 if(!checkPriv(player->getName(), "interact"))
2392 actionstream<<player->getName()<<" attempted to interact with "
2393 <<pointed.dump()<<" without 'interact' privilege"
2395 // Re-send block to revert change on client-side
2396 RemoteClient *client = getClient(peer_id);
2397 // Digging completed -> under
2399 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2400 client->SetBlockNotSent(blockpos);
2402 // Placement -> above
2404 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2405 client->SetBlockNotSent(blockpos);
2411 If something goes wrong, this player is to blame
2413 RollbackScopeActor rollback_scope(m_rollback,
2414 std::string("player:")+player->getName());
2417 0: start digging or punch object
2421 if(pointed.type == POINTEDTHING_NODE)
2424 NOTE: This can be used in the future to check if
2425 somebody is cheating, by checking the timing.
2427 MapNode n(CONTENT_IGNORE);
2429 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2431 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2434 infostream<<"Server: Not punching: Node not found."
2435 <<" Adding block to emerge queue."
2437 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2440 if(n.getContent() != CONTENT_IGNORE)
2441 m_script->node_on_punch(p_under, n, playersao, pointed);
2443 playersao->noCheatDigStart(p_under);
2445 else if(pointed.type == POINTEDTHING_OBJECT)
2447 // Skip if object has been removed
2448 if(pointed_object->m_removed)
2451 actionstream<<player->getName()<<" punches object "
2452 <<pointed.object_id<<": "
2453 <<pointed_object->getDescription()<<std::endl;
2455 ItemStack punchitem = playersao->getWieldedItem();
2456 ToolCapabilities toolcap =
2457 punchitem.getToolCapabilities(m_itemdef);
2458 v3f dir = (pointed_object->getBasePosition() -
2459 (player->getPosition() + player->getEyeOffset())
2461 float time_from_last_punch =
2462 playersao->resetTimeFromLastPunch();
2463 pointed_object->punch(dir, &toolcap, playersao,
2464 time_from_last_punch);
2472 else if(action == 1)
2477 2: Digging completed
2479 else if(action == 2)
2481 // Only digging of nodes
2482 if(pointed.type == POINTEDTHING_NODE)
2485 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2487 infostream << "Server: Not finishing digging: Node not found."
2488 << " Adding block to emerge queue."
2490 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2493 /* Cheat prevention */
2494 bool is_valid_dig = true;
2495 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2497 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2498 float nocheat_t = playersao->getNoCheatDigTime();
2499 playersao->noCheatDigEnd();
2500 // If player didn't start digging this, ignore dig
2501 if(nocheat_p != p_under){
2502 infostream<<"Server: NoCheat: "<<player->getName()
2503 <<" started digging "
2504 <<PP(nocheat_p)<<" and completed digging "
2505 <<PP(p_under)<<"; not digging."<<std::endl;
2506 is_valid_dig = false;
2508 m_script->on_cheat(playersao, "finished_unknown_dig");
2510 // Get player's wielded item
2511 ItemStack playeritem;
2512 InventoryList *mlist = playersao->getInventory()->getList("main");
2514 playeritem = mlist->getItem(playersao->getWieldIndex());
2515 ToolCapabilities playeritem_toolcap =
2516 playeritem.getToolCapabilities(m_itemdef);
2517 // Get diggability and expected digging time
2518 DigParams params = getDigParams(m_nodedef->get(n).groups,
2519 &playeritem_toolcap);
2520 // If can't dig, try hand
2521 if(!params.diggable){
2522 const ItemDefinition &hand = m_itemdef->get("");
2523 const ToolCapabilities *tp = hand.tool_capabilities;
2525 params = getDigParams(m_nodedef->get(n).groups, tp);
2527 // If can't dig, ignore dig
2528 if(!params.diggable){
2529 infostream<<"Server: NoCheat: "<<player->getName()
2530 <<" completed digging "<<PP(p_under)
2531 <<", which is not diggable with tool. not digging."
2533 is_valid_dig = false;
2535 m_script->on_cheat(playersao, "dug_unbreakable");
2537 // Check digging time
2538 // If already invalidated, we don't have to
2540 // Well not our problem then
2542 // Clean and long dig
2543 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2544 // All is good, but grab time from pool; don't care if
2545 // it's actually available
2546 playersao->getDigPool().grab(params.time);
2548 // Short or laggy dig
2549 // Try getting the time from pool
2550 else if(playersao->getDigPool().grab(params.time)){
2555 infostream<<"Server: NoCheat: "<<player->getName()
2556 <<" completed digging "<<PP(p_under)
2557 <<"too fast; not digging."<<std::endl;
2558 is_valid_dig = false;
2560 m_script->on_cheat(playersao, "dug_too_fast");
2564 /* Actually dig node */
2566 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2567 m_script->node_on_dig(p_under, n, playersao);
2569 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2570 RemoteClient *client = getClient(peer_id);
2571 // Send unusual result (that is, node not being removed)
2572 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2574 // Re-send block to revert change on client-side
2575 client->SetBlockNotSent(blockpos);
2578 client->ResendBlockIfOnWire(blockpos);
2584 3: place block or right-click object
2586 else if(action == 3)
2588 ItemStack item = playersao->getWieldedItem();
2590 // Reset build time counter
2591 if(pointed.type == POINTEDTHING_NODE &&
2592 item.getDefinition(m_itemdef).type == ITEM_NODE)
2593 getClient(peer_id)->m_time_from_building = 0.0;
2595 if(pointed.type == POINTEDTHING_OBJECT)
2597 // Right click object
2599 // Skip if object has been removed
2600 if(pointed_object->m_removed)
2603 actionstream<<player->getName()<<" right-clicks object "
2604 <<pointed.object_id<<": "
2605 <<pointed_object->getDescription()<<std::endl;
2608 pointed_object->rightClick(playersao);
2610 else if(m_script->item_OnPlace(
2611 item, playersao, pointed))
2613 // Placement was handled in lua
2615 // Apply returned ItemStack
2616 playersao->setWieldedItem(item);
2619 // If item has node placement prediction, always send the
2620 // blocks to make sure the client knows what exactly happened
2621 RemoteClient *client = getClient(peer_id);
2622 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2623 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2624 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2625 client->SetBlockNotSent(blockpos);
2626 if(blockpos2 != blockpos) {
2627 client->SetBlockNotSent(blockpos2);
2631 client->ResendBlockIfOnWire(blockpos);
2632 if(blockpos2 != blockpos) {
2633 client->ResendBlockIfOnWire(blockpos2);
2641 else if(action == 4)
2643 ItemStack item = playersao->getWieldedItem();
2645 actionstream<<player->getName()<<" uses "<<item.name
2646 <<", pointing at "<<pointed.dump()<<std::endl;
2648 if(m_script->item_OnUse(
2649 item, playersao, pointed))
2651 // Apply returned ItemStack
2652 playersao->setWieldedItem(item);
2659 Catch invalid actions
2663 infostream<<"WARNING: Server: Invalid action "
2664 <<action<<std::endl;
2667 else if(command == TOSERVER_REMOVED_SOUNDS)
2669 std::string datastring((char*)&data[2], datasize-2);
2670 std::istringstream is(datastring, std::ios_base::binary);
2672 int num = readU16(is);
2673 for(int k=0; k<num; k++){
2674 s32 id = readS32(is);
2675 std::map<s32, ServerPlayingSound>::iterator i =
2676 m_playing_sounds.find(id);
2677 if(i == m_playing_sounds.end())
2679 ServerPlayingSound &psound = i->second;
2680 psound.clients.erase(peer_id);
2681 if(psound.clients.empty())
2682 m_playing_sounds.erase(i++);
2685 else if(command == TOSERVER_NODEMETA_FIELDS)
2687 std::string datastring((char*)&data[2], datasize-2);
2688 std::istringstream is(datastring, std::ios_base::binary);
2690 v3s16 p = readV3S16(is);
2691 std::string formname = deSerializeString(is);
2692 int num = readU16(is);
2693 std::map<std::string, std::string> fields;
2694 for(int k=0; k<num; k++){
2695 std::string fieldname = deSerializeString(is);
2696 std::string fieldvalue = deSerializeLongString(is);
2697 fields[fieldname] = fieldvalue;
2700 // If something goes wrong, this player is to blame
2701 RollbackScopeActor rollback_scope(m_rollback,
2702 std::string("player:")+player->getName());
2704 // Check the target node for rollback data; leave others unnoticed
2705 RollbackNode rn_old(&m_env->getMap(), p, this);
2707 m_script->node_on_receive_fields(p, formname, fields,playersao);
2709 // Report rollback data
2710 RollbackNode rn_new(&m_env->getMap(), p, this);
2711 if(rollback() && rn_new != rn_old){
2712 RollbackAction action;
2713 action.setSetNode(p, rn_old, rn_new);
2714 rollback()->reportAction(action);
2717 else if(command == TOSERVER_INVENTORY_FIELDS)
2719 std::string datastring((char*)&data[2], datasize-2);
2720 std::istringstream is(datastring, std::ios_base::binary);
2722 std::string formname = deSerializeString(is);
2723 int num = readU16(is);
2724 std::map<std::string, std::string> fields;
2725 for(int k=0; k<num; k++){
2726 std::string fieldname = deSerializeString(is);
2727 std::string fieldvalue = deSerializeLongString(is);
2728 fields[fieldname] = fieldvalue;
2731 m_script->on_playerReceiveFields(playersao, formname, fields);
2735 infostream<<"Server::ProcessData(): Ignoring "
2736 "unknown command "<<command<<std::endl;
2740 catch(SendFailedException &e)
2742 errorstream<<"Server::ProcessData(): SendFailedException: "
2748 void Server::setTimeOfDay(u32 time)
2750 m_env->setTimeOfDay(time);
2751 m_time_of_day_send_timer = 0;
2754 void Server::onMapEditEvent(MapEditEvent *event)
2756 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2757 if(m_ignore_map_edit_events)
2759 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2761 MapEditEvent *e = event->clone();
2762 m_unsent_map_edit_queue.push_back(e);
2765 Inventory* Server::getInventory(const InventoryLocation &loc)
2768 case InventoryLocation::UNDEFINED:
2771 case InventoryLocation::CURRENT_PLAYER:
2774 case InventoryLocation::PLAYER:
2776 Player *player = m_env->getPlayer(loc.name.c_str());
2779 PlayerSAO *playersao = player->getPlayerSAO();
2782 return playersao->getInventory();
2785 case InventoryLocation::NODEMETA:
2787 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2790 return meta->getInventory();
2793 case InventoryLocation::DETACHED:
2795 if(m_detached_inventories.count(loc.name) == 0)
2797 return m_detached_inventories[loc.name];
2805 void Server::setInventoryModified(const InventoryLocation &loc)
2808 case InventoryLocation::UNDEFINED:
2811 case InventoryLocation::PLAYER:
2813 Player *player = m_env->getPlayer(loc.name.c_str());
2816 PlayerSAO *playersao = player->getPlayerSAO();
2819 playersao->m_inventory_not_sent = true;
2820 playersao->m_wielded_item_not_sent = true;
2823 case InventoryLocation::NODEMETA:
2825 v3s16 blockpos = getNodeBlockPos(loc.p);
2827 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2829 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2831 setBlockNotSent(blockpos);
2834 case InventoryLocation::DETACHED:
2836 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2844 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2846 std::list<u16> clients = m_clients.getClientIDs();
2848 // Set the modified blocks unsent for all the clients
2849 for (std::list<u16>::iterator
2850 i = clients.begin();
2851 i != clients.end(); ++i) {
2852 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2854 client->SetBlocksNotSent(block);
2859 void Server::peerAdded(con::Peer *peer)
2861 DSTACK(__FUNCTION_NAME);
2862 verbosestream<<"Server::peerAdded(): peer->id="
2863 <<peer->id<<std::endl;
2866 c.type = con::PEER_ADDED;
2867 c.peer_id = peer->id;
2869 m_peer_change_queue.push_back(c);
2872 void Server::deletingPeer(con::Peer *peer, bool timeout)
2874 DSTACK(__FUNCTION_NAME);
2875 verbosestream<<"Server::deletingPeer(): peer->id="
2876 <<peer->id<<", timeout="<<timeout<<std::endl;
2878 m_clients.event(peer->id, CSE_Disconnect);
2880 c.type = con::PEER_REMOVED;
2881 c.peer_id = peer->id;
2882 c.timeout = timeout;
2883 m_peer_change_queue.push_back(c);
2886 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2888 *retval = m_con.getPeerStat(peer_id,type);
2889 if (*retval == -1) return false;
2893 bool Server::getClientInfo(
2902 std::string* vers_string
2905 *state = m_clients.getClientState(peer_id);
2907 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2909 if (client == NULL) {
2914 *uptime = client->uptime();
2915 *ser_vers = client->serialization_version;
2916 *prot_vers = client->net_proto_version;
2918 *major = client->getMajor();
2919 *minor = client->getMinor();
2920 *patch = client->getPatch();
2921 *vers_string = client->getPatch();
2928 void Server::handlePeerChanges()
2930 while(m_peer_change_queue.size() > 0)
2932 con::PeerChange c = m_peer_change_queue.pop_front();
2934 verbosestream<<"Server: Handling peer change: "
2935 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2940 case con::PEER_ADDED:
2941 m_clients.CreateClient(c.peer_id);
2944 case con::PEER_REMOVED:
2945 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2949 assert("Invalid peer change event received!" == 0);
2955 void Server::SendMovement(u16 peer_id)
2957 DSTACK(__FUNCTION_NAME);
2958 std::ostringstream os(std::ios_base::binary);
2960 writeU16(os, TOCLIENT_MOVEMENT);
2961 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2962 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2963 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2964 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2965 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2966 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2967 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2968 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2969 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2970 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2971 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2972 writeF1000(os, g_settings->getFloat("movement_gravity"));
2975 std::string s = os.str();
2976 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2978 m_clients.send(peer_id, 0, data, true);
2981 void Server::SendHP(u16 peer_id, u8 hp)
2983 DSTACK(__FUNCTION_NAME);
2984 std::ostringstream os(std::ios_base::binary);
2986 writeU16(os, TOCLIENT_HP);
2990 std::string s = os.str();
2991 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2993 m_clients.send(peer_id, 0, data, true);
2996 void Server::SendBreath(u16 peer_id, u16 breath)
2998 DSTACK(__FUNCTION_NAME);
2999 std::ostringstream os(std::ios_base::binary);
3001 writeU16(os, TOCLIENT_BREATH);
3002 writeU16(os, breath);
3005 std::string s = os.str();
3006 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3008 m_clients.send(peer_id, 0, data, true);
3011 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3013 DSTACK(__FUNCTION_NAME);
3014 std::ostringstream os(std::ios_base::binary);
3016 writeU16(os, TOCLIENT_ACCESS_DENIED);
3017 os<<serializeWideString(reason);
3020 std::string s = os.str();
3021 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3023 m_clients.send(peer_id, 0, data, true);
3026 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3027 v3f camera_point_target)
3029 DSTACK(__FUNCTION_NAME);
3030 std::ostringstream os(std::ios_base::binary);
3032 writeU16(os, TOCLIENT_DEATHSCREEN);
3033 writeU8(os, set_camera_point_target);
3034 writeV3F1000(os, camera_point_target);
3037 std::string s = os.str();
3038 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3040 m_clients.send(peer_id, 0, data, true);
3043 void Server::SendItemDef(u16 peer_id,
3044 IItemDefManager *itemdef, u16 protocol_version)
3046 DSTACK(__FUNCTION_NAME);
3047 std::ostringstream os(std::ios_base::binary);
3051 u32 length of the next item
3052 zlib-compressed serialized ItemDefManager
3054 writeU16(os, TOCLIENT_ITEMDEF);
3055 std::ostringstream tmp_os(std::ios::binary);
3056 itemdef->serialize(tmp_os, protocol_version);
3057 std::ostringstream tmp_os2(std::ios::binary);
3058 compressZlib(tmp_os.str(), tmp_os2);
3059 os<<serializeLongString(tmp_os2.str());
3062 std::string s = os.str();
3063 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3064 <<"): size="<<s.size()<<std::endl;
3065 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3067 m_clients.send(peer_id, 0, data, true);
3070 void Server::SendNodeDef(u16 peer_id,
3071 INodeDefManager *nodedef, u16 protocol_version)
3073 DSTACK(__FUNCTION_NAME);
3074 std::ostringstream os(std::ios_base::binary);
3078 u32 length of the next item
3079 zlib-compressed serialized NodeDefManager
3081 writeU16(os, TOCLIENT_NODEDEF);
3082 std::ostringstream tmp_os(std::ios::binary);
3083 nodedef->serialize(tmp_os, protocol_version);
3084 std::ostringstream tmp_os2(std::ios::binary);
3085 compressZlib(tmp_os.str(), tmp_os2);
3086 os<<serializeLongString(tmp_os2.str());
3089 std::string s = os.str();
3090 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3091 <<"): size="<<s.size()<<std::endl;
3092 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3094 m_clients.send(peer_id, 0, data, true);
3098 Non-static send methods
3101 void Server::SendInventory(u16 peer_id)
3103 DSTACK(__FUNCTION_NAME);
3105 PlayerSAO *playersao = getPlayerSAO(peer_id);
3108 playersao->m_inventory_not_sent = false;
3114 std::ostringstream os;
3115 playersao->getInventory()->serialize(os);
3117 std::string s = os.str();
3119 SharedBuffer<u8> data(s.size()+2);
3120 writeU16(&data[0], TOCLIENT_INVENTORY);
3121 memcpy(&data[2], s.c_str(), s.size());
3124 m_clients.send(peer_id, 0, data, true);
3127 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3129 DSTACK(__FUNCTION_NAME);
3131 std::ostringstream os(std::ios_base::binary);
3135 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3136 os.write((char*)buf, 2);
3139 writeU16(buf, message.size());
3140 os.write((char*)buf, 2);
3143 for(u32 i=0; i<message.size(); i++)
3147 os.write((char*)buf, 2);
3151 std::string s = os.str();
3152 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3154 if (peer_id != PEER_ID_INEXISTENT)
3157 m_clients.send(peer_id, 0, data, true);
3161 m_clients.sendToAll(0,data,true);
3165 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3166 const std::string &formname)
3168 DSTACK(__FUNCTION_NAME);
3170 std::ostringstream os(std::ios_base::binary);
3175 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3176 os.write((char*)buf, 2);
3177 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3178 os<<serializeString(formname);
3181 std::string s = os.str();
3182 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3184 m_clients.send(peer_id, 0, data, true);
3187 // Spawns a particle on peer with peer_id
3188 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3189 float expirationtime, float size, bool collisiondetection,
3190 bool vertical, std::string texture)
3192 DSTACK(__FUNCTION_NAME);
3194 std::ostringstream os(std::ios_base::binary);
3195 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3196 writeV3F1000(os, pos);
3197 writeV3F1000(os, velocity);
3198 writeV3F1000(os, acceleration);
3199 writeF1000(os, expirationtime);
3200 writeF1000(os, size);
3201 writeU8(os, collisiondetection);
3202 os<<serializeLongString(texture);
3203 writeU8(os, vertical);
3206 std::string s = os.str();
3207 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3209 if (peer_id != PEER_ID_INEXISTENT)
3212 m_clients.send(peer_id, 0, data, true);
3216 m_clients.sendToAll(0,data,true);
3220 // Adds a ParticleSpawner on peer with peer_id
3221 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3222 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3223 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3225 DSTACK(__FUNCTION_NAME);
3227 std::ostringstream os(std::ios_base::binary);
3228 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3230 writeU16(os, amount);
3231 writeF1000(os, spawntime);
3232 writeV3F1000(os, minpos);
3233 writeV3F1000(os, maxpos);
3234 writeV3F1000(os, minvel);
3235 writeV3F1000(os, maxvel);
3236 writeV3F1000(os, minacc);
3237 writeV3F1000(os, maxacc);
3238 writeF1000(os, minexptime);
3239 writeF1000(os, maxexptime);
3240 writeF1000(os, minsize);
3241 writeF1000(os, maxsize);
3242 writeU8(os, collisiondetection);
3243 os<<serializeLongString(texture);
3245 writeU8(os, vertical);
3248 std::string s = os.str();
3249 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3251 if (peer_id != PEER_ID_INEXISTENT)
3254 m_clients.send(peer_id, 0, data, true);
3257 m_clients.sendToAll(0,data,true);
3261 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3263 DSTACK(__FUNCTION_NAME);
3265 std::ostringstream os(std::ios_base::binary);
3266 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3271 std::string s = os.str();
3272 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3274 if (peer_id != PEER_ID_INEXISTENT) {
3276 m_clients.send(peer_id, 0, data, true);
3279 m_clients.sendToAll(0,data,true);
3284 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3286 std::ostringstream os(std::ios_base::binary);
3289 writeU16(os, TOCLIENT_HUDADD);
3291 writeU8(os, (u8)form->type);
3292 writeV2F1000(os, form->pos);
3293 os << serializeString(form->name);
3294 writeV2F1000(os, form->scale);
3295 os << serializeString(form->text);
3296 writeU32(os, form->number);
3297 writeU32(os, form->item);
3298 writeU32(os, form->dir);
3299 writeV2F1000(os, form->align);
3300 writeV2F1000(os, form->offset);
3301 writeV3F1000(os, form->world_pos);
3302 writeV2S32(os,form->size);
3305 std::string s = os.str();
3306 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3308 m_clients.send(peer_id, 1, data, true);
3311 void Server::SendHUDRemove(u16 peer_id, u32 id)
3313 std::ostringstream os(std::ios_base::binary);
3316 writeU16(os, TOCLIENT_HUDRM);
3320 std::string s = os.str();
3321 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3324 m_clients.send(peer_id, 1, data, true);
3327 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3329 std::ostringstream os(std::ios_base::binary);
3332 writeU16(os, TOCLIENT_HUDCHANGE);
3334 writeU8(os, (u8)stat);
3337 case HUD_STAT_SCALE:
3338 case HUD_STAT_ALIGN:
3339 case HUD_STAT_OFFSET:
3340 writeV2F1000(os, *(v2f *)value);
3344 os << serializeString(*(std::string *)value);
3346 case HUD_STAT_WORLD_POS:
3347 writeV3F1000(os, *(v3f *)value);
3350 writeV2S32(os,*(v2s32 *)value);
3352 case HUD_STAT_NUMBER:
3356 writeU32(os, *(u32 *)value);
3361 std::string s = os.str();
3362 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3364 m_clients.send(peer_id, 0, data, true);
3367 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3369 std::ostringstream os(std::ios_base::binary);
3372 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3374 //////////////////////////// compatibility code to be removed //////////////
3375 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3376 ////////////////////////////////////////////////////////////////////////////
3377 writeU32(os, flags);
3381 std::string s = os.str();
3382 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3384 m_clients.send(peer_id, 0, data, true);
3387 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3389 std::ostringstream os(std::ios_base::binary);
3392 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3393 writeU16(os, param);
3394 os<<serializeString(value);
3397 std::string s = os.str();
3398 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3400 m_clients.send(peer_id, 0, data, true);
3403 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3404 const std::string &type, const std::vector<std::string> ¶ms)
3406 std::ostringstream os(std::ios_base::binary);
3409 writeU16(os, TOCLIENT_SET_SKY);
3410 writeARGB8(os, bgcolor);
3411 os<<serializeString(type);
3412 writeU16(os, params.size());
3413 for(size_t i=0; i<params.size(); i++)
3414 os<<serializeString(params[i]);
3417 std::string s = os.str();
3418 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3420 m_clients.send(peer_id, 0, data, true);
3423 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3426 std::ostringstream os(std::ios_base::binary);
3429 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3430 writeU8(os, do_override);
3431 writeU16(os, ratio*65535);
3434 std::string s = os.str();
3435 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3437 m_clients.send(peer_id, 0, data, true);
3440 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3442 DSTACK(__FUNCTION_NAME);
3445 SharedBuffer<u8> data(2+2+4);
3446 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3447 writeU16(&data[2], time);
3448 writeF1000(&data[4], time_speed);
3450 if (peer_id == PEER_ID_INEXISTENT) {
3451 m_clients.sendToAll(0,data,true);
3455 m_clients.send(peer_id, 0, data, true);
3459 void Server::SendPlayerHP(u16 peer_id)
3461 DSTACK(__FUNCTION_NAME);
3462 PlayerSAO *playersao = getPlayerSAO(peer_id);
3464 playersao->m_hp_not_sent = false;
3465 SendHP(peer_id, playersao->getHP());
3466 m_script->player_event(playersao,"health_changed");
3468 // Send to other clients
3469 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3470 ActiveObjectMessage aom(playersao->getId(), true, str);
3471 playersao->m_messages_out.push_back(aom);
3474 void Server::SendPlayerBreath(u16 peer_id)
3476 DSTACK(__FUNCTION_NAME);
3477 PlayerSAO *playersao = getPlayerSAO(peer_id);
3479 playersao->m_breath_not_sent = false;
3480 m_script->player_event(playersao,"breath_changed");
3481 SendBreath(peer_id, playersao->getBreath());
3484 void Server::SendMovePlayer(u16 peer_id)
3486 DSTACK(__FUNCTION_NAME);
3487 Player *player = m_env->getPlayer(peer_id);
3490 std::ostringstream os(std::ios_base::binary);
3491 writeU16(os, TOCLIENT_MOVE_PLAYER);
3492 writeV3F1000(os, player->getPosition());
3493 writeF1000(os, player->getPitch());
3494 writeF1000(os, player->getYaw());
3497 v3f pos = player->getPosition();
3498 f32 pitch = player->getPitch();
3499 f32 yaw = player->getYaw();
3500 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3501 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3508 std::string s = os.str();
3509 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3511 m_clients.send(peer_id, 0, data, true);
3514 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3516 std::ostringstream os(std::ios_base::binary);
3518 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3519 writeV2S32(os, animation_frames[0]);
3520 writeV2S32(os, animation_frames[1]);
3521 writeV2S32(os, animation_frames[2]);
3522 writeV2S32(os, animation_frames[3]);
3523 writeF1000(os, animation_speed);
3526 std::string s = os.str();
3527 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3529 m_clients.send(peer_id, 0, data, true);
3532 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3534 std::ostringstream os(std::ios_base::binary);
3536 writeU16(os, TOCLIENT_EYE_OFFSET);
3537 writeV3F1000(os, first);
3538 writeV3F1000(os, third);
3541 std::string s = os.str();
3542 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3544 m_clients.send(peer_id, 0, data, true);
3546 void Server::SendPlayerPrivileges(u16 peer_id)
3548 Player *player = m_env->getPlayer(peer_id);
3550 if(player->peer_id == PEER_ID_INEXISTENT)
3553 std::set<std::string> privs;
3554 m_script->getAuth(player->getName(), NULL, &privs);
3556 std::ostringstream os(std::ios_base::binary);
3557 writeU16(os, TOCLIENT_PRIVILEGES);
3558 writeU16(os, privs.size());
3559 for(std::set<std::string>::const_iterator i = privs.begin();
3560 i != privs.end(); i++){
3561 os<<serializeString(*i);
3565 std::string s = os.str();
3566 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3568 m_clients.send(peer_id, 0, data, true);
3571 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3573 Player *player = m_env->getPlayer(peer_id);
3575 if(player->peer_id == PEER_ID_INEXISTENT)
3578 std::ostringstream os(std::ios_base::binary);
3579 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3580 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3583 std::string s = os.str();
3584 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3586 m_clients.send(peer_id, 0, data, true);
3589 s32 Server::playSound(const SimpleSoundSpec &spec,
3590 const ServerSoundParams ¶ms)
3592 // Find out initial position of sound
3593 bool pos_exists = false;
3594 v3f pos = params.getPos(m_env, &pos_exists);
3595 // If position is not found while it should be, cancel sound
3596 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3599 // Filter destination clients
3600 std::list<u16> dst_clients;
3601 if(params.to_player != "")
3603 Player *player = m_env->getPlayer(params.to_player.c_str());
3605 infostream<<"Server::playSound: Player \""<<params.to_player
3606 <<"\" not found"<<std::endl;
3609 if(player->peer_id == PEER_ID_INEXISTENT){
3610 infostream<<"Server::playSound: Player \""<<params.to_player
3611 <<"\" not connected"<<std::endl;
3614 dst_clients.push_back(player->peer_id);
3618 std::list<u16> clients = m_clients.getClientIDs();
3620 for(std::list<u16>::iterator
3621 i = clients.begin(); i != clients.end(); ++i)
3623 Player *player = m_env->getPlayer(*i);
3627 if(player->getPosition().getDistanceFrom(pos) >
3628 params.max_hear_distance)
3631 dst_clients.push_back(*i);
3634 if(dst_clients.empty())
3638 s32 id = m_next_sound_id++;
3639 // The sound will exist as a reference in m_playing_sounds
3640 m_playing_sounds[id] = ServerPlayingSound();
3641 ServerPlayingSound &psound = m_playing_sounds[id];
3642 psound.params = params;
3643 for(std::list<u16>::iterator i = dst_clients.begin();
3644 i != dst_clients.end(); i++)
3645 psound.clients.insert(*i);
3647 std::ostringstream os(std::ios_base::binary);
3648 writeU16(os, TOCLIENT_PLAY_SOUND);
3650 os<<serializeString(spec.name);
3651 writeF1000(os, spec.gain * params.gain);
3652 writeU8(os, params.type);
3653 writeV3F1000(os, pos);
3654 writeU16(os, params.object);
3655 writeU8(os, params.loop);
3657 std::string s = os.str();
3658 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3660 for(std::list<u16>::iterator i = dst_clients.begin();
3661 i != dst_clients.end(); i++){
3663 m_clients.send(*i, 0, data, true);
3667 void Server::stopSound(s32 handle)
3669 // Get sound reference
3670 std::map<s32, ServerPlayingSound>::iterator i =
3671 m_playing_sounds.find(handle);
3672 if(i == m_playing_sounds.end())
3674 ServerPlayingSound &psound = i->second;
3676 std::ostringstream os(std::ios_base::binary);
3677 writeU16(os, TOCLIENT_STOP_SOUND);
3678 writeS32(os, handle);
3680 std::string s = os.str();
3681 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3683 for(std::set<u16>::iterator i = psound.clients.begin();
3684 i != psound.clients.end(); i++){
3686 m_clients.send(*i, 0, data, true);
3688 // Remove sound reference
3689 m_playing_sounds.erase(i);
3692 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3693 std::list<u16> *far_players, float far_d_nodes)
3695 float maxd = far_d_nodes*BS;
3696 v3f p_f = intToFloat(p, BS);
3700 SharedBuffer<u8> reply(replysize);
3701 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3702 writeS16(&reply[2], p.X);
3703 writeS16(&reply[4], p.Y);
3704 writeS16(&reply[6], p.Z);
3706 std::list<u16> clients = m_clients.getClientIDs();
3707 for(std::list<u16>::iterator
3708 i = clients.begin();
3709 i != clients.end(); ++i)
3714 Player *player = m_env->getPlayer(*i);
3717 // If player is far away, only set modified blocks not sent
3718 v3f player_pos = player->getPosition();
3719 if(player_pos.getDistanceFrom(p_f) > maxd)
3721 far_players->push_back(*i);
3728 m_clients.send(*i, 0, reply, true);
3732 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3733 std::list<u16> *far_players, float far_d_nodes,
3734 bool remove_metadata)
3736 float maxd = far_d_nodes*BS;
3737 v3f p_f = intToFloat(p, BS);
3739 std::list<u16> clients = m_clients.getClientIDs();
3740 for(std::list<u16>::iterator
3741 i = clients.begin();
3742 i != clients.end(); ++i)
3748 Player *player = m_env->getPlayer(*i);
3751 // If player is far away, only set modified blocks not sent
3752 v3f player_pos = player->getPosition();
3753 if(player_pos.getDistanceFrom(p_f) > maxd)
3755 far_players->push_back(*i);
3760 SharedBuffer<u8> reply(0);
3762 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3766 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3767 reply = SharedBuffer<u8>(replysize);
3768 writeU16(&reply[0], TOCLIENT_ADDNODE);
3769 writeS16(&reply[2], p.X);
3770 writeS16(&reply[4], p.Y);
3771 writeS16(&reply[6], p.Z);
3772 n.serialize(&reply[8], client->serialization_version);
3773 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3774 writeU8(&reply[index], remove_metadata ? 0 : 1);
3776 if (!remove_metadata) {
3777 if (client->net_proto_version <= 21) {
3778 // Old clients always clear metadata; fix it
3779 // by sending the full block again.
3780 client->SetBlockNotSent(p);
3787 if (reply.getSize() > 0)
3788 m_clients.send(*i, 0, reply, true);
3792 void Server::setBlockNotSent(v3s16 p)
3794 std::list<u16> clients = m_clients.getClientIDs();
3796 for(std::list<u16>::iterator
3797 i = clients.begin();
3798 i != clients.end(); ++i)
3800 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3801 client->SetBlockNotSent(p);
3806 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3808 DSTACK(__FUNCTION_NAME);
3810 v3s16 p = block->getPos();
3814 bool completely_air = true;
3815 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3816 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3817 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3819 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3821 completely_air = false;
3822 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3827 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3829 infostream<<"[completely air] ";
3830 infostream<<std::endl;
3834 Create a packet with the block in the right format
3837 std::ostringstream os(std::ios_base::binary);
3838 block->serialize(os, ver, false);
3839 block->serializeNetworkSpecific(os, net_proto_version);
3840 std::string s = os.str();
3841 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3843 u32 replysize = 8 + blockdata.getSize();
3844 SharedBuffer<u8> reply(replysize);
3845 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3846 writeS16(&reply[2], p.X);
3847 writeS16(&reply[4], p.Y);
3848 writeS16(&reply[6], p.Z);
3849 memcpy(&reply[8], *blockdata, blockdata.getSize());
3851 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3852 <<": \tpacket size: "<<replysize<<std::endl;*/
3857 m_clients.send(peer_id, 2, reply, true);
3860 void Server::SendBlocks(float dtime)
3862 DSTACK(__FUNCTION_NAME);
3864 JMutexAutoLock envlock(m_env_mutex);
3865 //TODO check if one big lock could be faster then multiple small ones
3867 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3869 std::vector<PrioritySortedBlockTransfer> queue;
3871 s32 total_sending = 0;
3874 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3876 std::list<u16> clients = m_clients.getClientIDs();
3879 for(std::list<u16>::iterator
3880 i = clients.begin();
3881 i != clients.end(); ++i)
3883 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3888 total_sending += client->SendingCount();
3889 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3895 // Lowest priority number comes first.
3896 // Lowest is most important.
3897 std::sort(queue.begin(), queue.end());
3900 for(u32 i=0; i<queue.size(); i++)
3902 //TODO: Calculate limit dynamically
3903 if(total_sending >= g_settings->getS32
3904 ("max_simultaneous_block_sends_server_total"))
3907 PrioritySortedBlockTransfer q = queue[i];
3909 MapBlock *block = NULL;
3912 block = m_env->getMap().getBlockNoCreate(q.pos);
3914 catch(InvalidPositionException &e)
3919 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3924 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3926 client->SentBlock(q.pos);
3932 void Server::fillMediaCache()
3934 DSTACK(__FUNCTION_NAME);
3936 infostream<<"Server: Calculating media file checksums"<<std::endl;
3938 // Collect all media file paths
3939 std::list<std::string> paths;
3940 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3941 i != m_mods.end(); i++){
3942 const ModSpec &mod = *i;
3943 paths.push_back(mod.path + DIR_DELIM + "textures");
3944 paths.push_back(mod.path + DIR_DELIM + "sounds");
3945 paths.push_back(mod.path + DIR_DELIM + "media");
3946 paths.push_back(mod.path + DIR_DELIM + "models");
3948 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3950 // Collect media file information from paths into cache
3951 for(std::list<std::string>::iterator i = paths.begin();
3952 i != paths.end(); i++)
3954 std::string mediapath = *i;
3955 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3956 for(u32 j=0; j<dirlist.size(); j++){
3957 if(dirlist[j].dir) // Ignode dirs
3959 std::string filename = dirlist[j].name;
3960 // If name contains illegal characters, ignore the file
3961 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3962 infostream<<"Server: ignoring illegal file name: \""
3963 <<filename<<"\""<<std::endl;
3966 // If name is not in a supported format, ignore it
3967 const char *supported_ext[] = {
3968 ".png", ".jpg", ".bmp", ".tga",
3969 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3971 ".x", ".b3d", ".md2", ".obj",
3974 if(removeStringEnd(filename, supported_ext) == ""){
3975 infostream<<"Server: ignoring unsupported file extension: \""
3976 <<filename<<"\""<<std::endl;
3979 // Ok, attempt to load the file and add to cache
3980 std::string filepath = mediapath + DIR_DELIM + filename;
3982 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3983 if(fis.good() == false){
3984 errorstream<<"Server::fillMediaCache(): Could not open \""
3985 <<filename<<"\" for reading"<<std::endl;
3988 std::ostringstream tmp_os(std::ios_base::binary);
3992 fis.read(buf, 1024);
3993 std::streamsize len = fis.gcount();
3994 tmp_os.write(buf, len);
4003 errorstream<<"Server::fillMediaCache(): Failed to read \""
4004 <<filename<<"\""<<std::endl;
4007 if(tmp_os.str().length() == 0){
4008 errorstream<<"Server::fillMediaCache(): Empty file \""
4009 <<filepath<<"\""<<std::endl;
4014 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4016 unsigned char *digest = sha1.getDigest();
4017 std::string sha1_base64 = base64_encode(digest, 20);
4018 std::string sha1_hex = hex_encode((char*)digest, 20);
4022 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4023 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4028 struct SendableMediaAnnouncement
4031 std::string sha1_digest;
4033 SendableMediaAnnouncement(const std::string &name_="",
4034 const std::string &sha1_digest_=""):
4036 sha1_digest(sha1_digest_)
4040 void Server::sendMediaAnnouncement(u16 peer_id)
4042 DSTACK(__FUNCTION_NAME);
4044 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4047 std::list<SendableMediaAnnouncement> file_announcements;
4049 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4050 i != m_media.end(); i++){
4052 file_announcements.push_back(
4053 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4057 std::ostringstream os(std::ios_base::binary);
4065 u16 length of sha1_digest
4070 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4071 writeU16(os, file_announcements.size());
4073 for(std::list<SendableMediaAnnouncement>::iterator
4074 j = file_announcements.begin();
4075 j != file_announcements.end(); ++j){
4076 os<<serializeString(j->name);
4077 os<<serializeString(j->sha1_digest);
4079 os<<serializeString(g_settings->get("remote_media"));
4082 std::string s = os.str();
4083 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4086 m_clients.send(peer_id, 0, data, true);
4089 struct SendableMedia
4095 SendableMedia(const std::string &name_="", const std::string &path_="",
4096 const std::string &data_=""):
4103 void Server::sendRequestedMedia(u16 peer_id,
4104 const std::list<std::string> &tosend)
4106 DSTACK(__FUNCTION_NAME);
4108 verbosestream<<"Server::sendRequestedMedia(): "
4109 <<"Sending files to client"<<std::endl;
4113 // Put 5kB in one bunch (this is not accurate)
4114 u32 bytes_per_bunch = 5000;
4116 std::vector< std::list<SendableMedia> > file_bunches;
4117 file_bunches.push_back(std::list<SendableMedia>());
4119 u32 file_size_bunch_total = 0;
4121 for(std::list<std::string>::const_iterator i = tosend.begin();
4122 i != tosend.end(); ++i)
4124 const std::string &name = *i;
4126 if(m_media.find(name) == m_media.end()){
4127 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4128 <<"unknown file \""<<(name)<<"\""<<std::endl;
4132 //TODO get path + name
4133 std::string tpath = m_media[name].path;
4136 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4137 if(fis.good() == false){
4138 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4139 <<tpath<<"\" for reading"<<std::endl;
4142 std::ostringstream tmp_os(std::ios_base::binary);
4146 fis.read(buf, 1024);
4147 std::streamsize len = fis.gcount();
4148 tmp_os.write(buf, len);
4149 file_size_bunch_total += len;
4158 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4159 <<name<<"\""<<std::endl;
4162 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4163 <<tname<<"\""<<std::endl;*/
4165 file_bunches[file_bunches.size()-1].push_back(
4166 SendableMedia(name, tpath, tmp_os.str()));
4168 // Start next bunch if got enough data
4169 if(file_size_bunch_total >= bytes_per_bunch){
4170 file_bunches.push_back(std::list<SendableMedia>());
4171 file_size_bunch_total = 0;
4176 /* Create and send packets */
4178 u32 num_bunches = file_bunches.size();
4179 for(u32 i=0; i<num_bunches; i++)
4181 std::ostringstream os(std::ios_base::binary);
4185 u16 total number of texture bunches
4186 u16 index of this bunch
4187 u32 number of files in this bunch
4196 writeU16(os, TOCLIENT_MEDIA);
4197 writeU16(os, num_bunches);
4199 writeU32(os, file_bunches[i].size());
4201 for(std::list<SendableMedia>::iterator
4202 j = file_bunches[i].begin();
4203 j != file_bunches[i].end(); ++j){
4204 os<<serializeString(j->name);
4205 os<<serializeLongString(j->data);
4209 std::string s = os.str();
4210 verbosestream<<"Server::sendRequestedMedia(): bunch "
4211 <<i<<"/"<<num_bunches
4212 <<" files="<<file_bunches[i].size()
4213 <<" size=" <<s.size()<<std::endl;
4214 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4216 m_clients.send(peer_id, 2, data, true);
4220 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4222 if(m_detached_inventories.count(name) == 0){
4223 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4226 Inventory *inv = m_detached_inventories[name];
4228 std::ostringstream os(std::ios_base::binary);
4229 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4230 os<<serializeString(name);
4234 std::string s = os.str();
4235 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4237 if (peer_id != PEER_ID_INEXISTENT)
4240 m_clients.send(peer_id, 0, data, true);
4244 m_clients.sendToAll(0,data,true);
4248 void Server::sendDetachedInventories(u16 peer_id)
4250 DSTACK(__FUNCTION_NAME);
4252 for(std::map<std::string, Inventory*>::iterator
4253 i = m_detached_inventories.begin();
4254 i != m_detached_inventories.end(); i++){
4255 const std::string &name = i->first;
4256 //Inventory *inv = i->second;
4257 sendDetachedInventory(name, peer_id);
4265 void Server::DiePlayer(u16 peer_id)
4267 DSTACK(__FUNCTION_NAME);
4269 PlayerSAO *playersao = getPlayerSAO(peer_id);
4272 infostream<<"Server::DiePlayer(): Player "
4273 <<playersao->getPlayer()->getName()
4274 <<" dies"<<std::endl;
4276 playersao->setHP(0);
4278 // Trigger scripted stuff
4279 m_script->on_dieplayer(playersao);
4281 SendPlayerHP(peer_id);
4282 SendDeathscreen(peer_id, false, v3f(0,0,0));
4285 void Server::RespawnPlayer(u16 peer_id)
4287 DSTACK(__FUNCTION_NAME);
4289 PlayerSAO *playersao = getPlayerSAO(peer_id);
4292 infostream<<"Server::RespawnPlayer(): Player "
4293 <<playersao->getPlayer()->getName()
4294 <<" respawns"<<std::endl;
4296 playersao->setHP(PLAYER_MAX_HP);
4298 bool repositioned = m_script->on_respawnplayer(playersao);
4300 v3f pos = findSpawnPos(m_env->getServerMap());
4301 playersao->setPos(pos);
4305 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4307 DSTACK(__FUNCTION_NAME);
4309 SendAccessDenied(peer_id, reason);
4310 m_clients.event(peer_id, CSE_SetDenied);
4311 m_con.DisconnectPeer(peer_id);
4314 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4316 DSTACK(__FUNCTION_NAME);
4317 std::wstring message;
4320 Clear references to playing sounds
4322 for(std::map<s32, ServerPlayingSound>::iterator
4323 i = m_playing_sounds.begin();
4324 i != m_playing_sounds.end();)
4326 ServerPlayingSound &psound = i->second;
4327 psound.clients.erase(peer_id);
4328 if(psound.clients.empty())
4329 m_playing_sounds.erase(i++);
4334 Player *player = m_env->getPlayer(peer_id);
4336 // Collect information about leaving in chat
4338 if(player != NULL && reason != CDR_DENY)
4340 std::wstring name = narrow_to_wide(player->getName());
4343 message += L" left the game.";
4344 if(reason == CDR_TIMEOUT)
4345 message += L" (timed out)";
4349 /* Run scripts and remove from environment */
4353 PlayerSAO *playersao = player->getPlayerSAO();
4356 m_script->on_leaveplayer(playersao);
4358 playersao->disconnected();
4366 if(player != NULL && reason != CDR_DENY)
4368 std::ostringstream os(std::ios_base::binary);
4369 std::list<u16> clients = m_clients.getClientIDs();
4371 for(std::list<u16>::iterator
4372 i = clients.begin();
4373 i != clients.end(); ++i)
4376 Player *player = m_env->getPlayer(*i);
4379 // Get name of player
4380 os<<player->getName()<<" ";
4383 actionstream<<player->getName()<<" "
4384 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4385 <<" List of players: "<<os.str()<<std::endl;
4389 JMutexAutoLock env_lock(m_env_mutex);
4390 m_clients.DeleteClient(peer_id);
4394 // Send leave chat message to all remaining clients
4395 if(message.length() != 0)
4396 SendChatMessage(PEER_ID_INEXISTENT,message);
4399 void Server::UpdateCrafting(u16 peer_id)
4401 DSTACK(__FUNCTION_NAME);
4403 Player* player = m_env->getPlayer(peer_id);
4406 // Get a preview for crafting
4408 InventoryLocation loc;
4409 loc.setPlayer(player->getName());
4410 getCraftingResult(&player->inventory, preview, false, this);
4411 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4413 // Put the new preview in
4414 InventoryList *plist = player->inventory.getList("craftpreview");
4416 assert(plist->getSize() >= 1);
4417 plist->changeItem(0, preview);
4420 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4422 RemoteClient *client = getClientNoEx(peer_id,state_min);
4424 throw ClientNotFoundException("Client not found");
4428 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4430 return m_clients.getClientNoEx(peer_id, state_min);
4433 std::string Server::getPlayerName(u16 peer_id)
4435 Player *player = m_env->getPlayer(peer_id);
4437 return "[id="+itos(peer_id)+"]";
4438 return player->getName();
4441 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4443 Player *player = m_env->getPlayer(peer_id);
4446 return player->getPlayerSAO();
4449 std::wstring Server::getStatusString()
4451 std::wostringstream os(std::ios_base::binary);
4454 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4456 os<<L", uptime="<<m_uptime.get();
4458 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4459 // Information about clients
4462 std::list<u16> clients = m_clients.getClientIDs();
4463 for(std::list<u16>::iterator i = clients.begin();
4464 i != clients.end(); ++i)
4467 Player *player = m_env->getPlayer(*i);
4468 // Get name of player
4469 std::wstring name = L"unknown";
4471 name = narrow_to_wide(player->getName());
4472 // Add name to information string
4480 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4481 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4482 if(g_settings->get("motd") != "")
4483 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4487 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4489 std::set<std::string> privs;
4490 m_script->getAuth(name, NULL, &privs);
4494 bool Server::checkPriv(const std::string &name, const std::string &priv)
4496 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4497 return (privs.count(priv) != 0);
4500 void Server::reportPrivsModified(const std::string &name)
4503 std::list<u16> clients = m_clients.getClientIDs();
4504 for(std::list<u16>::iterator
4505 i = clients.begin();
4506 i != clients.end(); ++i){
4507 Player *player = m_env->getPlayer(*i);
4508 reportPrivsModified(player->getName());
4511 Player *player = m_env->getPlayer(name.c_str());
4514 SendPlayerPrivileges(player->peer_id);
4515 PlayerSAO *sao = player->getPlayerSAO();
4518 sao->updatePrivileges(
4519 getPlayerEffectivePrivs(name),
4524 void Server::reportInventoryFormspecModified(const std::string &name)
4526 Player *player = m_env->getPlayer(name.c_str());
4529 SendPlayerInventoryFormspec(player->peer_id);
4532 void Server::setIpBanned(const std::string &ip, const std::string &name)
4534 m_banmanager->add(ip, name);
4537 void Server::unsetIpBanned(const std::string &ip_or_name)
4539 m_banmanager->remove(ip_or_name);
4542 std::string Server::getBanDescription(const std::string &ip_or_name)
4544 return m_banmanager->getBanDescription(ip_or_name);
4547 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4549 Player *player = m_env->getPlayer(name);
4553 if (player->peer_id == PEER_ID_INEXISTENT)
4556 SendChatMessage(player->peer_id, msg);
4559 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4561 Player *player = m_env->getPlayer(playername);
4565 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4569 SendShowFormspecMessage(player->peer_id, formspec, formname);
4573 u32 Server::hudAdd(Player *player, HudElement *form) {
4577 u32 id = player->addHud(form);
4579 SendHUDAdd(player->peer_id, id, form);
4584 bool Server::hudRemove(Player *player, u32 id) {
4588 HudElement* todel = player->removeHud(id);
4595 SendHUDRemove(player->peer_id, id);
4599 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4603 SendHUDChange(player->peer_id, id, stat, data);
4607 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4611 SendHUDSetFlags(player->peer_id, flags, mask);
4612 player->hud_flags = flags;
4614 PlayerSAO* playersao = player->getPlayerSAO();
4616 if (playersao == NULL)
4619 m_script->player_event(playersao, "hud_changed");
4623 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4626 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4629 std::ostringstream os(std::ios::binary);
4630 writeS32(os, hotbar_itemcount);
4631 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4635 void Server::hudSetHotbarImage(Player *player, std::string name) {
4639 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4642 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4646 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4649 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4654 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4658 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4663 SendEyeOffset(player->peer_id, first, third);
4667 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4668 const std::string &type, const std::vector<std::string> ¶ms)
4673 SendSetSky(player->peer_id, bgcolor, type, params);
4677 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4683 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4687 void Server::notifyPlayers(const std::wstring &msg)
4689 SendChatMessage(PEER_ID_INEXISTENT,msg);
4692 void Server::spawnParticle(const char *playername, v3f pos,
4693 v3f velocity, v3f acceleration,
4694 float expirationtime, float size, bool
4695 collisiondetection, bool vertical, std::string texture)
4697 Player *player = m_env->getPlayer(playername);
4700 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4701 expirationtime, size, collisiondetection, vertical, texture);
4704 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4705 float expirationtime, float size,
4706 bool collisiondetection, bool vertical, std::string texture)
4708 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4709 expirationtime, size, collisiondetection, vertical, texture);
4712 u32 Server::addParticleSpawner(const char *playername,
4713 u16 amount, float spawntime,
4714 v3f minpos, v3f maxpos,
4715 v3f minvel, v3f maxvel,
4716 v3f minacc, v3f maxacc,
4717 float minexptime, float maxexptime,
4718 float minsize, float maxsize,
4719 bool collisiondetection, bool vertical, std::string texture)
4721 Player *player = m_env->getPlayer(playername);
4726 for(;;) // look for unused particlespawner id
4729 if (std::find(m_particlespawner_ids.begin(),
4730 m_particlespawner_ids.end(), id)
4731 == m_particlespawner_ids.end())
4733 m_particlespawner_ids.push_back(id);
4738 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4739 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4740 minexptime, maxexptime, minsize, maxsize,
4741 collisiondetection, vertical, texture, id);
4746 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4747 v3f minpos, v3f maxpos,
4748 v3f minvel, v3f maxvel,
4749 v3f minacc, v3f maxacc,
4750 float minexptime, float maxexptime,
4751 float minsize, float maxsize,
4752 bool collisiondetection, bool vertical, std::string texture)
4755 for(;;) // look for unused particlespawner id
4758 if (std::find(m_particlespawner_ids.begin(),
4759 m_particlespawner_ids.end(), id)
4760 == m_particlespawner_ids.end())
4762 m_particlespawner_ids.push_back(id);
4767 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4768 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4769 minexptime, maxexptime, minsize, maxsize,
4770 collisiondetection, vertical, texture, id);
4775 void Server::deleteParticleSpawner(const char *playername, u32 id)
4777 Player *player = m_env->getPlayer(playername);
4781 m_particlespawner_ids.erase(
4782 std::remove(m_particlespawner_ids.begin(),
4783 m_particlespawner_ids.end(), id),
4784 m_particlespawner_ids.end());
4785 SendDeleteParticleSpawner(player->peer_id, id);
4788 void Server::deleteParticleSpawnerAll(u32 id)
4790 m_particlespawner_ids.erase(
4791 std::remove(m_particlespawner_ids.begin(),
4792 m_particlespawner_ids.end(), id),
4793 m_particlespawner_ids.end());
4794 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4797 Inventory* Server::createDetachedInventory(const std::string &name)
4799 if(m_detached_inventories.count(name) > 0){
4800 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4801 delete m_detached_inventories[name];
4803 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4805 Inventory *inv = new Inventory(m_itemdef);
4807 m_detached_inventories[name] = inv;
4808 //TODO find a better way to do this
4809 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4816 BoolScopeSet(bool *dst, bool val):
4819 m_orig_state = *m_dst;
4824 *m_dst = m_orig_state;
4831 // actions: time-reversed list
4832 // Return value: success/failure
4833 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4834 std::list<std::string> *log)
4836 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4837 ServerMap *map = (ServerMap*)(&m_env->getMap());
4839 // Fail if no actions to handle
4840 if(actions.empty()){
4841 log->push_back("Nothing to do.");
4848 for(std::list<RollbackAction>::const_iterator
4849 i = actions.begin();
4850 i != actions.end(); i++)
4852 const RollbackAction &action = *i;
4854 bool success = action.applyRevert(map, this, this);
4857 std::ostringstream os;
4858 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4859 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4861 log->push_back(os.str());
4863 std::ostringstream os;
4864 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4865 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4867 log->push_back(os.str());
4871 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4872 <<" failed"<<std::endl;
4874 // Call it done if less than half failed
4875 return num_failed <= num_tried/2;
4878 // IGameDef interface
4880 IItemDefManager* Server::getItemDefManager()
4884 INodeDefManager* Server::getNodeDefManager()
4888 ICraftDefManager* Server::getCraftDefManager()
4892 ITextureSource* Server::getTextureSource()
4896 IShaderSource* Server::getShaderSource()
4900 scene::ISceneManager* Server::getSceneManager()
4905 u16 Server::allocateUnknownNodeId(const std::string &name)
4907 return m_nodedef->allocateDummy(name);
4909 ISoundManager* Server::getSoundManager()
4911 return &dummySoundManager;
4913 MtEventManager* Server::getEventManager()
4918 IWritableItemDefManager* Server::getWritableItemDefManager()
4922 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4926 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4931 const ModSpec* Server::getModSpec(const std::string &modname)
4933 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4934 i != m_mods.end(); i++){
4935 const ModSpec &mod = *i;
4936 if(mod.name == modname)
4941 void Server::getModNames(std::list<std::string> &modlist)
4943 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4945 modlist.push_back(i->name);
4948 std::string Server::getBuiltinLuaPath()
4950 return porting::path_share + DIR_DELIM + "builtin";
4953 v3f findSpawnPos(ServerMap &map)
4955 //return v3f(50,50,50)*BS;
4960 nodepos = v2s16(0,0);
4965 s16 water_level = map.getWaterLevel();
4967 // Try to find a good place a few times
4968 for(s32 i=0; i<1000; i++)
4971 // We're going to try to throw the player to this position
4972 v2s16 nodepos2d = v2s16(
4973 -range + (myrand() % (range * 2)),
4974 -range + (myrand() % (range * 2)));
4976 // Get ground height at point
4977 s16 groundheight = map.findGroundLevel(nodepos2d);
4978 if (groundheight <= water_level) // Don't go underwater
4980 if (groundheight > water_level + 6) // Don't go to high places
4983 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4984 bool is_good = false;
4986 for (s32 i = 0; i < 10; i++) {
4987 v3s16 blockpos = getNodeBlockPos(nodepos);
4988 map.emergeBlock(blockpos, true);
4989 content_t c = map.getNodeNoEx(nodepos).getContent();
4990 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4992 if (air_count >= 2){
5000 // Found a good place
5001 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5007 return intToFloat(nodepos, BS);
5010 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5012 RemotePlayer *player = NULL;
5013 bool newplayer = false;
5016 Try to get an existing player
5018 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5020 // If player is already connected, cancel
5021 if(player != NULL && player->peer_id != 0)
5023 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5028 If player with the wanted peer_id already exists, cancel.
5030 if(m_env->getPlayer(peer_id) != NULL)
5032 infostream<<"emergePlayer(): Player with wrong name but same"
5033 " peer_id already exists"<<std::endl;
5037 // Load player if it isn't already loaded
5039 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5042 // Create player if it doesn't exist
5045 player = new RemotePlayer(this, name);
5046 // Set player position
5047 infostream<<"Server: Finding spawn place for player \""
5048 <<name<<"\""<<std::endl;
5049 v3f pos = findSpawnPos(m_env->getServerMap());
5050 player->setPosition(pos);
5052 // Make sure the player is saved
5053 player->setModified(true);
5055 // Add player to environment
5056 m_env->addPlayer(player);
5059 // Create a new player active object
5060 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5061 getPlayerEffectivePrivs(player->getName()),
5064 /* Clean up old HUD elements from previous sessions */
5067 /* Add object to environment */
5068 m_env->addActiveObject(playersao);
5072 m_script->on_newplayer(playersao);
5078 void dedicated_server_loop(Server &server, bool &kill)
5080 DSTACK(__FUNCTION_NAME);
5082 verbosestream<<"dedicated_server_loop()"<<std::endl;
5084 IntervalLimiter m_profiler_interval;
5088 float steplen = g_settings->getFloat("dedicated_server_step");
5089 // This is kind of a hack but can be done like this
5090 // because server.step() is very light
5092 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5093 sleep_ms((int)(steplen*1000.0));
5095 server.step(steplen);
5097 if(server.getShutdownRequested() || kill)
5099 infostream<<"Dedicated server quitting"<<std::endl;
5101 if(g_settings->getBool("server_announce"))
5102 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
5110 float profiler_print_interval =
5111 g_settings->getFloat("profiler_print_interval");
5112 if(profiler_print_interval != 0)
5114 if(m_profiler_interval.step(steplen, profiler_print_interval))
5116 infostream<<"Profiler:"<<std::endl;
5117 g_profiler->print(infostream);
5118 g_profiler->clear();